mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
[Improvement] Swipe: optimzie performance (#985)
This commit is contained in:
parent
997780f2f5
commit
2899a4cb8e
@ -27,7 +27,7 @@
|
|||||||
</demo-block>
|
</demo-block>
|
||||||
|
|
||||||
<demo-block :title="$t('title4')">
|
<demo-block :title="$t('title4')">
|
||||||
<van-swipe :autoplay="3000" vertical>
|
<van-swipe :autoplay="3000" vertical class="demo-swipe--vertical">
|
||||||
<van-swipe-item>1</van-swipe-item>
|
<van-swipe-item>1</van-swipe-item>
|
||||||
<van-swipe-item>2</van-swipe-item>
|
<van-swipe-item>2</van-swipe-item>
|
||||||
<van-swipe-item>3</van-swipe-item>
|
<van-swipe-item>3</van-swipe-item>
|
||||||
@ -79,11 +79,9 @@ export default {
|
|||||||
|
|
||||||
.van-swipe {
|
.van-swipe {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
height: 140px;
|
|
||||||
|
|
||||||
&-item {
|
&-item {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
min-height: 140px;
|
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 150px;
|
line-height: 150px;
|
||||||
@ -107,5 +105,13 @@ export default {
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--vertical {
|
||||||
|
height: 200px;
|
||||||
|
|
||||||
|
.van-swipe-item {
|
||||||
|
line-height: 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -16,10 +16,7 @@ export default {
|
|||||||
this.deltaY = touch.clientY - this.startY;
|
this.deltaY = touch.clientY - this.startY;
|
||||||
this.offsetX = Math.abs(this.deltaX);
|
this.offsetX = Math.abs(this.deltaX);
|
||||||
this.offsetY = Math.abs(this.deltaY);
|
this.offsetY = Math.abs(this.deltaY);
|
||||||
|
|
||||||
if (!this.direction) {
|
|
||||||
this.direction = this.offsetX > this.offsetY ? 'horizontal' : this.offsetX < this.offsetY ? 'vertical' : '';
|
this.direction = this.offsetX > this.offsetY ? 'horizontal' : this.offsetX < this.offsetY ? 'vertical' : '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
@ -17,11 +17,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="showIndicators && count > 1"
|
v-if="showIndicators && count > 1"
|
||||||
:class="b(indicatorsClass)"
|
:class="b('indicators', { vertical })"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
v-for="index in count"
|
v-for="index in count"
|
||||||
:key="index"
|
|
||||||
:class="b('indicator', { active: index - 1 === activeIndicator })"
|
:class="b('indicator', { active: index - 1 === activeIndicator })"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -67,14 +66,11 @@ export default create({
|
|||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
startX: 0,
|
|
||||||
startY: 0,
|
|
||||||
active: 0,
|
active: 0,
|
||||||
deltaX: 0,
|
deltaX: 0,
|
||||||
deltaY: 0,
|
deltaY: 0,
|
||||||
swipes: [],
|
swipes: [],
|
||||||
direction: '',
|
swiping: false
|
||||||
currentDuration: 0
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -83,7 +79,7 @@ export default create({
|
|||||||
},
|
},
|
||||||
|
|
||||||
destroyed() {
|
destroyed() {
|
||||||
clearTimeout(this.timer);
|
this.clear();
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
@ -97,7 +93,7 @@ export default create({
|
|||||||
|
|
||||||
autoplay(autoplay) {
|
autoplay(autoplay) {
|
||||||
if (!autoplay) {
|
if (!autoplay) {
|
||||||
clearTimeout(this.timer);
|
this.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -107,45 +103,41 @@ export default create({
|
|||||||
return this.swipes.length;
|
return this.swipes.length;
|
||||||
},
|
},
|
||||||
|
|
||||||
trackStyle() {
|
delta() {
|
||||||
const sizeKey = this.vertical ? 'height' : 'width';
|
return this.vertical ? this.deltaY : this.deltaX;
|
||||||
|
|
||||||
const style = {
|
|
||||||
[this.vertical ? 'paddingTop' : 'paddingLeft']: `${this[sizeKey]}px`,
|
|
||||||
[sizeKey]: `${(this.count + 2) * this[sizeKey]}px`,
|
|
||||||
transitionDuration: `${this.currentDuration}ms`
|
|
||||||
};
|
|
||||||
|
|
||||||
if (this.vertical) {
|
|
||||||
style.transform = `translate(0, ${this.offset}px)`;
|
|
||||||
} else {
|
|
||||||
style.transform = `translate(${this.offset}px, 0)`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return style;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
indicatorsClass() {
|
size() {
|
||||||
return this.vertical ? 'indicators--vertical' : 'indicators';
|
return this[this.vertical ? 'height' : 'width'];
|
||||||
|
},
|
||||||
|
|
||||||
|
trackSize() {
|
||||||
|
return this.count * this.size;
|
||||||
},
|
},
|
||||||
|
|
||||||
activeIndicator() {
|
activeIndicator() {
|
||||||
return (this.active + this.count) % this.count;
|
return (this.active + this.count) % this.count;
|
||||||
},
|
},
|
||||||
|
|
||||||
size() {
|
trackStyle() {
|
||||||
return this.vertical ? this.height : this.width;
|
return {
|
||||||
|
[this.vertical ? 'height' : 'width']: `${this.trackSize}px`,
|
||||||
|
transitionDuration: `${this.swiping ? 0 : this.duration}ms`,
|
||||||
|
transform: `translate${this.vertical ? 'Y' : 'X'}(${this.offset}px)`
|
||||||
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
// initialize swipe position
|
||||||
initialize() {
|
initialize() {
|
||||||
// reset offset when children changes
|
|
||||||
clearTimeout(this.timer);
|
clearTimeout(this.timer);
|
||||||
({ width: this.width, height: this.height } = this.$el.getBoundingClientRect());
|
const rect = this.$el.getBoundingClientRect();
|
||||||
|
this.swiping = true;
|
||||||
|
this.width = rect.width;
|
||||||
|
this.height = rect.height;
|
||||||
this.active = this.initialSwipe;
|
this.active = this.initialSwipe;
|
||||||
this.currentDuration = 0;
|
this.offset = this.count > 1 ? -this.size * this.active : 0;
|
||||||
this.offset = this.count > 1 ? -this.size * (this.active + 1) : 0;
|
|
||||||
this.swipes.forEach(swipe => {
|
this.swipes.forEach(swipe => {
|
||||||
swipe.offset = 0;
|
swipe.offset = 0;
|
||||||
});
|
});
|
||||||
@ -155,64 +147,49 @@ export default create({
|
|||||||
onTouchStart(event) {
|
onTouchStart(event) {
|
||||||
if (!this.touchable) return;
|
if (!this.touchable) return;
|
||||||
|
|
||||||
clearTimeout(this.timer);
|
this.clear();
|
||||||
|
this.swiping = true;
|
||||||
this.currentDuration = 0;
|
|
||||||
this.touchStart(event);
|
this.touchStart(event);
|
||||||
|
this.correctPosition();
|
||||||
if (this.active <= -1) {
|
|
||||||
this.move(this.count);
|
|
||||||
}
|
|
||||||
if (this.active >= this.count) {
|
|
||||||
this.move(-this.count);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onTouchMove(event) {
|
onTouchMove(event) {
|
||||||
if (!this.touchable) return;
|
if (!this.touchable) return;
|
||||||
|
|
||||||
const delta = this.vertical ? this.deltaY : this.deltaX;
|
|
||||||
|
|
||||||
this.touchMove(event);
|
this.touchMove(event);
|
||||||
|
|
||||||
if (this.vertical && this.direction === 'vertical') {
|
if (
|
||||||
event.preventDefault();
|
(this.vertical && this.direction === 'vertical') ||
|
||||||
event.stopPropagation();
|
this.direction === 'horizontal'
|
||||||
} else if (this.direction === 'horizontal') {
|
) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.move(0, this.range(delta, [-this.size, this.size]));
|
this.move(0, Math.min(Math.max(this.delta, -this.size), this.size));
|
||||||
this.move(0, this.range(delta, [-this.size, this.size]));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onTouchEnd() {
|
onTouchEnd() {
|
||||||
if (!this.touchable) return;
|
if (!this.touchable) return;
|
||||||
|
|
||||||
const { deltaX, deltaY } = this;
|
if (this.delta) {
|
||||||
|
const offset = this.vertical ? this.offsetY : this.offsetX;
|
||||||
if (deltaX) {
|
this.move(offset > 50 ? (this.delta > 0 ? -1 : 1) : 0);
|
||||||
this.move(this.offsetX > 50 ? (deltaX > 0 ? -1 : 1) : 0);
|
this.swiping = false;
|
||||||
this.currentDuration = this.duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deltaY) {
|
|
||||||
this.move(this.offsetY > 50 ? (deltaY > 0 ? -1 : 1) : 0);
|
|
||||||
this.currentDuration = this.duration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.autoPlay();
|
this.autoPlay();
|
||||||
},
|
},
|
||||||
|
|
||||||
move(move = 0, offset = 0) {
|
move(move = 0, offset = 0) {
|
||||||
const { active, count, swipes } = this;
|
const { delta, active, count, swipes, trackSize } = this;
|
||||||
const delta = this.vertical ? this.deltaY : this.deltaX;
|
const atFirst = active === 0;
|
||||||
|
const atLast = active === count - 1;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!this.loop &&
|
!this.loop &&
|
||||||
((active === 0 && (offset > 0 || move < 0)) ||
|
((atFirst && (offset > 0 || move < 0)) ||
|
||||||
(active === count - 1 && (offset < 0 || move > 0)))
|
(atLast && (offset < 0 || move > 0)))
|
||||||
) {
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -221,41 +198,47 @@ export default create({
|
|||||||
if (active === -1) {
|
if (active === -1) {
|
||||||
swipes[count - 1].offset = 0;
|
swipes[count - 1].offset = 0;
|
||||||
}
|
}
|
||||||
swipes[0].offset = active === count - 1 && move > 0 ? count * this.size : 0;
|
swipes[0].offset = atLast && move > 0 ? trackSize : 0;
|
||||||
|
|
||||||
this.active += move;
|
this.active += move;
|
||||||
} else {
|
} else {
|
||||||
if (active === 0) {
|
if (atFirst) {
|
||||||
swipes[count - 1].offset = delta > 0 ? -count * this.size : 0;
|
swipes[count - 1].offset = delta > 0 ? -trackSize : 0;
|
||||||
} else if (active === count - 1) {
|
} else if (atLast) {
|
||||||
swipes[0].offset = delta < 0 ? count * this.size : 0;
|
swipes[0].offset = delta < 0 ? trackSize : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.offset = offset - (this.active + 1) * this.size;
|
this.offset = offset - this.active * this.size;
|
||||||
|
},
|
||||||
|
|
||||||
|
correctPosition() {
|
||||||
|
if (this.active <= -1) {
|
||||||
|
this.move(this.count);
|
||||||
|
}
|
||||||
|
if (this.active >= this.count) {
|
||||||
|
this.move(-this.count);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
clearTimeout(this.timer);
|
||||||
},
|
},
|
||||||
|
|
||||||
autoPlay() {
|
autoPlay() {
|
||||||
const { autoplay } = this;
|
const { autoplay } = this;
|
||||||
if (autoplay && this.count > 1) {
|
if (autoplay && this.count > 1) {
|
||||||
clearTimeout(this.timer);
|
this.clear();
|
||||||
this.timer = setTimeout(() => {
|
this.timer = setTimeout(() => {
|
||||||
this.currentDuration = 0;
|
this.swiping = true;
|
||||||
|
this.correctPosition();
|
||||||
if (this.active >= this.count) {
|
|
||||||
this.move(-this.count);
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.currentDuration = this.duration;
|
this.swiping = false;
|
||||||
this.move(1);
|
this.move(1);
|
||||||
this.autoPlay();
|
this.autoPlay();
|
||||||
}, 30);
|
}, 30);
|
||||||
}, autoplay);
|
}, autoplay);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
range(num, arr) {
|
|
||||||
return Math.min(Math.max(num, arr[0]), arr[1]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -13,29 +13,30 @@ $van-swipe-indicator: 6px;
|
|||||||
|
|
||||||
&__track {
|
&__track {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__indicators {
|
&__indicators {
|
||||||
|
display: flex;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
bottom: 10px;
|
bottom: 10px;
|
||||||
height: $van-swipe-indicator;
|
transform: translateX(-50%);
|
||||||
transform: translate3d(-50%, 0, 0);
|
|
||||||
|
|
||||||
&--vertical {
|
&--vertical {
|
||||||
position: absolute;
|
|
||||||
left: 10px;
|
left: 10px;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
width: $van-swipe-indicator;
|
bottom: auto;
|
||||||
transform: translate3d(0, -50%, 0);
|
flex-direction: column;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
|
||||||
|
.van-swipe__indicator:not(:last-child) {
|
||||||
|
margin-bottom: $van-swipe-indicator;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__indicator {
|
&__indicator {
|
||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
vertical-align: top;
|
|
||||||
display: inline-block;
|
|
||||||
background-color: $gray-dark;
|
background-color: $gray-dark;
|
||||||
width: $van-swipe-indicator;
|
width: $van-swipe-indicator;
|
||||||
height: $van-swipe-indicator;
|
height: $van-swipe-indicator;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user