1. 载入
  2. 结构
  3. 封装
  4. 注意事项

封装Swiper为Vue组件

载入

安装swiper

1
yarn add swiper@4.5.0

另外, 也可以使用cdn载入

1
2
3
4
// css
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.5.0/css/swiper.min.css">
// js
<script src="https://cdnjs.cloudflare.com/ajax/libs/Swiper/4.5.0/js/swiper.min.js"></script>

结构

一个swiper所需的html结构如下

1
2
3
4
5
6
7
8
9
10
11
12

<div class="swiper-container">
<!-- Additional required wrapper -->
<!-- swiper通过更改swiper-wrapper的transform属性来轮播内容 -->
<div class="swiper-wrapper">
<!-- Slides 单个内容-->
<div class="swiper-slide">Slide 1</div>
<div class="swiper-slide">Slide 2</div>
<div class="swiper-slide">Slide 3</div>
...
</div>
</div>

class属性值swiper-wrapper和swiper-slide是必有的,没找到可以更改这两个class的设置项.

创建swiper

1
var mySwiper = new Swiper ('.swiper-container', { params...}

https://idangero.us/swiper/get-started/

See the Pen Swiper示例 by aaronbird (@aaronbird) on CodePen.

封装

component/swiper

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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
<template>
<div class="swiper">
<div class="swiper-container" ref="container">

<div class="swiper-wrapper" ref="wrapper">
<!-- 通过slot传入内容 -->
<slot></slot>
</div>
</div>
<!-- 分页器 -->
<div class="swiper-pagination" ref="pagination"></div>
</div>
</template>

<script>
import Swiper from 'swiper'
import 'swiper/dist/css/swiper.min.css'

export default {
name: 'swiper',
props: {
// 显示分页器
showPagination: {
type: Boolean,
default: false
},
// 显示slide数量
// 可选值: 数字 或 'auto'
slidesPerView: {
type: [Number, String],
default: 1
},
// slide间隔
spaceBetween: {
type: Number,
default: 0
},
// 循环
loop: {
type: Boolean,
default: true
},
// 自动居中
centeredSlides: {
type: Boolean,
default: true
},
// 自动播放
autoplay: {
type: Boolean,
default: false
},
// 时间间隔
delay: {
type: Number,
default: 3000
},
// 用户操作后, 是否禁止自动播放
disableOnInteraction: {
type: Boolean,
default: true
}
},
mounted() {
this.create()
},
beforeDestroy() {
this.destroy()
},
methods: {
create() {
// 如果已经有swiper实例了,就先销毁
this.destroy()

// 轮播内容的class必须为swiper-slide
const slides = this.$refs.wrapper.children
Array.from(slides).forEach(el => {
el.classList.add('swiper-slide')
})
// swiper参数
const param = {
slidesPerView: this.slidesPerView,
spaceBetween: this.spaceBetween,
loop: this.loop,
centeredSlides: this.centeredSlides,
pagination: {}
}
// 自动播放
if (this.autoplay) {
param.autoplay = {
delay: this.delay,
disableOnInteraction: this.disableOnInteraction
}
}
// 显示分页器
if (this.showPagination) {
param.pagination = {
el: this.$refs.pagination
}
}
// 创建swiper
this.swiper = new Swiper(this.$refs.container, param)
},
destroy() {
// 销毁swiper
if (this.swiper) {
this.swiper.destroy()
this.swiper = null
}
},
update() {
// 更新swiper
// 这个方法就是create的别名
this.create()

// swiper的文档说update方法用于更新swiper
// 但试了下更新slide后再调用update方法,并没有什么效果
// 只好先销毁swiper,然后重新创建

// if (this.swiper) {
// this.swiper.update()
// }
}
}
}
</script>

<style scoped>
.swiper {
width: 100%;
position: relative;
}
.swiper-pagination {
position: absolute;
bottom: 10%;
left: 50%;
transform: translateX(-50%);
}

/* 分页器标签由swiper生成, 因此vue不会添加scoped的样式 */
/* https://segmentfault.com/q/1010000010981722 */
/* .swiper-pagination-bullet {
margin: 0 4px;
} */
</style>

<style>
.swiper-pagination-bullet {
margin: 0 4px;
}
</style>

调用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<div v-if="items.length > 0">
<swiper ref="banner" :spaceBetween="20" slidesPerView="auto" :autoplay="true">
<div v-for="(item, index) of items" :key="index">
<img :src="item.pic_info.url" class="needsclick">
</div>
</swiper>
</div>
<template>
<script>
import Swiper from 'component/swiper'
export default {
components: {Swiper}
}
</script>

注意事项

1 最好先获取数据,再渲染swiper.
用vue往往都是先声明一个空数组占位, 异步获取数据后,再添加到数组中.
但对于swiper, 最好用v-if包裹, 等到获取完数据后在渲染swiper.

1
2
3
<div  v-if="items.length > 0"> 
<swiper>...</swiper>
</div>

如果把最外层的v-if去掉,用update更新swiper,可能会有bug.

不赞成的写法:

1
2
3
4
5
<div> // 去掉了 v-if="items.length > 0" 
<swiper ref="swiper" :spaceBetween="20" slidesPerView="auto" :autoplay="true">
...
</swiper>
</div>
1
2
3
4
5
getData().then(()=> {
this.$nextTick(()=> {
this.$refs.swiper.update()
})
})

一些已知bug的例子:
{ loop: true } swiper-slide goes wrong when data is from v-for · Issue #322 · surmon-china/vue-awesome-swiper · GitHub