利用better-scroll實現Vue輪播圖組件

起步

上一次基於better-scroll實現了移動端縱向滾動的演示。這一次繼續利用它實現一個橫向滾動——輪播圖組件。演示以下:vue

首先來整理一下需求:ios

  • 可以根據異步請求到的圖片數據進行輪播圖展現。
  • 可以控制它是否自動播放,是否循環播放,自動播放間隔。
  • 可以提示當前播放頁。

在這裏插入圖片描述

Mock數據

因爲是一個demo,從網上找了幾張圖片寫成json格式,數據用於模擬接口數據。這裏用到了mock.js。Axios。安裝方法以下:git

npm install mockjs
複製代碼
npm install --save axios vue-axios
複製代碼

axios使用方法很少贅述,簡述一下mock數據。在mock文件夾下新建json文件夾放置json數據文件。新建index.js導出接口。就可使用axios請求接口了。github

[
	"https://img3.mukewang.com/szimg/5df8852609e0762d12000676-360-202.png",
    "https://img1.mukewang.com/szimg/5d9c62fb0907ccf012000676-360-202.png",
    "https://img3.mukewang.com/5aeecb1d0001e5ea06000338-360-202.jpg"
]
複製代碼
const Mock = require('mockjs')

Mock.mock('/slider', 'get', require('./json/slider.json'))
複製代碼

基礎組件:slider.vue

將輪播圖組件抽象出來,接收isLoop、isAutoPlay、interval屬性控制輪播圖。從mounted方法調用順序能夠知道思路是npm

  • setSliderWidth()中先獲取再設置顯示層和圖片包裹層高度。
setSliderWidth () { /* 獲取顯示層寬度,計算內容層寬度 */
      const clientWidth = this.$refs.slider.clientWidth
      let sliderWidth = 0
      this.children = this.$refs.group.children
      for (let i = 0; i < this.children.length; i++) {
        this.children[i].style.width = clientWidth + 'px'
        sliderWidth += clientWidth
      }
      if (this.isLoop) { /* 循環播放須要增長先後兩個寬度 */
        sliderWidth += clientWidth * 2
      }
      this.$refs.group.style.width = sliderWidth + 'px' /* 設置內容層寬度 */
    },
複製代碼
  • initDots()根據圖片包裹層子元素的個數設置數組放置圓點。
initDots () {
      this.dots = new Array(this.children.length)
    },
複製代碼
  • initSlider()初始化better-scroll。
initSlider () {
      this.slider = new BScroll(this.$refs.slider, {
        scrollX: true, /* 橫向滾動 */
        scrollY: false,
        snap: { /* 循環滾動設置 */
          loop: this.isLoop,
          threshold: 0.3,
          speed: 400
        }
      })
      this.slider.on('scrollEnd', () => {
        const pageIndex = this.slider.getCurrentPage().pageX /* 獲取當前輪播頁,用於圓點提示 */
        this.currentIndex = pageIndex
        if (this.isAutoPlay) {
          clearTimeout(this.timer) /* 從新設置自動播放,不然沒法自動播放 */
          this.autoPlay()
        }
      })
    },
複製代碼
  • autoPlay()設置自動播放。
autoPlay () {
      this.timer = setTimeout(() => {
        this.slider.next(400)
      }, this.interval)
    }
複製代碼

完整代碼:json

<template>
  <div class="slider-apply" ref="slider">  <!-- 顯示層 -->
    <div class="slider-group" ref="group"> <!-- 全部圖片包裹層 -->
      <slot></slot>                        <!-- 插槽顯示圖片內容 -->
    </div>
    <div class="dots">                     <!-- 提示圓點 -->
      <div class="dot" v-for="(item, index) in dots" :key="index" :class="currentIndex===index?'active':''"></div>
    </div>
  </div>
</template>

<script type='text/ecmascript-6'>
import BScroll from 'better-scroll'
export default {
  data () {
    return {
      dots: [],
      currentIndex: 0 /* 當前頁下標 */
    }
  },
  props: {
    isLoop: { /* 循環播放 */
      type: Boolean,
      default: true
    },
    isAutoPlay: { /* 自動播放 */
      type: Boolean,
      default: true
    },
    interval: { /* 播放間隔 */
      type: Number,
      default: 2000
    }
  },
  mounted () { /* mounted階段dom渲染完,20ms確保刷新 */
    setTimeout(() => {
      this.setSliderWidth()
      this.initDots()
      this.initSlider()
      if (this.isAutoPlay) {
        this.autoPlay()
      }
    }, 20)
  },
  methods: {
    setSliderWidth () { /* 獲取顯示層寬度,計算內容層寬度 */
      const clientWidth = this.$refs.slider.clientWidth
      let sliderWidth = 0
      this.children = this.$refs.group.children
      for (let i = 0; i < this.children.length; i++) {
        this.children[i].style.width = clientWidth + 'px'
        sliderWidth += clientWidth
      }
      if (this.isLoop) { /* 循環播放須要增長先後兩個寬度 */
        sliderWidth += clientWidth * 2
      }
      this.$refs.group.style.width = sliderWidth + 'px' /* 設置內容層寬度 */
    },
    initDots () {
      this.dots = new Array(this.children.length)
    },
    initSlider () {
      this.slider = new BScroll(this.$refs.slider, {
        scrollX: true, /* 橫向滾動 */
        scrollY: false,
        snap: { /* 循環滾動設置 */
          loop: this.isLoop,
          threshold: 0.3,
          speed: 400
        }
      })
      this.slider.on('scrollEnd', () => {
        const pageIndex = this.slider.getCurrentPage().pageX /* 獲取當前輪播頁,用於圓點提示 */
        this.currentIndex = pageIndex
        if (this.isAutoPlay) {
          clearTimeout(this.timer) /* 從新設置自動播放,不然沒法自動播放 */
          this.autoPlay()
        }
      })
    },
    autoPlay () {
      this.timer = setTimeout(() => {
        this.slider.next(400)
      }, this.interval)
    }
  },
  destroyed () { /* 確保清除定時器 */
    clearTimeout(this.timer)
  }
}
</script>

<style lang="stylus" scoped>
.slider-apply
  position relative             // 讓dots找準位置
  height 200px
  width 100%                    // slider-apply會依據父元素寬度顯示寬度
  overflow hidden               //  超出元素隱藏
  border-radius 5px
  .dots
    position absolute
    bottom 10px
    left 50%
    transform translate(-50%, 0) // 居中
    display flex
    .dot
      margin 0 10px
      height 7px
      width 7px
      background #fff
      border-radius 50%
    .active                     // 當前dot樣式
      width 15px
      border-radius 50% 5px
</style>

複製代碼

應用組件:slider-apply.vue

能夠根據alider-apply.vue中的使用方法應用在本身的項目中。axios

<template>
  <div class="slider-wrapper">
    <Slider v-if="showSlider"> <!-- showSlider使得數據請求完成後再顯示,不然better-scroll可能會計算錯誤 -->
      <div v-for="item in imageList" :key="item" class="slider-item">
        <img :src="item" class="img">
      </div>
    </Slider>
  </div>
</template>

<script type='text/ecmascript-6'>
import Slider from 'base/slider'
export default {
  data () {
    return {
      imageList: [], // 圖片列表
      showSlider: false // 顯示slider標誌位
    }
  },
  created () {
    this.getImages() // 獲取數據
  },
  methods: {
    getImages () {
      this.axios.get('/slider').then((res) => {
        this.imageList = res.data
        this.showSlider = true
      }).catch((err) => {
        console.log(err)
      })
    }
  },
  components: {
    Slider
  }
}
</script>

<style lang="stylus" scoped>

.slider-wrapper
  margin 0 auto
  height 200px  // 固定輪播圖顯示高度
  width 500px   // 固定輪播圖顯示寬度,可設置百分比
  background #000
  border-radius 5px
  .slider-item
    float left // 元素向左浮動
    width 100%
    overflow hidden
    text-align center
  .img
    height 200px
    width 100%

</style>

複製代碼

總結

  • 若是以上步驟沒有看明白的話,能夠在個人github中找到源碼https://github.com/Gesj-yean/vue-demo-collection。
  • 建議小夥伴本身封裝一個基礎組件,並無想象的難(加油)。

之後會封裝更多組件,和我一塊兒寫組件叭,完結,撒花花~數組

更多推薦

相關文章
相關標籤/搜索