better-scroll 是什么
better-scroll 是一款重点解决移动端(已支持 PC)各种滚动场景需求的插件。它的核心是借鉴的 iscroll 的实现,它的 API 设计基本兼容 iscroll,在 iscroll 的基础上又扩展了一些 feature 以及做了一些性能优化。
better-scroll 是基于原生 JS 实现的,不依赖任何框架。它编译后的代码大小是 63kb,压缩后是 35kb,gzip 后仅有 9kb,是一款非常轻量的 JS lib。
今天我们利用它实现一个横向滚动——轮播图组件。演示如下:
首先来整理一下需求:
Mock数据
由于是一个demo,从网上找了几张图片写成json格式,数据用于模拟接口数据。这里用到了mock.js。Axios。安装方法如下:
npm install mockjs
npm install --save axios vue-axios
axios使用方法不多赘述,简述一下mock数据。在mock文件夹下新建json文件夹放置json数据文件。新建index.js导出接口。就可以使用axios请求接口了。
1
2
3
|
const Mock = require( 'mockjs' ) Mock.mock( '/slider' , 'get' , require( './json/slider.json' )) |
基础组件:slider.vue
将轮播图组件抽象出来,接收isLoop、isAutoPlay、interval属性控制轮播图。从mounted方法调用顺序可以知道思路是
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
<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中的使用方法应用在自己的项目中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
<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中找到源码。