Commit ccf544dcc2499ddde06aa7bb0076d4885efc9055
1 parent
9b24f1ab
Merge branch 'master' of https://github.com/iview/iview into 2.0
Update carousel component: add loop and radiusDot property # Conflicts: # package.json # src/components/date-picker/picker.vue # src/components/select/select.vue
Showing
4 changed files
with
115 additions
and
19 deletions
Show diff stats
examples/routers/carousel.vue
1 | <template> | 1 | <template> |
2 | <div> | 2 | <div> |
3 | - <Carousel v-model="v1" dots="inside" trigger="hover"> | 3 | + <Carousel v-model="v1" dots="inside" trigger="hover" autoplay loop radius-dot> |
4 | <Carousel-item> | 4 | <Carousel-item> |
5 | - <Card> | ||
6 | - <div class="demo-carousel">1</div> | ||
7 | - </Card> | 5 | + <div class="demo-carousel">1</div> |
8 | </Carousel-item> | 6 | </Carousel-item> |
9 | <Carousel-item> | 7 | <Carousel-item> |
10 | <div class="demo-carousel">2</div> | 8 | <div class="demo-carousel">2</div> |
@@ -24,8 +22,8 @@ | @@ -24,8 +22,8 @@ | ||
24 | export default { | 22 | export default { |
25 | data () { | 23 | data () { |
26 | return { | 24 | return { |
27 | - v1: 1 | ||
28 | - } | 25 | + v1: 0 |
26 | + }; | ||
29 | }, | 27 | }, |
30 | methods: { | 28 | methods: { |
31 | push () { | 29 | push () { |
src/components/carousel/carousel-item.vue
@@ -27,6 +27,15 @@ | @@ -27,6 +27,15 @@ | ||
27 | mounted () { | 27 | mounted () { |
28 | this.$parent.slotChange(); | 28 | this.$parent.slotChange(); |
29 | }, | 29 | }, |
30 | + watch: { | ||
31 | + width (val) { | ||
32 | + if (val && this.$parent.loop) { | ||
33 | + this.$nextTick(() => { | ||
34 | + this.$parent.initCopyTrackDom(); | ||
35 | + }); | ||
36 | + } | ||
37 | + } | ||
38 | + }, | ||
30 | beforeDestroy () { | 39 | beforeDestroy () { |
31 | this.$parent.slotChange(); | 40 | this.$parent.slotChange(); |
32 | } | 41 | } |
src/components/carousel/carousel.vue
@@ -4,9 +4,11 @@ | @@ -4,9 +4,11 @@ | ||
4 | <Icon type="chevron-left"></Icon> | 4 | <Icon type="chevron-left"></Icon> |
5 | </button> | 5 | </button> |
6 | <div :class="[prefixCls + '-list']"> | 6 | <div :class="[prefixCls + '-list']"> |
7 | - <div :class="[prefixCls + '-track']" :style="trackStyles"> | 7 | + <div :class="[prefixCls + '-track', showCopyTrack ? '' : 'higher']" :style="trackStyles" ref="originTrack"> |
8 | <slot></slot> | 8 | <slot></slot> |
9 | </div> | 9 | </div> |
10 | + <div :class="[prefixCls + '-track', showCopyTrack ? 'higher' : '']" :style="copyTrackStyles" ref="copyTrack" v-if="loop"> | ||
11 | + </div> | ||
10 | </div> | 12 | </div> |
11 | <button :class="arrowClasses" class="right" @click="arrowEvent(1)"> | 13 | <button :class="arrowClasses" class="right" @click="arrowEvent(1)"> |
12 | <Icon type="chevron-right"></Icon> | 14 | <Icon type="chevron-right"></Icon> |
@@ -16,7 +18,7 @@ | @@ -16,7 +18,7 @@ | ||
16 | <li :class="[n - 1 === currentIndex ? prefixCls + '-active' : '']" | 18 | <li :class="[n - 1 === currentIndex ? prefixCls + '-active' : '']" |
17 | @click="dotsEvent('click', n - 1)" | 19 | @click="dotsEvent('click', n - 1)" |
18 | @mouseover="dotsEvent('hover', n - 1)"> | 20 | @mouseover="dotsEvent('hover', n - 1)"> |
19 | - <button></button> | 21 | + <button :class="[radiusDot ? 'radius' : '']"></button> |
20 | </li> | 22 | </li> |
21 | </template> | 23 | </template> |
22 | </ul> | 24 | </ul> |
@@ -48,6 +50,10 @@ | @@ -48,6 +50,10 @@ | ||
48 | type: Number, | 50 | type: Number, |
49 | default: 2000 | 51 | default: 2000 |
50 | }, | 52 | }, |
53 | + loop: { | ||
54 | + type: Boolean, | ||
55 | + default: false | ||
56 | + }, | ||
51 | easing: { | 57 | easing: { |
52 | type: String, | 58 | type: String, |
53 | default: 'ease' | 59 | default: 'ease' |
@@ -59,6 +65,10 @@ | @@ -59,6 +65,10 @@ | ||
59 | return oneOf(value, ['inside', 'outside', 'none']); | 65 | return oneOf(value, ['inside', 'outside', 'none']); |
60 | } | 66 | } |
61 | }, | 67 | }, |
68 | + radiusDot: { | ||
69 | + type: Boolean, | ||
70 | + default: false | ||
71 | + }, | ||
62 | trigger: { | 72 | trigger: { |
63 | type: String, | 73 | type: String, |
64 | default: 'click', | 74 | default: 'click', |
@@ -84,11 +94,16 @@ | @@ -84,11 +94,16 @@ | ||
84 | listWidth: 0, | 94 | listWidth: 0, |
85 | trackWidth: 0, | 95 | trackWidth: 0, |
86 | trackOffset: 0, | 96 | trackOffset: 0, |
97 | + trackCopyOffset: 0, | ||
98 | + showCopyTrack: false, | ||
87 | slides: [], | 99 | slides: [], |
88 | slideInstances: [], | 100 | slideInstances: [], |
89 | timer: null, | 101 | timer: null, |
90 | ready: false, | 102 | ready: false, |
91 | - currentIndex: this.value | 103 | + currentIndex: this.value, |
104 | + trackIndex: this.value, | ||
105 | + copyTrackIndex: this.value, | ||
106 | + hideTrackPos: -1, // 默认左滑 | ||
92 | }; | 107 | }; |
93 | }, | 108 | }, |
94 | computed: { | 109 | computed: { |
@@ -97,13 +112,27 @@ | @@ -97,13 +112,27 @@ | ||
97 | `${prefixCls}` | 112 | `${prefixCls}` |
98 | ]; | 113 | ]; |
99 | }, | 114 | }, |
115 | + listStyle () { | ||
116 | + return { | ||
117 | + width: `${this.trackWidth * 2}px`, | ||
118 | + }; | ||
119 | + }, | ||
100 | trackStyles () { | 120 | trackStyles () { |
101 | return { | 121 | return { |
102 | width: `${this.trackWidth}px`, | 122 | width: `${this.trackWidth}px`, |
103 | - transform: `translate3d(-${this.trackOffset}px, 0px, 0px)`, | 123 | + transform: `translate3d(${-this.trackOffset}px, 0px, 0px)`, |
104 | transition: `transform 500ms ${this.easing}` | 124 | transition: `transform 500ms ${this.easing}` |
105 | }; | 125 | }; |
106 | }, | 126 | }, |
127 | + copyTrackStyles () { | ||
128 | + return { | ||
129 | + width: `${this.trackWidth}px`, | ||
130 | + transform: `translate3d(${-this.trackCopyOffset}px, 0px, 0px)`, | ||
131 | + transition: `transform 500ms ${this.easing}`, | ||
132 | + position: 'absolute', | ||
133 | + top: 0 | ||
134 | + }; | ||
135 | + }, | ||
107 | arrowClasses () { | 136 | arrowClasses () { |
108 | return [ | 137 | return [ |
109 | `${prefixCls}-arrow`, | 138 | `${prefixCls}-arrow`, |
@@ -142,6 +171,12 @@ | @@ -142,6 +171,12 @@ | ||
142 | }); | 171 | }); |
143 | } | 172 | } |
144 | }, | 173 | }, |
174 | + // copy trackDom | ||
175 | + initCopyTrackDom () { | ||
176 | + this.$nextTick(() => { | ||
177 | + this.$refs.copyTrack.innerHTML = this.$refs.originTrack.innerHTML; | ||
178 | + }); | ||
179 | + }, | ||
145 | updateSlides (init) { | 180 | updateSlides (init) { |
146 | let slides = []; | 181 | let slides = []; |
147 | let index = 1; | 182 | let index = 1; |
@@ -158,7 +193,6 @@ | @@ -158,7 +193,6 @@ | ||
158 | }); | 193 | }); |
159 | 194 | ||
160 | this.slides = slides; | 195 | this.slides = slides; |
161 | - | ||
162 | this.updatePos(); | 196 | this.updatePos(); |
163 | }, | 197 | }, |
164 | updatePos () { | 198 | updatePos () { |
@@ -185,21 +219,57 @@ | @@ -185,21 +219,57 @@ | ||
185 | this.updatePos(); | 219 | this.updatePos(); |
186 | this.updateOffset(); | 220 | this.updateOffset(); |
187 | }, | 221 | }, |
222 | + updateTrackPos (index) { | ||
223 | + if (this.showCopyTrack) { | ||
224 | + this.trackIndex = index; | ||
225 | + } else { | ||
226 | + this.copyTrackIndex = index; | ||
227 | + } | ||
228 | + }, | ||
229 | + updateTrackIndex (index) { | ||
230 | + if (this.showCopyTrack) { | ||
231 | + this.copyTrackIndex = index; | ||
232 | + } else { | ||
233 | + this.trackIndex = index; | ||
234 | + } | ||
235 | + }, | ||
188 | add (offset) { | 236 | add (offset) { |
189 | - let index = this.currentIndex; | 237 | + // 获取单个轨道的图片数 |
238 | + let slidesLen = this.slides.length; | ||
239 | + // 如果是无缝滚动,需要初始化双轨道位置 | ||
240 | + if (this.loop) { | ||
241 | + if (offset > 0) { | ||
242 | + // 初始化左滑轨道位置 | ||
243 | + this.hideTrackPos = -1; | ||
244 | + } else { | ||
245 | + // 初始化右滑轨道位置 | ||
246 | + this.hideTrackPos = slidesLen; | ||
247 | + } | ||
248 | + this.updateTrackPos(this.hideTrackPos); | ||
249 | + } | ||
250 | + // 获取当前展示图片的索引值 | ||
251 | + let index = this.showCopyTrack ? this.copyTrackIndex : this.trackIndex; | ||
190 | index += offset; | 252 | index += offset; |
191 | - while (index < 0) index += this.slides.length; | ||
192 | - index = index % this.slides.length; | ||
193 | - this.currentIndex = index; | ||
194 | - this.$emit('input', index); | 253 | + while (index < 0) index += slidesLen; |
254 | + if (((offset > 0 && index === slidesLen) || offset < 0 && index === slidesLen - 1) && this.loop) { | ||
255 | + // 极限值(左滑:当前索引为总图片张数, 右滑:当前索引为总图片张数 - 1)切换轨道 | ||
256 | + this.showCopyTrack = !this.showCopyTrack; | ||
257 | + this.trackIndex += offset; | ||
258 | + this.copyTrackIndex += offset; | ||
259 | + } else { | ||
260 | + if (!this.loop) index = index % this.slides.length; | ||
261 | + this.updateTrackIndex(index); | ||
262 | + } | ||
263 | + this.$emit('input', index === this.slides.length ? 0 : index); | ||
195 | }, | 264 | }, |
196 | arrowEvent (offset) { | 265 | arrowEvent (offset) { |
197 | this.setAutoplay(); | 266 | this.setAutoplay(); |
198 | this.add(offset); | 267 | this.add(offset); |
199 | }, | 268 | }, |
200 | dotsEvent (event, n) { | 269 | dotsEvent (event, n) { |
201 | - if (event === this.trigger && this.currentIndex !== n) { | ||
202 | - this.currentIndex = n; | 270 | + let curIndex = this.showCopyTrack ? this.copyTrackIndex : this.trackIndex; |
271 | + if (event === this.trigger && curIndex !== n) { | ||
272 | + this.updateTrackIndex(n); | ||
203 | this.$emit('input', n); | 273 | this.$emit('input', n); |
204 | // Reset autoplay timer when trigger be activated | 274 | // Reset autoplay timer when trigger be activated |
205 | this.setAutoplay(); | 275 | this.setAutoplay(); |
@@ -215,7 +285,10 @@ | @@ -215,7 +285,10 @@ | ||
215 | }, | 285 | }, |
216 | updateOffset () { | 286 | updateOffset () { |
217 | this.$nextTick(() => { | 287 | this.$nextTick(() => { |
218 | - this.trackOffset = this.currentIndex * this.listWidth; | 288 | + /* hack: revise copyTrack offset (1px) */ |
289 | + let ofs = this.copyTrackIndex > 0 ? -1 : 1; | ||
290 | + this.trackOffset = this.trackIndex * this.listWidth; | ||
291 | + this.trackCopyOffset = this.copyTrackIndex * this.listWidth + ofs; | ||
219 | }); | 292 | }); |
220 | } | 293 | } |
221 | }, | 294 | }, |
@@ -228,6 +301,11 @@ | @@ -228,6 +301,11 @@ | ||
228 | }, | 301 | }, |
229 | currentIndex (val, oldVal) { | 302 | currentIndex (val, oldVal) { |
230 | this.$emit('on-change', oldVal, val); | 303 | this.$emit('on-change', oldVal, val); |
304 | + }, | ||
305 | + trackIndex () { | ||
306 | + this.updateOffset(); | ||
307 | + }, | ||
308 | + copyTrackIndex () { | ||
231 | this.updateOffset(); | 309 | this.updateOffset(); |
232 | }, | 310 | }, |
233 | height () { | 311 | height () { |
src/styles/components/carousel.less
@@ -31,6 +31,9 @@ | @@ -31,6 +31,9 @@ | ||
31 | overflow: hidden; | 31 | overflow: hidden; |
32 | 32 | ||
33 | z-index: 1; | 33 | z-index: 1; |
34 | + &.higher { | ||
35 | + z-index: 2; | ||
36 | + } | ||
34 | } | 37 | } |
35 | 38 | ||
36 | &-item { | 39 | &-item { |
@@ -159,6 +162,11 @@ | @@ -159,6 +162,11 @@ | ||
159 | color: transparent; | 162 | color: transparent; |
160 | 163 | ||
161 | transition: all .5s; | 164 | transition: all .5s; |
165 | + &.radius { | ||
166 | + width: 6px; | ||
167 | + height: 6px; | ||
168 | + border-radius: 50%; | ||
169 | + } | ||
162 | } | 170 | } |
163 | 171 | ||
164 | &:hover > button { | 172 | &:hover > button { |
@@ -168,6 +176,9 @@ | @@ -168,6 +176,9 @@ | ||
168 | &.@{carousel-prefix-cls}-active > button { | 176 | &.@{carousel-prefix-cls}-active > button { |
169 | opacity: 1; | 177 | opacity: 1; |
170 | width: 24px; | 178 | width: 24px; |
179 | + &.radius{ | ||
180 | + width: 6px; | ||
181 | + } | ||
171 | } | 182 | } |
172 | } | 183 | } |
173 | } | 184 | } |