better-scroll 实现无缝轮播

better-scroll  适用于解决移动端各种滚动场景,滚动列表、轮播图等。

better-scroll新版本设置轮播图有一些变动。

slider.vue:

结构及部分样式设置:

  <div class="slider" ref="slider">
    <div class="slider-group" ref="sliderGroup">
      <slot>    //插槽位置即轮播图,在引入主页面的中间插入图片
      </slot>
    </div>
    <div class="dots"> //小圆点采用绝对定位
      <span class="dot" :class="{active:currentIndex === index}" v-for="(item, index) in dots" :key="index" ></span>
    </div>
  </div>
<style rel="stylesheet/stylus" lang="stylus">
  @import "~common/stylus/variable"

  .slider
    min-height: 1px  //防止文本溢出
    .slider-group
      position: relative
      overflow: hidden
      white-space: nowrap
      .slider-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%
</script>

recommend.vue:  

        <div class="slider-wrapper">
            <div v-if="recommends.length" class="slider-wrapper">  
              <slider>   //以下就是插槽的内容
                <div v-for="(item, index) in recommends" :key = "index">
                  <a :href="item.linkUrl">
                    <img class="needclick" :src="item.picUrl">
                  </a>
                </div>
              </slider>
            </div>
        </div>

        其中需要注意,这边需要控制显示的时机,是由于slider.vue中设置html的宽度等是在mounted (即已完成模板渲染后执行),而recommend.vue 当还未获取数据的时候,mounted 已经执行,为了确保元素的存在再渲染,所以添加判断。

slider.vue,设置图片的宽度以及总宽度:

    _setSliderWidth(isResize) {
      this.children = this.$refs.sliderGroup.children 
      let width = 0
      let slideWidth = this.$refs.slider.clientWidth
      for (let i = 0; i < this.children.length; i++) {
        let child = this.children[i]
        addClass(child, 'slider-item') //为每一个子元素添加类名

        child.style.width = slideWidth + 'px'
        width += slideWidth        //容器的总宽度
      }
      if (this.loop && !isResize) {
        width += 2 * slideWidth    //如果轮播,左右会各增加一个,所以要加上两张图片的宽度
      }
      this.$refs.sliderGroup.style.width = width + 'px'        //为元素设置容器的总宽度
    },

addClass :(添加类名)

export function hasClass(el, className) {
  let reg = new RegExp('(^|\\s)' + className + '(\\s|$)')    //判断className 的开头或结尾无字符或者是空格
  return reg.test(el.className)    
}

export function addClass(el, className) {
  if (hasClass(el, className)) {    //有这个类名就返回
    return
  }

  let newClass = el.className.split(' ')  //split() 将原本的className字符串按空格分割成数组
  newClass.push(className)        //将新的className 添加到上面的数组中
  el.className = newClass.join(' ')        //join() 以空格为连接符链接成class字符串
}

拓展:

//删除class
export function removeClass(el, className) {
  //先判断是否含有这个class,含有时,才继续
  if (!hasClass(el, className)) {
    return
  }

  let newClass = el.className.split(' ')     //分割class字符串为class数组
  let index = newClass.findIndex((item)=>{   //找到指定的class在class数组中的索引
    return item === className
  })
  newClass.splice(index,1)   // 删除索引中的这项
  el.className = newClass.join(' ')  //将class数组以空格为连接符连接成class字符串
}

初始化 better-scroll时机,将那些函数在mounted  完成渲染后执行:(*一般初始化better-scroll不成功);

 并通过监听窗口改变事件,解决当窗口改变时,图片的宽度未发生改变的问题

  mounted() {
    this._setSliderWidth()
    setTimeout(() => {
      this._initDots()
      this._initSlider()
      if (this.autoPlay) {
        this._play()
      }
    }, 20) //保证DOM被渲染,做了20ms的延时(*为何值为20??* 因为浏览器刷新时间一般为17ms一次)

    window.addEventListener('resize', () => {        //监听窗口改变事件,解决当窗口改变时,图片的宽度未发生改变的问题
      if (!this.slider) {    
        return
      }
      this._setSliderWidth(true)
      this.slider.refresh()
    })

初始化better-slider插件:

    _initSlider() {
      this.slider = new BScroll(this.$refs.slider, {
        scrollX: true,    //横向滚动
        scrollY: false,    //不允许纵向滚动
        momentum: false,    //关闭动量动画,能提升效能
        snap: {            //新版本将snap的属性都当成一个对象来书写
          loop: this.loop,    //循环
          threshold: 0.3,    
          speed: 400        //轮播间隔
        },
        click: true        
      })

      this.slider.on('scrollEnd', () => {
        let pageIndex = this.slider.getCurrentPage().pageX //轮播到下一张,获取当前的index
        // if (this.loop) {            //旧版本设置方式,新版本不需要
        //   pageIndex -= 1
        // }
        this.currentIndex = pageIndex 

        if (this.autoPlay) {
          clearTimeout(this.timer)    //如果设置额自动轮播就清除轮播再重新启动
          this._play()
        }
      })
    },

新版本的dots没有改变设置:

   _initDots() {
      this.dots = new Array(this.children.length)
    },

播放就可以采用更便捷的命令:

    _play() {
      // let pageIndex = this.currentIndex + 1        //旧版本需要计算增加的两张图片带来的影响
      // if (this.loop) {
      //   pageIndex += 1
      // }
      this.timer = setTimeout(() => {
        this.slider.next()
      }, this.interval)
    }

优化: 

1.     及时关闭轮播,有利于内存的释放

  destroyed() {
    clearTimeout(this.timer)
  }

2.    app.vue中添加<keep-alive>,将DOM缓存到内存中,切换不会重新请求,并且没有一闪而过的画面

    <keep-alive>
      <router-view></router-view>
    </keep-alive>




猜你喜欢

转载自blog.csdn.net/weixin_41892205/article/details/80993909
今日推荐