美文网首页
轮播组件——基于原生 && Vue

轮播组件——基于原生 && Vue

作者: 苏敏 | 来源:发表于2018-05-06 23:29 被阅读19次

    基于 better-scroll 的轮播图组件

    在做移动端轮播图的时候,本想沿用之前 PC 端的轮播图,后来发现并没有支持 touch 事件,所以采用了 better-scroll 来实现轮播图组件。

    关于 better-scroll 的介绍可以看官方文档 传送门

    正如 文档中所说,学习 bette-scroll 的相关组件 最好的方式就是去看 example 目录下的 demo,我现在要实现轮播图组件,直接找到轮播图的 demo 代码部分 源码传送门

    image.png

    首先实现轮播图的基本思路是通过 width 设置 overflow: hidden 来达到目的,通过 translate 移动图片实现轮播,这里 translate 的事情 better-scroll 已经替我们干了

    首先看下轮播图的 html 结构:

    <div class="slide" ref="slide">
        <div class="slide-group" ref="slideGroup">
          <slot></slot>    // 通过 slot 父组件传入图片等自定义内容
        </div>
        <div v-show="showDot" class="dots">
          <span class="dot"      // 图片对应的下标
                :class="{active: currentPageIndex === index}"
                v-for="(item, index) in dots"
                :key="index"
          ></span>
        </div>
      </div>
    

    css 结构采用的是 stylus:

    .slide 
        min-height: 1px
        .slide-group
          position: relative
          overflow: hidden
          white-space: nowrap
          .slide-item
            float: left
            box-sizing: border-box
            overflow: hidden
            text-align: center
            a
              display: block
              width: 100%
              overflow: hidden
              text-decoration: none
            img
              display: block
              width: 100%
        .dots
          position: absolute
          right: 0
          left: 0
          bottom: 12px
          transform: translateZ(1px)
          text-align: center
          font-size: 0
          .dot
            display: inline-block
            margin: 0 4px
            width: 8px
            height: 8px
            border-radius: 50%
            background: $color-text-l
            &.active
              width: 20px
              border-radius: 5px
              background: $color-text-ll
    

    好了,下面我们看看如何组织下代码,首先我们需要看一下 better-scroll 的文档,就会知道 better-scroll 执行的时机是 dom 结构渲染完毕后,所以最好的执行时机可以通过 this.$nextTick() 去实现,当然也可以通过定时器 setTimeout(fn, 20) 这样一个经验值去实现也是没有问题的。

    确定好了执行时机,我们开始初始化相关内容,比如轮播容器宽度以及 better-scroll 等

    初始化 slide 宽度

    // 获取图片的 clientWidth
    // 当需要循环播放的时候在首尾添加两个图片的 clientWidth,做一个过渡
    // 给整个 slideGroup 设置 width
    
    _setSliderWidth(isResize) {
        this.children = this.$refs.slideGroup.children 
        let width = 0 
        let slideWidth = this.$refs.slide.clientWidth
        for (let i = 0; i < this.children.length; i++) {
            let child = this.children[i] 
            addClass(child, 'slide-item') 
            child.style.width = slideWidth + 'px'
            width += slideWidth
        }
        if (this.loop && !isResize) {
            width += 2 * slideWidth
        }
        this.$refs.slideGroup.style.width = width + 'px'
    }
    

    初始化 slide 宽度后可以初始化 better-scroll 了

    // 这个配置直接直接看文档就好了,这里我们监听了 scrollEnd 事件获取当前页数
    this.slider = new BScroll(this.$refs.slide, {
        scrollX: true,
        scrollY: false,
        momentum: false,
        snap: {
            loop: this.loop,
            threshold: this.threshold,
            speed: this.speed
        }
    })
    
    this.slider.on('scrollEnd', () = >{
        this.currentPageIndex = this.slider.getCurrentPage().pageX
        if (this.autoPlay) this._play()
    })
    

    初始化 dot

    // 初始化对应轮播数量的 dot 即可
    this.dots = new Array(this.children.length)
    

    自动播放

    // 通过定时器调用 next 接口即可
    clearTimeout(this.timer)
    this.timer = setTimeout(() => {
      this.slider.next()
    }, this.interval)
    

    mounted 阶段初始化,并且监听 resize 事件

    setTimeout(() = >{
        this._setSliderWidth() 
        if (this.showDot) this._initDots() 
        this._initSlider()
    
        if (this.autoPlay) this._play()
    }, 20)
    
    window.addEventListener('resize', () = >{
        if (!this.slider) return 
        this._setSliderWidth(true) 
        this.slider.refresh()
    })
    

    还有一个注意的点,当组件中用到了计时器时,要在 destroyed 阶段清除定时器,释放内存

    destoryed() {
      clearTimeout(this.timer)
    }
    

    然后我们再父组件引用 slider 组件即可

    <div v-if="recommends.length" class="slider-wrapper">
       <div class="slider-content">
         <slider>
           <div v-for="(item, index) in recommends" :key="index">
             <a :href="item.linkUrl">
               <img :src="item.picUrl">
             </a>
           </div>
         </slider>
       </div>
     </div>
    

    不得不说 better-scroll 真的很强大,最终的展示效果如下:

    slider.gif

    相关文章

      网友评论

          本文标题:轮播组件——基于原生 && Vue

          本文链接:https://www.haomeiwen.com/subject/slbqrftx.html