您的位置:首页 > 产品设计 > UI/UE

使用better-scroll实现slider组件

2017-10-24 14:50 344 查看
经过很长的一段时间折腾和看视频、文档,终于热乎乎的slider的组件编写,已经基本完成了,以下就是整个思路:

首先呢,需要用到大名鼎鼎的移动端滑动库better-scroll了

新建一个名为slider.vue的文件,基本结构如下:

<template>
<div class="slider" ref="slider">
<div class="slider-group" ref="sliderGroup">
<slot></slot>
</div>
<div class="dots">
<span class="dot"></span>
</div>
</div>
</template>


上述代码中的slot插槽的说明:在外部引用slide时,slider包裹的DOM会被插入进这个slot插槽部分 ,

eg:在相关页面需要引用slide组件的地方写下如下代码:

<slide>

<div>这里div的部分会被放进slot里面</div>

</slide>


在slider.vue中加入script部分,然后引用我们需要用到better-scroll库。ps:一定要先安装才可以使用它哦,npm install better-scorll –save

import BScroll from 'better-scroll'
export default {
props: { // 这里定义可在外部控制的属性
loop: { // 是否是循环轮播
type: Boolean,
default: true
},
autoPlay: { // 自动播放
type: Boolean,
default: true
},
interval: { // 自动轮播间隔
type: Number,
default: 4000
}
},
mounted() { // 初始化
setTimeout(() => {
this._setSliderWideth() //初始化slider的宽度
}, 20)
},
methods: {
_setSliderWideth(isResize) {
// 获取整个列表有多少个元素
this.children = this.$refs.slideGroup.children
let width = 0 // 总的宽度
// slider 父元素的宽度
let slideWidth = this.$refs.slider.clientWidth
for (let i = 0; i < this.children.length; i++) {
let child = this.children[i] // 获取每个子元素
addClass(child, 'slider-item') // 添加名为slider-item的类名

child.style.width = slideWidth + 'px'
console.log(child.style.width)
width += slideWidth
}
if (this.loop && !isResize) { // 如果slide是需要循环的话,slide会在左右两侧copy两个子元素从而保证循环切换
width += 2 * slideWidth
console.log(width)
}
this.$refs.slideGroup.style.width = width + 'px'
}
}
}


上述代码中,因为我们是吧slider这个组件抽离出来做成木偶组件,并不直接进行数据之间的交互,所以我们需要先在props中定义可以在外部控制的属性(loop 是否循环播放,autoPlay自动播放,interval 自动轮播间隔)

1、在mounted的计算属性中进行初始化

2、在methods中进行私有函数的定义,自定义的函数方法都是在该计算属性中进行的

2-1、关于addClass()方法的说明,因为该方法是直接进行DOM操作,所以该方法是单独放在一个js文件中,代码如下:

export function addClass(el, className) {

if (hasClass(el, className)) { // 该DOM对象有这个类名时,什么都不做

return

}

let newClass = el.className.split('') // 获取类名

newClass.push(className)

el.className = newClass.join('')

}

export function hasClass(el, className) { // 是否存在该类名

let reg = new RegExp('(^|\\s)' + className + '(\\s|$)') // (\\s| 空白字符)

return reg.test(el.className) // el.className 获取class

}


然后在
import BScroll from 'better-scroll'
下面引入import { addClass } from ‘你的那个dom.js文件路径’

这个时候我们的slider的宽度已经计算完成,现在需要初始化slider,这里需要使用better-scroll暴露出来的方法与事件来操作slider,在methods计算属性中新建一个方法叫_initSlider(),代码如下:

_initSlider() { // 初始化slide
this.slider = new BScroll(this.$refs.slider, {
scrollX: true, // 横向滚动
scrollY: false, // 不允许纵向滚动
momentum: false, // 是否开启动量动画,关闭可以提升效率
// ***配置:在better-scroll版本0.1.15以前可用以下参数进行slide配置,但1.0.0版本以上需按照未注释前的方法使用***/
// snap: true, // slide组件
// snapLoop: this.loop, // 循环
// snapThreshold: 0.3, //
// snapSpeed: 400
snap: {
loop: this.loop,
threshold: 0.3,
speed: 400
}
})
this.slider.on('scrollEnd', () => {
// 参考文档 https://ustbhuangyi.github.io/better-scroll/doc/zh-hans/api-specific.html#getcurrentpage let pageIndex = this.slider.getCurrentPage().pageX
if (this.loop) {
pageIndex -= 1 // 因为设置自动播放之后,会自动在左右两侧copy两个子元素,所以在设置pageIndex时应减一
}
this.currentPageIndex = pageIndex
if (this.autoPlay) {
this._play()
}
})
// 参考文档 https://ustbhuangyi.github.io/better-scroll/doc/zh-hans/events.html#beforescrollstart this.slider.on('beforeScrollStart', () => {
if (this.autoPlay) {
clearTimeout(this.timer)
}
})
},


上述代码里面需要特别注意的是better-scroll的版本的不同,初始化scroll的时有参数不同,具体请参照官方文档

全部代码如下:

<template>
<div class="slider" ref="slider">
<div class="slider-group" ref="slideGroup">
<slot></slot>
<!--slot插槽说明
//外部引用slide时,slider包裹的DOM会被插入进这个slot插槽部分
eg:
在相关页面需要引用slide组件的地方写下如下代码:
<slide>
<div>...这里写循环的内容与结构....</div>
</slide>
-->
</div>
<div class="dots">
<span class="dot" v-for="(item, index) in dots" :class="{active: currentPageIndex === index}"></span>
</div>
</div>
</template>

<script>
import BScroll from 'better-scroll'
import { addClass } from '../../assets/js/dom'
// slide 基于better-scroll实现,监听了它的几个事件{snap,snapLoop,snapThreshold,snapSpeed } **注:better-scroll因为版本原因,以上几个事件会有出入,请参考官方文档,下面在实例化better-scroll时有做详细说明**
export default {
data() {
return {
dots: [], // 定义一个名为dots的数组,小圆点数组
currentPageIndex: 0 // 当前的页码
}
},
props: { // 这里定义可在外部控制的属性
loop: { // 是否是循环轮播
type: Boolean,
default: true
},
autoPlay: { // 自动播放
type: Boolean,
default: true
},
interval: { // 自动轮播间隔
type: Number,
default: 4000
}
},
mounted() { // 初始化 better-scroll时机(*一般初始化better-scroll不成功,会引起*)
setTimeout(() => {
this._setSliderWideth()
this._initDots()
this._initSlider()
if (this.autoPlay) {
this._play()
}
}, 20)// 保证DOM被渲染,做了20ms的延时(*为何值为20??* 因为浏览器刷新时间一般为17ms一次)
//
window.addEventListener('resize', () => {
if (!this.slider) {
return
}
this._setSliderWideth(true)
this.slider.refresh()
})
},
methods: {
// 因为是横向滚动,需计算slide 的宽度并且赋值
_setSliderWideth(isResize) {
this.children = this.$refs.slideGroup.children // 获取整个列表有多少个元素
console.log(this.children.length)

let width = 0 // 总的宽度
let slideWidth = this.$refs.slider.clientWidth // slide 父元素的宽度
for (let i = 0; i < this.children.length; i++) {
let child = this.children[i] // 获取每个子元素
addClass(child, 'slider-item') // 添加名为slider-item的类名

child.style.width = slideWidth + 'px'
console.log(child.style.width)
width += slideWidth
}
if (this.loop && !isResize) { // 如果slide是需要循环的话,slide会在左右两侧copy两个子元素从而保证循环切换
width += 2 * slideWidth
}
this.$refs.slideGroup.style.width = width + 'px'
},
_initDots() {
this.dots = new Array(this.children.length)
},
_initSlider() { // 初始化slide this.slider = new BScroll(this.$refs.slider, { scrollX: true, // 横向滚动 scrollY: false, // 不允许纵向滚动 momentum: false, // 是否开启动量动画,关闭可以提升效率 // ***配置:在better-scroll版本0.1.15以前可用以下参数进行slide配置,但1.0.0版本以上需按照未注释前的方法使用***/ // snap: true, // slide组件 // snapLoop: this.loop, // 循环 // snapThreshold: 0.3, // // snapSpeed: 400 snap: { loop: this.loop, threshold: 0.3, speed: 400 } }) this.slider.on('scrollEnd', () => { // 参考文档 https://ustbhuangyi.github.io/better-scroll/doc/zh-hans/api-specific.html#getcurrentpage let pageIndex = this.slider.getCurrentPage().pageX if (this.loop) { pageIndex -= 1 // 因为设置自动播放之后,会自动在左右两侧copy两个子元素,所以在设置pageIndex时应减一 } this.currentPageIndex = pageIndex if (this.autoPlay) { this._play() } }) // 参考文档 https://ustbhuangyi.github.io/better-scroll/doc/zh-hans/events.html#beforescrollstart this.slider.on('beforeScrollStart', () => { if (this.autoPlay) { clearTimeout(this.timer) } }) },
_play() {
let pageIndex = this.currentPageIndex + 1
if (this.loop) {
pageIndex += 1
}
this.timer = setTimeout(() => {
this.slider.goToPage(pageIndex, 0, 400)
}, this.interval)
}
},
destroyet() {
clearTimeout(this.timer)
}
}
</script>

<style rel="stylesheet" lang="stylus">
@import "../../assets/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%
.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: $color-text-l
&.active
width: 20px
border-radius: 5px
background: $color-text-ll
</style>
</style>


如何使用slider

在该使用的地方直接 import slider from ‘你的slider文件的路径’

代码如下:

<template>
<div v-if="recommends.length" class="slider-wrapper">
<slider >
<div v-for="item in recommends">
<a>
<img class="needsclick" :src="item.picUrl" alt="">
</a>
</div>
</slider>
</div>
</template>
<script>
import Slider from '你的slider文件的路径'
export default{
data() {
return {
recommends: [
{'picurl':'http://y.gtimg.cn/music/photo_new/T003R720x288M000002QA9kw0QwiVQ.jpg'},
{'picurl':'http://y.gtimg.cn/music/photo_new/T003R720x288M000002QA9kw0QwiVQ.jpg'},
{'picurl':'http://y.gtimg.cn/music/photo_new/T003R720x288M000002QA9kw0QwiVQ.jpg'},
{'picurl':'http://y.gtimg.cn/music/photo_new/T003R720x288M000002QA9kw0QwiVQ.jpg'}
]
}
},
components: {
Slider
}
}
</script>


好了,关于slider的封装与使用就到此结束了….
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  vue