使用vue.js制作carousel跑马灯组件

前几天在掘金上看到一个开源项目(PyUI)在招人,一个基于vue.js的UI库,想着反正页闲着,就硬着头皮加入了(其实我都还没学vue.js)
两天速成了一下,学了点皮毛,就开始撸代码了,组织给我分配的是carousel跑马灯的组件

边学边做,一天半撸完了,效果完全参照iview的跑马灯效果(任务要求)
其实原本只要拿iview的代码过来改一改就好了,但是感觉这样页学不到什么,硬着头皮自己撸了

第一次写vue.js感觉在项目任务的督促下学的还是很快的

carousel组件构成

跑马灯的过渡效果主要用了<transition>组件
我的主要思想是将carousel插槽内的代码块提取出来,用一个<li>列表放置在<transition>内,然后实现轮播效果

html部分

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
<template>
<div :class="classes">
<div class="py-carousel__slide-lists" ref="carousel_list">
<slot></slot>
</div>
<button :class="arrowClasses" class="lefts" @click="change(currentIndex-1)">
</button>
<button :class="arrowClasses" class="rights" @click="change(currentIndex+1)">
</button>
<transition-group tag="div" name="list" class="py-carousel__slide-current">
<li v-for="(list,index) in slideList.length"
class="py-carousel__slide-current-item"
:key="index"
v-show="index===currentIndex"
@mouseenter="hover(1)"
@mouseleave="hover(2)">
<div v-html="slideList[index].outerHTML"></div>
</li>
</transition-group>
<div :class="'py-carousel__positions-'+position" class="py-carousel__positions">
<span v-for="(item,index) in slideList.length" :key="index"
:class="positionClass(index)"
@mouseover="hoverChange(index)"
@mouseleave="hover(3)"
@click="change(index)">
</span>
</div>
</div>
</template>

js部分

我感觉相对于iview的代码,相同的效果我的代码量已经少了好多,当然可能人家的组件比较稳定吧,我的还没经过比较正规的测试

js部分主要就是一些函数鼠标对轮播图的操作,轮播函数是autoplay()go()两个函数主要控制的

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

<script>
// 组件class前缀
const prefixCls = 'py-carousel';
const Props = {
arrow: new Set(['hover', 'always', 'never']),
position: new Set(['inside', 'outside', 'none', 'left', 'right']),
};

export default {
name: 'py-carousel',
props: {
// 初始位置
value: {
type: Number,
default: 0,
},
// 轮播速度
speed: {
type: Number,
default: 3000,
},
// 初始自动轮播
autoloop: {
type: Boolean,
default: true,
},
// 自动轮播
loop: {
type: Boolean,
default: true,
},
// 鼠标移至界面时是否暂停
hoverstop: {
type: Boolean,
default: true,
},
// 两侧箭头显示时机
arrow: {
type: String,
default: 'hover',
validator (value) {
return Props.arrow.has(value);
},
},
// 底部指示器位置
position: {
type: String,
default: 'outside',
validator (value) {
return Props.position.has(value);
},
},
// 圆形指示器
radiusPosition: {
type: Boolean,
default: false,
},
// 指示器触发方式
trigger: {
type: Boolean,
default: true,
},
},
data () {
return {
slideList: [],
currentIndex: 0,
timer: '',
};
},
computed: {
classes() {
return `${prefixCls}`;
},
arrowClasses () {
return [
`py-carousel__arrow`,
`py-carousel__arrow-${this.arrow}`,
];
},
},
methods: {
go() {
this.timer = setInterval(() => {
this.autoPlay();
}, this.speed);
},
stop() {
clearInterval(this.timer);
this.timer = null;
},
hover(n) {
if (n === 1 && this.hoverstop) this.stop();
if (n === 2 && this.hoverstop) this.go();
if (n === 3 && this.trigger) this.go();
},
change(index) {
index = (index + this.slideList.length) % this.slideList.length;
this.currentIndex = index;
this.stop();
},
hoverChange(index) {
if (this.trigger) {
this.change(index);
}
},
autoPlay() {
if (this.loop) {
this.currentIndex += 1;
if (this.currentIndex > this.slideList.length - 1) {
this.currentIndex = 0;
}
}
},
positionClass(index) {
const classs = [];
if (index === this.currentIndex) classs.push(`active`);
if (this.radiusPosition) classs.push(`radius`);
return classs;
},
},
created() {
this.$nextTick(() => {
this.slideList = this.$refs.carousel_list.children;
this.currentIndex = this.value;
if (this.autoloop) {
this.timer = setInterval(() => {
this.autoPlay();
}, this.speed);
}
});
},
};
</script>

相对来说,代码量挺少了哈

css部分

css部分有个小问题就是,当底部指示器的位置设置在外部时,我是从carousel的高度中拿出5%的高度作为底部指示器的空间,然后carousel的高度是向外自适应的,所以carousel1的父节点必须指定高度,而且要和内部轮播代码框的高度一致

12月8日更新修复了上诉问题

以下为scss代码

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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
@charset "UTF-8";

@include b(carousel) {
box-sizing: border-box;
position:relative;
height: 100%;
width: 100%;
display: block;
-webkit-box-sizing: border-box;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-ms-touch-action: pan-y;
touch-action: pan-y;

@include e(slide) {

@include e(slide-lists) {
display: none;
}

@include e(slide-current) {
position: relative;
width: 100%;
height: 100%;
display: block;
overflow: hidden;
padding:0;
margin: 0;
li {
position: absolute;
width: 100%;
height: 100%;
}
}

@include e(slide-current-item) {
list-style-type:none;
width: 100%;
height: 100%;
margin:0;
padding:0;
}
}

@include e(arrow) {
border: none;
outline: none;
padding: 0;
margin: 0;
width: 36px;
height: 36px;
border-radius: 50%;
cursor: pointer;
position: absolute;
top: 50%;
z-index: 10;
transform: translateY(-50%);
background-color: rgba(31, 45, 61, 0.11);
text-align: center;
color: aliceblue;
font-size: 1em;
font-family: inherit;
line-height: inherit;
&.rights {
right: 16px;
}
&.lefts{
left: 16px;
}

&.rights:before {
content: ">";
}
&.lefts:before{
content: "<";
}

@include e(arrow-hover) {
display: inherit;
opacity: 0;
}

@include e(arrow-always) {
display: inherit;
}
@include e(arrow-never) {
display: none;
}

&-hover > * {
vertical-align: baseline;
}

}

&:hover &__arrow-hover {
opacity: 1;
}

@include e(positions) {
display: block;
z-index: 10;
height: 16px;
width: 100%;
position: relative;
text-align: center;

@include e(positions-inside) {
position: absolute;
bottom: 8px;
height: 12px;
}

@include e(positions-outside) {
margin-top: 8px;
width: 100%;
position: relative;
}

@include e(positions-none) {
display: none;
}

@include e(positions-left) {
position: absolute;
bottom: 8px;
text-align: left;
padding-left: 18px;
height: 12px;
}

@include e(positions-right) {
position: absolute;
bottom: 8px;
text-align: right;
padding-right: 18px;
height: 12px;
}

span {
display: inline-block;
vertical-align: top;
text-align: center;
margin: 0 2px;
width: 20px;
height: 3px;
border-radius: 0;
cursor: pointer;
background-color:#898989;
opacity: 0.5;
font-size: 12px;
&.active {
width: 25px;
background-color: rgb(82, 87, 74);
opacity: 0.7;
}
}
.radius {
width: 12px;
height: 12px;
border-radius: 50%;
border: 1px solid #2b2b28;
background: rgba(82, 87, 74, 0.1);
&.active {
width: 12px;
background-color: #505042;
opacity: 0.7;
}
}
}

.list-enter-to {
transition: all 0.8s ease;
transform: translateX(0);
}

.list-leave-active {
transition: all 0.8s ease;
transform: translateX(-100%)
}

.list-enter {
transform: translateX(100%)
}

.list-leave {
transform: translateX(0)
}
}

放上GitHub地址

PyUi








我是小鸡,这篇文章的标题是——使用vue.js制作carousel跑马灯组件
喜欢的话可以转载,不过记得标记出处

2018年12月02日