@mixd-id/web-scaffold 0.1.240411080 → 0.1.240411081
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/components/Carousel.vue +103 -172
- package/src/components/Image.vue +6 -0
package/package.json
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
:style="computedStyle">
|
|
6
6
|
|
|
7
7
|
<div ref="inner" :class="computedContainerClass">
|
|
8
|
-
|
|
8
|
+
<div v-for="item in items" :class="computedItemClass">
|
|
9
9
|
<slot v-if="$slots['default']" :item="item"></slot>
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
<component v-else :is="item.type" :="item" />
|
|
11
|
+
</div>
|
|
12
12
|
</div>
|
|
13
13
|
|
|
14
14
|
<div v-if="useNextPrev && (items ?? []).length > 1 && index < items.length - 1" :class="$style.carouselNext" @click="next(true)">
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
</slot>
|
|
22
22
|
</div>
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
<div v-if="useNextPrev && (items ?? []).length > 1 && index > 0" :class="$style.carouselPrev" @click="prev">
|
|
25
25
|
<slot name="prev">
|
|
26
26
|
<div class="p-3">
|
|
27
27
|
<button :class="$style.btn">
|
|
@@ -50,22 +50,22 @@ import {componentMixin} from "../mixin/component";
|
|
|
50
50
|
|
|
51
51
|
export default{
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
mixins: [ componentMixin ],
|
|
54
54
|
|
|
55
55
|
props:{
|
|
56
56
|
|
|
57
57
|
items: Array,
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
infinite: {
|
|
60
|
+
type: undefined,
|
|
61
|
+
default: false
|
|
62
|
+
},
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
ratio: Array,
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
autoPlay: [ Number, String ],
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
useLegend: [ Boolean, Number ],
|
|
69
69
|
|
|
70
70
|
useNextPrev: [ Boolean, Number ],
|
|
71
71
|
|
|
@@ -73,68 +73,56 @@ export default{
|
|
|
73
73
|
|
|
74
74
|
emits: [ 'change' ],
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
computed: {
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
78
|
+
computedContainerClass(){
|
|
79
|
+
return [
|
|
80
|
+
this.$style.inner,
|
|
81
|
+
this.containerClass
|
|
82
|
+
]
|
|
83
|
+
.filter(_ => _)
|
|
84
|
+
.join(' ')
|
|
85
|
+
},
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
87
|
+
computedItemClass(){
|
|
88
|
+
return [
|
|
89
|
+
this.$style.item,
|
|
90
|
+
this.itemClass
|
|
91
|
+
]
|
|
92
|
+
.filter(_ => _)
|
|
93
|
+
.join(' ')
|
|
94
|
+
}
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
},
|
|
97
97
|
|
|
98
98
|
data(){
|
|
99
99
|
return {
|
|
100
100
|
index: 0,
|
|
101
|
-
|
|
101
|
+
timeoutId: null,
|
|
102
102
|
scrollPosition: null,
|
|
103
103
|
swiping: false,
|
|
104
|
-
|
|
105
|
-
// physics state
|
|
106
|
-
_rafId: null,
|
|
107
|
-
_anim: null,
|
|
108
|
-
_currentX: 0,
|
|
109
104
|
}
|
|
110
105
|
},
|
|
111
106
|
|
|
112
107
|
mounted(){
|
|
113
108
|
window.addEventListener('touchmove', this.onTouchMove, { passive: false });
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
// initialize transform position
|
|
118
|
-
window.requestAnimationFrame(() => {
|
|
119
|
-
this._currentX = this._getCurrentX()
|
|
120
|
-
this._applyX(this._currentX)
|
|
121
|
-
})
|
|
109
|
+
if(this.autoPlay > 0)
|
|
110
|
+
this.play()
|
|
122
111
|
},
|
|
123
112
|
|
|
124
113
|
unmounted() {
|
|
125
114
|
window.removeEventListener('touchmove', this.onTouchMove, { passive: false });
|
|
126
|
-
this._stopRaf()
|
|
127
115
|
},
|
|
128
116
|
|
|
129
117
|
watch:{
|
|
130
118
|
|
|
131
|
-
|
|
119
|
+
index(to){
|
|
132
120
|
this.$emit('change', to)
|
|
133
121
|
},
|
|
134
122
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
123
|
+
items(){
|
|
124
|
+
this.index = 0
|
|
125
|
+
},
|
|
138
126
|
|
|
139
127
|
},
|
|
140
128
|
|
|
@@ -148,31 +136,10 @@ export default{
|
|
|
148
136
|
}
|
|
149
137
|
},
|
|
150
138
|
|
|
151
|
-
|
|
152
|
-
if(this.
|
|
153
|
-
cancelAnimationFrame(this._rafId)
|
|
154
|
-
this._rafId = null
|
|
155
|
-
}
|
|
156
|
-
this._anim = null
|
|
157
|
-
},
|
|
158
|
-
|
|
159
|
-
_applyX(x){
|
|
160
|
-
this._currentX = x
|
|
161
|
-
if(this.$el?.firstElementChild)
|
|
162
|
-
this.$el.firstElementChild.style.transform = `translate3d(${x}px, 0, 0)`
|
|
163
|
-
},
|
|
164
|
-
|
|
165
|
-
_getCurrentX(){
|
|
166
|
-
const t = this.$el?.firstElementChild?.style?.transform || ''
|
|
167
|
-
const matches = t.match(/translate3d\((.*?)(?=\,)/)
|
|
168
|
-
return matches != null && typeof matches[1] !== 'undefined'
|
|
169
|
-
? parseFloat(matches[1].replace('px', ''))
|
|
170
|
-
: 0
|
|
171
|
-
},
|
|
172
|
-
|
|
173
|
-
_getTargetXForIndex(index){
|
|
174
|
-
if(!this.$refs.inner) return 0
|
|
139
|
+
setPosition(noAnimation) {
|
|
140
|
+
if(!this.$refs.inner) return
|
|
175
141
|
|
|
142
|
+
const index = this.index
|
|
176
143
|
let left = 0
|
|
177
144
|
const gapPx = parseInt(window.getComputedStyle(this.$refs.inner).getPropertyValue('column-gap'))
|
|
178
145
|
for(let curIndex = 0 ; curIndex < this.items.length ; curIndex++){
|
|
@@ -181,68 +148,20 @@ export default{
|
|
|
181
148
|
left += (item.clientWidth + (!isNaN(gapPx) ? gapPx : 0))
|
|
182
149
|
}
|
|
183
150
|
|
|
184
|
-
|
|
185
|
-
},
|
|
186
|
-
|
|
187
|
-
_rubberBand(distance, dimension, constant = 0.55){
|
|
188
|
-
// similar to iOS rubber-banding
|
|
189
|
-
const abs = Math.abs(distance)
|
|
190
|
-
const result = (dimension * constant * abs) / (dimension + constant * abs)
|
|
191
|
-
return Math.sign(distance) * result
|
|
192
|
-
},
|
|
193
|
-
|
|
194
|
-
_springTo(targetX, { stiffness = 0.09, damping = 0.78, maxDuration = 900 } = {}){
|
|
195
|
-
this._stopRaf()
|
|
196
|
-
|
|
197
|
-
const startTime = performance.now()
|
|
198
|
-
let x = this._getCurrentX()
|
|
199
|
-
let v = 0
|
|
200
|
-
|
|
201
|
-
const step = (now) => {
|
|
202
|
-
const dtMs = now - (this._anim?.t || now)
|
|
203
|
-
const dt = Math.min(0.032, Math.max(0.008, dtMs / 1000))
|
|
204
|
-
this._anim = { t: now }
|
|
205
|
-
|
|
206
|
-
// spring force
|
|
207
|
-
const F = (targetX - x) * stiffness
|
|
208
|
-
v = (v + F) * damping
|
|
209
|
-
x = x + v / dt
|
|
210
|
-
|
|
211
|
-
// numerical safety
|
|
212
|
-
if(!isFinite(x)) x = targetX
|
|
213
|
-
|
|
214
|
-
this._applyX(x)
|
|
151
|
+
left *= -1
|
|
215
152
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
this._stopRaf()
|
|
222
|
-
return
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
this._rafId = requestAnimationFrame(step)
|
|
153
|
+
if(!noAnimation){
|
|
154
|
+
this.$el.firstElementChild.addEventListener('transitionend', function(){
|
|
155
|
+
this.classList.remove('transition-carousel')
|
|
156
|
+
})
|
|
157
|
+
this.$el.firstElementChild.classList.add('transition-carousel')
|
|
226
158
|
}
|
|
227
159
|
|
|
228
|
-
|
|
160
|
+
window.requestAnimationFrame(() => {
|
|
161
|
+
this.$el.firstElementChild.style.transform = `translate3d(${left}px, 0, 0)`
|
|
162
|
+
})
|
|
229
163
|
},
|
|
230
164
|
|
|
231
|
-
setPosition(noAnimation) {
|
|
232
|
-
if(!this.$refs.inner) return
|
|
233
|
-
|
|
234
|
-
const left = this._getTargetXForIndex(this.index)
|
|
235
|
-
|
|
236
|
-
if(noAnimation){
|
|
237
|
-
this._stopRaf()
|
|
238
|
-
window.requestAnimationFrame(() => this._applyX(left))
|
|
239
|
-
return
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// spring settle
|
|
243
|
-
this._springTo(left)
|
|
244
|
-
},
|
|
245
|
-
|
|
246
165
|
setIndex(index){
|
|
247
166
|
if(index >= 0 && index < this.items.length){
|
|
248
167
|
this.index = index
|
|
@@ -257,25 +176,30 @@ export default{
|
|
|
257
176
|
index = useBack === true ? 0 : this.items.length - 1
|
|
258
177
|
|
|
259
178
|
this.index = index
|
|
179
|
+
|
|
260
180
|
this.setPosition()
|
|
261
181
|
},
|
|
262
182
|
|
|
263
183
|
prev(){
|
|
184
|
+
|
|
264
185
|
let index = this.index - 1;
|
|
186
|
+
|
|
265
187
|
if(index < 0) index = 0
|
|
188
|
+
|
|
266
189
|
this.index = index
|
|
190
|
+
|
|
267
191
|
this.setPosition()
|
|
268
192
|
},
|
|
269
193
|
|
|
270
|
-
|
|
194
|
+
play(){
|
|
271
195
|
if(this.autoPlay > 0)
|
|
272
|
-
|
|
273
|
-
|
|
196
|
+
this.timeoutId = window.setTimeout(() => { this.next(true); this.play() }, this.autoPlay)
|
|
197
|
+
},
|
|
274
198
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
199
|
+
stop(){
|
|
200
|
+
if(this.timeoutId)
|
|
201
|
+
window.clearTimeout(this.timeoutId)
|
|
202
|
+
},
|
|
279
203
|
|
|
280
204
|
mouseMove(e){
|
|
281
205
|
const sx = typeof e.touches !== 'undefined' ? e.touches[0].clientX : e.clientX
|
|
@@ -293,20 +217,16 @@ export default{
|
|
|
293
217
|
}
|
|
294
218
|
}
|
|
295
219
|
else if(this._props['direction'] === 'horizontal'){
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
if(overscrolling){
|
|
304
|
-
const dim = this.$el?.clientWidth || 1
|
|
305
|
-
nextX = baseX + this._rubberBand(dx, dim)
|
|
220
|
+
let ix
|
|
221
|
+
if((this.index === this.items.length - 1 && dx < 0) ||
|
|
222
|
+
(this.index === 0 && dx > 0)){
|
|
223
|
+
ix = parseInt(this._props['ix'] + (dx * .19812))
|
|
224
|
+
}
|
|
225
|
+
else{
|
|
226
|
+
ix = parseInt(this._props['ix'] + dx)
|
|
306
227
|
}
|
|
307
228
|
|
|
308
|
-
this.
|
|
309
|
-
this._applyX(nextX)
|
|
229
|
+
this.$el.firstElementChild.style.transform = `translate3d(${ix}px, 0, 0)`
|
|
310
230
|
}
|
|
311
231
|
|
|
312
232
|
},
|
|
@@ -338,19 +258,18 @@ export default{
|
|
|
338
258
|
window.removeEventListener('touchmove', this.mouseMove)
|
|
339
259
|
window.removeEventListener('touchend', this.mouseUp)
|
|
340
260
|
|
|
341
|
-
|
|
342
|
-
|
|
261
|
+
if(this.autoPlay > 0)
|
|
262
|
+
this.play()
|
|
343
263
|
},
|
|
344
264
|
|
|
345
265
|
mouseDown(e){
|
|
346
|
-
|
|
347
|
-
|
|
266
|
+
if(!this.items || this.items.length <= 1)
|
|
267
|
+
return
|
|
348
268
|
|
|
349
|
-
|
|
269
|
+
this.stop()
|
|
350
270
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
const ix = this._getCurrentX()
|
|
271
|
+
var matches = this.$el.firstElementChild.style.transform.match(/translate3d\((.*?)(?=\,)/)
|
|
272
|
+
var ix = matches != null && typeof matches[1] != 'undefined' ? parseInt(matches[1].replace('px', '')) : 0
|
|
354
273
|
|
|
355
274
|
this._props = {
|
|
356
275
|
sx:typeof e.touches !== 'undefined' ? e.touches[0].clientX : e.clientX,
|
|
@@ -373,17 +292,29 @@ export default{
|
|
|
373
292
|
|
|
374
293
|
<style>
|
|
375
294
|
|
|
376
|
-
|
|
295
|
+
.carousel-next,
|
|
296
|
+
.carousel-prev{
|
|
297
|
+
position: absolute;
|
|
298
|
+
top: 50%;
|
|
299
|
+
transform: translate3d(0, -50%, 0);
|
|
300
|
+
}
|
|
301
|
+
.carousel-next{
|
|
302
|
+
right: 10px;
|
|
303
|
+
}
|
|
304
|
+
.carousel-prev{
|
|
305
|
+
left: 10px;
|
|
306
|
+
}
|
|
307
|
+
|
|
377
308
|
.transition-carousel{
|
|
378
|
-
transition:
|
|
309
|
+
transition: all 300ms cubic-bezier(0.25, 1, 0.5, 1);
|
|
379
310
|
}
|
|
380
311
|
</style>
|
|
381
312
|
|
|
382
313
|
<style module>
|
|
383
314
|
|
|
384
315
|
.comp{
|
|
385
|
-
|
|
386
|
-
|
|
316
|
+
overflow: hidden;
|
|
317
|
+
position: relative;
|
|
387
318
|
@apply flex flex-col;
|
|
388
319
|
}
|
|
389
320
|
|
|
@@ -392,34 +323,34 @@ export default{
|
|
|
392
323
|
}
|
|
393
324
|
|
|
394
325
|
.carouselNext{
|
|
395
|
-
|
|
326
|
+
@apply absolute top-0 bottom-0 right-0 flex items-center justify-center;
|
|
396
327
|
}
|
|
397
328
|
|
|
398
329
|
.carouselPrev{
|
|
399
|
-
|
|
330
|
+
@apply absolute top-0 bottom-0 left-0 flex items-center justify-center;
|
|
400
331
|
}
|
|
401
332
|
|
|
402
333
|
.inner{
|
|
403
|
-
|
|
404
|
-
|
|
334
|
+
will-change: transform;
|
|
335
|
+
@apply flex flex-row items-stretch;
|
|
405
336
|
}
|
|
406
337
|
.inner>*{
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
338
|
+
display: inline-block;
|
|
339
|
+
width: 100%;
|
|
340
|
+
min-width: 100%;
|
|
341
|
+
vertical-align: top;
|
|
411
342
|
}
|
|
412
343
|
|
|
413
344
|
.legend{
|
|
414
|
-
|
|
345
|
+
@apply flex justify-center gap-2 py-1;
|
|
415
346
|
}
|
|
416
347
|
.legend .legendItem{
|
|
417
348
|
}
|
|
418
349
|
.legend .legendItem>*{
|
|
419
|
-
|
|
350
|
+
@apply w-2 h-2 rounded-full bg-gray-100;
|
|
420
351
|
}
|
|
421
352
|
.legend .legendItemActive>*{
|
|
422
|
-
|
|
353
|
+
@apply bg-primary-500;
|
|
423
354
|
}
|
|
424
355
|
|
|
425
356
|
.btn{
|
package/src/components/Image.vue
CHANGED
|
@@ -107,6 +107,7 @@ export default{
|
|
|
107
107
|
moved: false,
|
|
108
108
|
isVisible: false,
|
|
109
109
|
actualSrc: null,
|
|
110
|
+
lastSrc: null
|
|
110
111
|
}
|
|
111
112
|
},
|
|
112
113
|
|
|
@@ -163,6 +164,8 @@ export default{
|
|
|
163
164
|
if(!this.isVisible) return
|
|
164
165
|
|
|
165
166
|
const setSrc = (src) => {
|
|
167
|
+
if(this.lastSrc && src === this.lastSrc) return
|
|
168
|
+
|
|
166
169
|
let reader
|
|
167
170
|
|
|
168
171
|
if(typeof src === 'string') {
|
|
@@ -173,6 +176,7 @@ export default{
|
|
|
173
176
|
|
|
174
177
|
this.actualSrc = src
|
|
175
178
|
this.status = 2
|
|
179
|
+
this.lastSrc = src
|
|
176
180
|
}
|
|
177
181
|
|
|
178
182
|
else if(src instanceof File){
|
|
@@ -181,11 +185,13 @@ export default{
|
|
|
181
185
|
reader.addEventListener('load', () => {
|
|
182
186
|
this.status = 2
|
|
183
187
|
this.actualSrc = reader.result
|
|
188
|
+
this.lastSrc = src
|
|
184
189
|
}, false)
|
|
185
190
|
|
|
186
191
|
reader.addEventListener('error', () => {
|
|
187
192
|
this.status = 3
|
|
188
193
|
this.actualSrc = this.defaultSrc
|
|
194
|
+
this.lastSrc = src
|
|
189
195
|
})
|
|
190
196
|
|
|
191
197
|
reader.readAsDataURL(src)
|