时间:2022-10-25 09:31:51 | 栏目:vue | 点击:次
前言
better-scroll是一个非常非常强大的第三方库 在移动端利用这个库 不仅可以实现一个非常类似原生ScrollView的效果 也可以实现一个轮播图的效果 这里就先记录一下自己实现这个效果的一些过程吧
思路
1.首先要确定自己的HTML结构 基本结构就是一个wrapper包含一个content
2.其次需要明白的一个页面可以滚动的原理在于 当内容的高度超出了容器的高度才可以实现滚动 如果没有超出 那么就没有滚动的必要 因此第一点需要实现的就是 获取到所有内容的高度 由于实现的是一个轮播图 所以其实整个页面应该想象成这样
滚动原理
这里可以很清楚的看到 当页面的横向宽度超出了视口的宽度 因此也就可以实现滚动 综上所述 可以看出 实现横向轮播最重要的一点在于宽度 因此 我们首先要获得的就是整个轮播图的宽度
3.既然是个轮播图 那么用户同时也需要知道的就是 当前播放的是第几张图 也就是常见的"小白点" 小白点的个数用于告诉用户总共有几张图 而当前播放第几张图则可以在小白点上加上一些特殊样式的方法来告知用户
4.轮播图也需要一些常见的属性 例如 页面渲染以后自动播放以及播放间隔 还有一个就是 是否支持循环轮播
理清思路以后 就可以开始干活了 1.完善HTML结构 其实代码非常简单 也就是创建两个div 并且添加ref引用可以方便的通过ref属性获取上下文
<div class="slider" ref="slider"> <div class="slider-content" ref="sliderContent"> <slot></slot> </div> </div>
这里用了vue中非常常见的slot插槽 为的是当我们在外部调用这个slider组件的时候 可以方便的在外部传入一些子组件
2.上文已经提到了一些控制slider的属性 所以需要在组件的props里接受这些属性 便于我们在外部方便的控制这些属性
props: { // 是否循环播放 loop: { type: Boolean, default: true }, // 是否自动播放 autoPlay: { type: Boolean, default: true }, // 播放间隔 interval: { type: Number, default: 3000 } }
3.一些初始步骤的完成的差不多了以后 我们需要借助到vue的一个生命周期钩子 mounted 也就是当页面渲染完毕以后 去获取轮播图的宽度以及初始化轮播图的一些设置
mounted: function () { setTimeout(() => { this.setSliderWidth() this.initSlider() }, 20)
这里有一个小小的tips 就是 通常情况下 浏览器渲染dom的时间为17ms 所以这里使用了一个延迟函数 在20ms以后去调用这些方法 也就是确保浏览器的dom被正确渲染 防止出现一些问题
4.上面只是调用了这个方法 还没有实现这些方法 首先在设置宽度的方法里 我们需要通过$refs.sliderContent拿到上下文 并且通过一个$refs.slider.clientWidth方法拿到当前屏幕宽度 然后遍历这个容器 取得容器里的所有内容 同时把获取的内容宽度设置为这个屏幕的宽度 最后所有的内容的宽度相加 就可以得到整个slider的宽度 说了这么多 感觉很绕口 所以还是看下代码吧
// 设置slider的宽度 setSliderWidth: function (isResize) { // 获取slider里的所有的子元素 this.children = this.$refs.sliderContent.children // console.log(this.children) // 计算宽度 = 图片个数+每张图片的宽度 let width = 0 // 获取手机屏幕的宽度 let sliderWidth = this.$refs.slider.clientWidth for (let i = 0; i < this.children.length; i++) { // 获取children里的每一项内容 let child = this.children[i] child.style.width = sliderWidth + 'px' width += sliderWidth } if (this.loop) { width += 2 * sliderWidth } this.$refs.sliderContent.style.width = width + 'px' }
这样我们就获取了整个slider的宽度 还有一个细节在于 当如果是loop的时候 better-scroll会在头尾克隆两份 所以宽度会需要*2 接下去就是实现一些初始化better-scroll的一些配置了 具体的参数内容可以从better-scorll官网上查询到 这里就不多做赘述了
// 设置宽度以后初始化slider initSlider: function () { this.slider = new BScroll(this.$refs.slider, { scrollX: true, scrollY: false, momentum: false, snap: { loop: this.loop, threshold: 0.3, speed: 400 }, click: true }) }
5.实现上述两个方法以后 其实轮播图基本已经可以在页面上看到了 大概就是长成这样 不过这样写完以后 会发现轮播图是没有办法自动轮播的以及当前显示的是几张图的样式并没有正确显示 所以接下去就是实现这两个方法 ps:这里的图片数据来源什么 是请求了QQ音乐banner的接口文件
轮播图的效果
6.实现dots样式的正确加载 这里用到了vue中样式的绑定
<div class="dots"> <span class="dot" v-for="(item, index) of dots" :class="{active:currentPageIndex === index}" :key="index"> </span> </div>
也就是说 我们通过下标来绑定样式 同时监听一个better-scroll的'scrollEnd'事件 当滚动结束的时候调用getCurrentPage()这个方法 这个方法会有一个返回值pageX 也就是横向滚动到第几页 把这个返回值赋值给currentPageIndex 从而达到正确显示样式的目的
this.slider.on('scrollEnd', () => { let page = this.slider.getCurrentPage().pageX this.currentPageIndex = page // 当滚动结束以后 如果是自动播放的话 那么首先要清除定时器(防止手动拖动轮播图以后图片无法正确显示)然后再次执行方法 才能实现轮播 if (this.autoPlay) { clearTimeout(this.timer) this.play() } })
7.实现自动播放功能 better-scroll也提供了一个接口goToPage(x, y, time, easing) 顾名思义也就是转到对应页面 其中几个参数分别代表 x表示横向页面 y表示纵向页面 time表示动画执行时间 easing一般不建议修改 有了这个接口 其实就非常轻松了 我们只需要在methods里再写一个Play方法 具体的思路就是 通过currentPageIndex+=1得到下一张要播放的图片的索引 同时当索引值达到图片数组的长度的时候将要索引重新赋值为0就好了 并在页面渲染了以后调用就可以了
play: function () { let playPage = this.currentPageIndex + 1 if (playPage === this.children.length - 2) { playPage = 0 } setTimeout(() => { this.slider.goToPage(playPage, 0, 400) }, this.interval) }
这里也有个细节就是 当设置这个轮播图为循环滚动的时候 better-scroll会自动在头尾各克隆一份图片 所以长度需要减去2 这样就可以实现轮播图的自动播放了
总结