用vue写轮子的一些心得(五)——Slides轮播组件

需求分析

  • Slides组件通常包括一下功能:
  • 可支持自动播放
  • 可设置自动播放时间
  • 轮播图片高宽可自适应
  • 支持触屏滑动轮播
  • 可无缝轮播

 

方法实现

1、定义组件:

在html中定义

t-slides组件定义为最外层轮播图包裹器,t-slides-item组件包裹每张轮播图片,并且每个t-slides-item组件都声明一个name,用以标识每张图片。

<t-slides class="wrapper"
          :autoPlay="autoPlay"
          :selected.sync="selected">
    <t-slides-item name="1">
        <div class="box">1</div>
    </t-slides-item>
    <t-slides-item name="2">
        <div class="box">2</div>
    </t-slides-item>
    <t-slides-item name="3">
        <div class="box">3</div>
    </t-slides-item>
</t-slides>

2、基础功能逻辑 :

t-slides单文件组件中的template模板声明相应鼠标、touch事件。并声明一个solt插槽用以接收t-slides-item组件数据,这些数据在我们做轮播动画的时候会用到,稍后我们再聊它们。

t-slides-dots类里面的内容为左右点击切换与显示轮播图下标圆点相关功能。

<template>
    <div @mouseenter="onMouseEnter"
         @mouseleave="onMouseLeave"
         @touchend="onTouchEnd"
         @touchstart="onTouchStart"
         class="t-slides">
        <div class="t-slides-window" ref="window">
            <div class="t-slides-wrapper">
                <slot></slot>
            </div>
        </div>
        <div class="t-slides-dots">
            <span @click="onClickPrev" data-action="prev">
                <t-icon name="left"></t-icon>
            </span>
            <span v-for="n in childrenLength" :class="{active: selectedIndex === n-1}"
                :key="n" :data-index="n-1"
                @click="select(n-1)">
                {{n}}
            </span>
            <span @click="onClickNext" data-aciton="next">
                <t-icon name="right"></t-icon>
            </span>
        </div>
    </div>
</template>

通过计算属性找到this.$children名字等于t-sildes-item的组件数量,这样就等于获取到了图片的数量,从而可执行与数量相关的逻辑。

computed: {
    items() {
        return this.$children.filter(vm=>vm.$options.name === 't-sildes-item')
    }
},

3、自动轮播逻辑:

定义一个方法,用setTimeout模拟setInterval并给setTimeout一个id,在页面生命周期销毁前或者任何时候关掉它,这样可减少性能消耗。有了这个方法自动轮播就很简单了,mounted的时候执行一下。

playAutomatically() {
    if (this.timeId) {return}
    let run = () => {
        let index = this.names.indexOf(this.getSelected())
        let newIndex = index + 1
        this.select(newIndex) //告诉外界选中的 newIndex
        this.timeId = setTimeout(run, this.autoPlayDelay) //this.autoPlayDelay 时间间隔
    }
    this.timeId = setTimeout(run, this.autoPlayDelay)
},

4、touch模拟滑动逻辑:

定义touch开始事件结束事件,拿到touch数组的第一项(第一个手指),取出XY轴坐标。用Math算出开始横坐标与结束横坐标的角度(三角函数最小边不超过斜边的2倍),则角度不会大于30°,角度不大于30°,我们就可以理解用户是在执行滑动操作。

onTouchEnd(e) {
    let endTouch = e.changedTouches[0]
    let {clientX: x1, clientY: y1} = this.startTouch
    let {clientX: x2, clientY: y2} = endTouch

    let distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
    let deltaY = Math.abs(y2 - y1)
    let rate = distance / deltaY
    if (rate > 2) {
        if (x2 > x1) {
            this.select(this.selectedIndex - 1)
        } else {
            this.select(this.selectedIndex + 1)
        }
    }
    this.$nextTick(()=> {
        this.playAutomatically()
    })
},

5、t-slides-item组件无缝轮播相关css:

通过animationEnabled变量控制轮播始终保持2种状态:1、当前状态 2、离开状态。

当前状态执行当前状态的样式类,离开状态执行另一种样式类。这样我们只需要定义两种样式类即可做出向左向右的任意动效样式。

6、轮播图片高宽可自适应:

只需要在当前状态类.slide-leave-active中定义position: absolute; width:100%; height: 100%;

其中微妙可自行琢磨。

<template v-if="animationEnabled">
    <transition name="slide">
        <div class="t-slides-item" v-if="visible" :class="{reverse}">
            <slot></slot>
        </div>
    </transition>
</template>
<template v-else>
    <div class="t-slides-item" v-if="visible" :class="{reverse}">
        <slot></slot>
    </div>
</template>
<style lang="scss" scoped>
    .slide-leave-active {
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
    }

    .slide-enter-active, .slide-leave-active {
        transition: all 0.5s;
    }

    .slide-enter {
        transform: translateX(100%);
    }

    .slide-enter.reverse {
        transform: translateX(-100%);
    }

    .slide-leave-to {
        transform: translateX(-100%);
    }

    .slide-leave-to.reverse {
        transform: translateX(100%);
    }

</style>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值