慕课网vue音乐播放器实战:better-scroll实现轮播图

21 篇文章 0 订阅
10 篇文章 0 订阅

知识点:

  • better-scroll的生命周期函数:scrollEnd(页面滚动完自动调用),beforeScrollStart(页面滚动前调用)
  • 计算slider的宽度:slider的宽度 = 轮播图的数量 * 一个图片容器的宽度。如果你要实现循环播放,你就要多给两个图片容器的宽度,这个better-scroll内部用来克隆第一个和最后一个轮播图,实现无缝首尾切换。
  • 屏幕大小变化的时候为什么不需要两倍的宽度? 答:因为已经克隆了第一个和最后一个轮播图,dom上已经多了两个轮播图元素,此时我们this.children.length是比一开始的this.children.length多2的,所有就不需要再循环外加多两倍的宽度。因为在for循环中宽度已经加了两倍的宽度(循环次数比第一次执行的时候多两遍)。

better-scroll版本更新:

  • this.slider.getCurrentPage.pageX:以前版本的是从1开始,现在最新版是从0开始,跟我们dot的下标刚好对应,不用在加工。scrollEnd的代码如下:
// 滚动完的生命周期函数
      this.slider.on('scrollEnd', () => {
        // 滚动完就当前页的下标赋值给currentPageIndex
        this.currentPageIndex = this.slider.getCurrentPage().pageX
        // 自动播放就执行
        if (this.autoPlay) {
          this._play()
        }
      })
  • this.slider.goToPage():由于版本的更替,使用goToPage这个方法来进行切换有点复杂(不知道是我不会,还是实现不了了),我使用next()来代替goToPage方法,因为我们配置了loop参数,我们一直调用next()方法,better-scroll会帮我们自动的循环切换到下一张轮播图。_play方法代码如下:
_play () {
      this.timer = setTimeout(() => {
        // 跳到下一页,因为我们设置配置参数loop为true,better-scroll会帮我们自动循环,我们直接跳下一页就行了
        this.slider.next()
      }, this.interval)
    }

下面是整个slider组件的代码,我已经写好了注释,如果有什么不懂的,可以在评论区里留言或私信我,一起探讨,一起进步!

<template>
  <div class="slider" ref="slider">
    <div class="slider-group" ref="sliderGroup">
      <slot></slot>
    </div>
    <div class="dot-group">
      <span
        class="dot"
        v-for="(item,index) in dots"
        :key="index"
        :class="{'dot-active': index === currentPageIndex}"
        @click="changeSliderPage(index)"
      ></span>
    </div>
  </div>
</template>

<script>
import BScroll from 'better-scroll'
import { addClass } from 'common/js/dom'
export default {
  data () {
    return {
      dots: [], // 用于存储轮播图的数量
      currentPageIndex: 0 // 正在显示图片的下标
    }
  },
  props: {
    // 是否循环
    loop: {
      type: Boolean,
      default: true
    },
    // 自动播放
    autoPlay: {
      type: Boolean,
      default: true
    },
    // 时间间隔
    interval: {
      type: Number,
      default: 2000
    }
  },
  mounted () {
    // 在mounted钩子执行后的20ms,dom才完全渲染完
    setTimeout(() => {
      // 初始化slider容器的宽度
      this._initSliderWidth()
      // 初始化小点
      this._initDot()
      // 初始化轮播图
      this._initSlider()
    }, 20)
    // 监听显示大小的变化
    window.onresize = () => {
      // 重新计算slider的宽度
      this._initSliderWidth(true)
      // better-scroll重新计算高度
      this.slider.refresh()
    }
  },
  // 使用了keep-alive组件包裹了,有activated钩子
  activated () {
    if (this.autoPlay) {
      this._play()
    }
  },
  // 离开该组件,就清除计时器
  deactivated () {
    clearTimeout(this.timer)
  },
  methods: {
    _initSliderWidth (isResize) {
      // 获取插槽中的子元素
      this.children = this.$refs.sliderGroup.children
      const sliderWidth = this.$refs.slider.clientWidth
      // 用于存储slider的总宽度
      let width = 0
      for (let i = 0; i < this.children.length; i++) {
        addClass(this.children[i], 'slider-item')
        this.children[i].style.width = `${sliderWidth}px`
        width += sliderWidth
      }
      // isResize是用于第二次渲染的,第二次渲染不需要宽度 * 2,因为页面上已经多了两个dom元素
      if (this.loop && !isResize) {
        width += 2 * sliderWidth
      }
      this.$refs.sliderGroup.style.width = `${width}px`
    },
    _initDot () {
      this.dots = new Array(this.children.length)
    },
    _initSlider () {
      this.slider = new BScroll(this.$refs.slider, {
        scrollX: true, // x轴滚动
        scrollY: false, // y轴滚动
        momentum: false, // 取消滑多少,滚多少。让你滑动一点,就可以滚动下一页或上一页
        snap: { // 轮播图的精髓
          loop: this.loop, // 循环播放
          threshold: 0.3 // 当你滑动30%页面的时候,就滚动上一页或者下一页
        },
        click: true // 允许点击事件
      })
      if (this.autoPlay) {
        clearTimeout(this.timer)
        this._play()
      }
      // 滚动完的生命周期函数
      this.slider.on('scrollEnd', () => {
        // 滚动完就当前页的下标赋值给currentPageIndex
        this.currentPageIndex = this.slider.getCurrentPage().pageX
        // 自动播放就执行
        if (this.autoPlay) {
          this._play()
        }
      })
      // 开始滚动前的生命周期函数
      this.slider.on('beforeScrollStart', () => {
        if (this.autoPlay) {
          clearTimeout(this.timer)
        }
      })
    },
    _play () {
      this.timer = setTimeout(() => {
        // 跳到下一页,因为我们设置配置参数loop为true,better-scroll会帮我们自动循环,我们直接跳下一页就行了
        this.slider.next()
      }, this.interval)
    },
    // 点击对应小点,跳到对应图片
    changeSliderPage (index) {
      this.slider.goToPage(index, 0, 400)
    }
  },
  destroyed () {
    // 清除定时器
    clearTimeout(this.timer)
  }
}
</script>

<style scoped lang="less">
.slider {
  position: relative;
  .slider-group {
    position: relative;
    overflow: hidden;
    .slider-item {
      float: left;
      img {
        display: block;
        width: 100%;
      }
    }
  }
  .dot-group {
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    .dot {
      display: inline-block;
      width: 8px;
      height: 8px;
      background-color: #b0acb2;
      border-radius: 50%;
      margin-left: 5px;
    }
    .dot-active {
      width: 15px;
      border-radius: 5px;
      background-color: #cccdd1;
    }
  }
}
</style>

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值