[Improvement] Swipe: optimzie performance (#985)

This commit is contained in:
neverland 2018-05-04 15:21:24 +08:00 committed by GitHub
parent 997780f2f5
commit 2899a4cb8e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 83 additions and 96 deletions

View File

@ -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>

View File

@ -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' : '';
} }
} }
}
}; };

View File

@ -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]);
} }
} }
}); });

View File

@ -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;