Skip to content

Commit 353fc68

Browse files
committed
feat: improve CCarousel and CCarouselItem components (no side effects)
1 parent 5864fab commit 353fc68

File tree

2 files changed

+122
-80
lines changed

2 files changed

+122
-80
lines changed

src/components/Carousel/CCarousel.vue

Lines changed: 72 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
11
<template>
2-
<div class="carousel slide" >
3-
<ol v-if="!noIndicators" :class="indicatorClasses">
2+
<div class="carousel slide" :style="{ height: height || 'auto' }">
3+
<ol v-if="indicators" :class="indicatorClasses">
44
<li
5-
v-for="(index, key) in itemsLength"
6-
@click="setSlide(key)"
7-
:class="{'active' : active === key}"
5+
v-for="(index, key) in items.length"
6+
@click="setItem(key)"
7+
:class="{ active: activated === key }"
88
:key="key"
99
></li>
1010
</ol>
1111
<div class="carousel-inner">
1212
<slot></slot>
1313
</div>
14-
<template v-if="!noArrows">
15-
<a class="carousel-control-prev" @click="previousSlide">
16-
<span class="carousel-control-prev-icon"></span>
17-
<span class="sr-only">Previous</span>
18-
</a>
19-
<a class="carousel-control-next" @click="nextSlide">
20-
<span class="carousel-control-next-icon"></span>
21-
<span class="sr-only">Next</span>
22-
</a>
14+
<template v-if="arrows">
15+
<slot name="arrows">
16+
<a class="carousel-control-prev" @click="previousItem">
17+
<span class="carousel-control-prev-icon"></span>
18+
<span class="sr-only">Previous</span>
19+
</a>
20+
<a class="carousel-control-next" @click="nextItem">
21+
<span class="carousel-control-next-icon"></span>
22+
<span class="sr-only">Next</span>
23+
</a>
24+
</slot>
2325
</template>
2426
</div>
2527
</template>
@@ -30,88 +32,79 @@ export default {
3032
props: {
3133
interval: {
3234
type: Number,
33-
default: 4000
35+
default: 6000
3436
},
35-
noAnimation: Boolean,
36-
noIndicators: Boolean,
37-
noArrows: Boolean,
37+
animate: Boolean,
38+
indicators: Boolean,
39+
arrows: Boolean,
3840
indicatorClasses: {
3941
type: [String, Array],
4042
default: 'carousel-indicators'
4143
},
44+
height: String
4245
},
4346
data () {
4447
return {
45-
active: 0,
46-
itemsLength: null,
48+
active: null,
49+
activated: null,
50+
items: [],
4751
currentInterval: null,
48-
transitioning: null
52+
transitioning: false,
53+
waitingItem: null
4954
}
5055
},
5156
mounted () {
52-
this.itemsLength = this.$children.length
53-
this.$children.forEach((item, index) => item.index = index)
54-
const activeItem = this.$children.filter(item => item.active)
55-
if (activeItem[0]) {
56-
this.active = activeItem[0].index || 0
57-
} else {
58-
this.$children[0].classes = 'active'
59-
}
60-
this.menageInterval()
57+
this.items = this.$slots.default.map(item => item.componentInstance)
58+
const activated = this.items.map((item, index) => item.active ? index :null)
59+
.filter(item => item)
60+
this.active = activated[0] || 0
61+
this.activate(activated[0] || 0)
6162
},
6263
methods: {
63-
menageInterval () {
64-
if (this.noAnimation) return
65-
66-
clearInterval(this.currentInterval)
67-
this.currentInterval = setInterval(() => {
68-
this.nextSlide()
69-
}, this.interval)
64+
resetInterval () {
65+
if (this.animate && this.interval) {
66+
clearInterval(this.currentInterval)
67+
this.currentInterval = setInterval(() => {
68+
this.nextItem()
69+
}, this.interval)
70+
}
7071
},
71-
nextSlide () {
72-
let index = this.active === this.itemsLength - 1 ? 0 : this.active + 1
73-
this.setSlide(index, 'left')
72+
nextItem () {
73+
this.setItem(this.active === this.items.length - 1 ? 0 : this.active + 1, 'next')
7474
},
75-
previousSlide () {
76-
let index = this.active === 0 ? this.itemsLength -1 : this.active - 1
77-
this.setSlide(index, 'right')
75+
previousItem () {
76+
this.setItem(this.active === 0 ? this.items.length -1 : this.active - 1, 'prev')
7877
},
79-
setSlide (index, direction = null) {
80-
if (index === this.active) {
81-
return this.menageInterval()
78+
setItem (index, passedOrder = null) {
79+
if (index === this.activated) {
80+
return this.resetInterval()
8281
}
83-
direction === null ? direction = this.active < index ? 'left' : 'right' : ''
84-
if (this.noAnimation) {
85-
this.$children[this.active].classes = ''
86-
this.$children[index].classes = 'active'
87-
this.active = index
88-
} else if (!this.transitioning) {
89-
this.slide(index, direction)
82+
const order = passedOrder || (this.active > index ? 'prev' : 'next')
83+
this.active = index
84+
if (!this.transitioning) {
85+
this.activate(index, order)
86+
} else {
87+
this.waitingItem = { index, order }
9088
}
9189
},
92-
slide (index, direction) {
93-
this.menageInterval()
94-
let oldIndex = this.active
95-
this.active = index
96-
const order = direction === 'right' ? 'prev' : 'next'
97-
const orderClass = `carousel-item-${order}`
98-
const directionClass = `carousel-item-${direction}`
99-
const activeEl = this.$children[oldIndex].$el
100-
const nextEl = this.$children[index].$el
101-
setTimeout(() =>{
102-
nextEl.classList.add(orderClass)
103-
nextEl.offsetHeight
104-
nextEl.classList.add(directionClass)
105-
activeEl.classList.add(directionClass)
106-
}, 0)
107-
108-
this.transitioning = setTimeout(() => {
109-
this.transitioning = null
110-
nextEl.classList.remove(orderClass)
111-
nextEl.classList.remove(directionClass)
112-
activeEl.classList.remove(directionClass)
113-
this.$children[oldIndex].classes = ''
114-
this.$children[index].classes = 'active'
90+
activate (index, order) {
91+
this.resetInterval()
92+
this.activated = index
93+
if (!order || this.animate) {
94+
this.items.forEach(item => item.$emit('setItem', this.items[index]))
95+
} else {
96+
this.slide(index, order)
97+
}
98+
},
99+
slide (i, order) {
100+
this.items.forEach(item => item.$emit('slideToItem', this.items[i], order))
101+
this.transitioning = true
102+
setTimeout(() => {
103+
this.transitioning = false
104+
if (this.waitingItem) {
105+
this.setItem(this.waitingItem.index, this.waitingItem.order)
106+
this.waitingItem = null
107+
}
115108
}, 600)
116109
}
117110
}
@@ -120,6 +113,9 @@ export default {
120113
</script>
121114

122115
<style scoped lang="scss">
116+
.carousel-inner, .carousel-item {
117+
height: inherit;
118+
}
123119
@import "~@coreui/coreui/scss/partials/carousel.scss";
124120
@import "~@coreui/coreui/scss/utilities/_screenreaders.scss";
125121
</style>

src/components/Carousel/CCarouselItem.vue

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
<template>
2-
<div class="carousel-item" :class="classes">
3-
<img v-if="imgSrc" :src="imgSrc" class="d-block w-100 h-100 img-fluid"/>
2+
<div :class="itemClasses">
3+
<CImage
4+
v-if="image || imgSrc"
5+
:src="imgSrc"
6+
v-bind="image"
7+
class="d-block w-100 h-100 img-fluid"
8+
/>
49
<slot>
510
<div class="carousel-caption">
611
<h3>{{caption}}</h3>
@@ -11,17 +16,58 @@
1116
</template>
1217

1318
<script>
19+
import CImage from '../Image/CImage'
1420
export default {
1521
name: 'CCarouselItem',
1622
props: {
23+
image: Object,
1724
imgSrc: String,
1825
caption: String,
1926
text: String,
20-
active: Boolean,
27+
active: Boolean
2128
},
2229
data () {
2330
return {
24-
classes: this.active ? 'active' : ''
31+
activated: false,
32+
transitioning: false,
33+
order: null
34+
}
35+
},
36+
mounted () {
37+
this.$on('setItem', this.setItem)
38+
this.$on('slideToItem', this.slideToItem)
39+
},
40+
computed: {
41+
direction () {
42+
return this.order === 'next' ? 'left' : 'right'
43+
},
44+
itemClasses () {
45+
return [
46+
'carousel-item',
47+
{
48+
[`carousel-item-${this.order}`]: this.order,
49+
[`carousel-item-${this.direction}`]: this.transitioning,
50+
'active': this.activated
51+
}
52+
]
53+
}
54+
},
55+
methods: {
56+
setItem (item) {
57+
this.activated = this._uid === item._uid
58+
},
59+
slideToItem (item, order) {
60+
if (this._uid === item._uid || this.activated) {
61+
this.order = order
62+
setTimeout(() => {
63+
this.transitioning = true
64+
}, 0)
65+
setTimeout(() => {
66+
this.transitioning = false
67+
this.order = null
68+
this.setItem(item)
69+
}, 600)
70+
}
2571
}
2672
}
2773
}

0 commit comments

Comments
 (0)