(该方法只针对移动端使用效果较好,PC端不推荐,使用的版本是[email protected],其他版本会出错)
在根目录中package.json的dependencies中添加:
"better-scroll": "^0.1.15"
然后 npm i
安装。
将better-scroll封装成两个基础组件slider和scroll放于src/base文件夹中。
slider.vue 代码
<template>
<div class="slider" ref="slider">
<div class="slider-group" ref="sliderGroup">
<slot>
slot>
div>
<div class="dots">
<span class="dot" :class="{active: currentPageIndex === index }" v-for="(item, index) in dots">span>
div>
div>
template>
<script>
import {addClass} from '../common/js/dom'
import BScroll from 'better-scroll'
export default{
data() {
return {
dots:[],
currentPageIndex: 0
}
},
props:{
loop:{
type:Boolean,
default:true
},
autoPlay:{
type:Boolean,
default:true
},
interval:{
type: Number,
default:4000
}
},
mounted() {
this._setSliderWidth()
setTimeout(() => {
// 在初始化slider前初始化dot
this._initDots()
this._initSlider()
if (this.autoPlay) {
this._play()
}
}, 20)
// 监听窗口大小改变时间
window.addEventListener('resize', () => {
if (!this.slider) {
return
}
this._setSliderWidth(true)
this.slider.refresh()
})
},
methods:{
_setSliderWidth(isResize) {
this.children = this.$refs.sliderGroup.children
let width = 0
// slider 可见宽度
let sliderWidth = 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 = sliderWidth + 'px'
// 计算总宽度
width += sliderWidth
}
// 循环播放首尾各加一个,因此总宽度还要加两倍的宽度
if (this.loop && !isResize) {
width += 2 * sliderWidth
}
this.$refs.sliderGroup.style.width = width + 'px'
},
_initSlider() {
this.slider = new BScroll(this.$refs.slider, {
scrollX: true,
scrollY: false,
momentum: false,
snap: true,
snapLoop: this.loop,
snapThreshold: 0.3,
snapSpeed: 400,
// click:true
})
// 监听滚动结束时间获取pageX
this.slider.on('scrollEnd', () => {
let pageIndex = this.slider.getCurrentPage().pageX
if (this.loop) {
// 由于bscroll循环播放首尾各加一个,因此索引-1
pageIndex -= 1
}
this.currentPageIndex = pageIndex
if (this.autoPlay) {
this._play()
}
})
this.slider.on('beforeScrollStart', () => {
if (this.autoPlay) {
clearTimeout(this.timer)
}
})
},
_initDots() {
// 长度为n的空数组
this.dots = new Array(this.children.length)
},
_play() {
// currentPageIndex为不含首尾副本的索引,因此若有循环要+2
let pageIndex = this.currentPageIndex + 1
if (this.loop) {
pageIndex += 1
}
this.timer = setTimeout(() => {
this.slider.goToPage(pageIndex, 0, 400)
}, this.interval)
}
},
// 生命周期destroyed销毁清除定时器,有利于内存释放
destroyed() {
clearTimeout(this.timer)
},
}
script>
<style scoped>
.slider{
min-height: 1px;
position: relative;
}
.slider-group{
position: relative;
overflow: hidden;
white-space: nowrap;
}
.slider-item{
float: left;
box-sizing: border-box;
overflow: hidden;
text-align: center;
height: 150px;
overflow: hidden;
}
.slider-item a{
display: block;
width: 100%;
overflow: hidden;
text-decoration: none;
}
.slider-item img{
display: block;
width: 100%;
}
.dots{
position: absolute;
right: 0;
left: 0;
bottom: 12px;
text-align: center;
font-size: 0;
}
.dot{
display: inline-block;
margin: 0 4px;
width: 8px;
height: 8px;
border-radius: 50%;
background: red;
}
.active{
width: 20px;
border-radius: 5px;
}
style>
该代码引用common/js/dom.js中的addClass()方法为每个轮播图添加一个slider-item类,dom.js代码如下:
export function hasClass (el, className) {
// 开始或空白字符+类名+空白字符或结束
let reg = new RegExp('(^|\\s)' + className + '(\\s|$)')
// 测试元素是否有该类名,返回布尔值
return reg.test(el.className)
}
export function addClass (el, className) {
if (hasClass(el, className)) {
return
}
// 以空白符为切割位置切割生成新数组
let newClass = el.className.split(' ')
// 数组中加入新类名
newClass.push(className)
// 将数组元素放入一个字符串,以空白符间隔
el.className = newClass.join(' ')
}
scroll.vue代码
"wrapper">