better-scroll 實現無縫輪播

七塊oooo發表於2018-07-11

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>

 

 

 

 

 

 

相關文章