[new feature] #734 swipe组件支持垂直滚动 (#938)

This commit is contained in:
nrz 2018-04-27 22:57:44 +08:00 committed by neverland
parent fa8f88c7be
commit 21372bea96
7 changed files with 109 additions and 23 deletions

View File

@ -25,6 +25,15 @@
<van-swipe-item>4</van-swipe-item> <van-swipe-item>4</van-swipe-item>
</van-swipe> </van-swipe>
</demo-block> </demo-block>
<demo-block :title="$t('title4')">
<van-swipe :autoplay="3000" vertical>
<van-swipe-item>1</van-swipe-item>
<van-swipe-item>2</van-swipe-item>
<van-swipe-item>3</van-swipe-item>
<van-swipe-item>4</van-swipe-item>
</van-swipe>
</demo-block>
</demo-section> </demo-section>
</template> </template>
@ -34,11 +43,13 @@ export default {
'zh-CN': { 'zh-CN': {
title2: '图片懒加载', title2: '图片懒加载',
title3: '监听 change 事件', title3: '监听 change 事件',
title4: '纵向滚动',
message: '当前 Swipe 索引:' message: '当前 Swipe 索引:'
}, },
'en-US': { 'en-US': {
title2: 'Image Lazyload', title2: 'Image Lazyload',
title3: 'Change Event', title3: 'Change Event',
title4: 'Vertical Scrolling',
message: 'Current Swipe index:' message: 'Current Swipe index:'
} }
}, },
@ -68,6 +79,7 @@ export default {
.van-swipe { .van-swipe {
cursor: pointer; cursor: pointer;
height: 140px;
&-item { &-item {
color: #fff; color: #fff;

View File

@ -66,6 +66,17 @@ export default {
} }
``` ```
#### Vertical Scrolling
```html
<van-swipe :autoplay="3000" vertical>
<van-swipe-item>1</van-swipe-item>
<van-swipe-item>2</van-swipe-item>
<van-swipe-item>3</van-swipe-item>
<van-swipe-item>4</van-swipe-item>
</van-swipe>
```
### API ### API
| Attribute | Description | Type | Default | Accepted Values | | Attribute | Description | Type | Default | Accepted Values |
@ -75,6 +86,7 @@ export default {
| loop | Whether to enable loop | `Boolean` | `true` | - | | loop | Whether to enable loop | `Boolean` | `true` | - |
| show-indicators | Whether to show indocators | `Boolean` | `true` | - | | show-indicators | Whether to show indocators | `Boolean` | `true` | - |
| initial-swipe | Index of initial swipe, start from 0 | `Number` | `0` | - | | initial-swipe | Index of initial swipe, start from 0 | `Number` | `0` | - |
| vertical | Vertical Scrolling | `Boolean` | `false` | - |
### Event ### Event

View File

@ -66,6 +66,17 @@ export default {
} }
``` ```
#### 纵向滚动
```html
<van-swipe :autoplay="3000" vertical>
<van-swipe-item>1</van-swipe-item>
<van-swipe-item>2</van-swipe-item>
<van-swipe-item>3</van-swipe-item>
<van-swipe-item>4</van-swipe-item>
</van-swipe>
```
### API ### API
| 参数 | 说明 | 类型 | 默认值 | 可选值 | | 参数 | 说明 | 类型 | 默认值 | 可选值 |
@ -75,6 +86,7 @@ export default {
| loop | 是否开启循环播放 | `Boolean` | `true` | - | | loop | 是否开启循环播放 | `Boolean` | `true` | - |
| show-indicators | 是否显示指示器 | `Boolean` | `true` | - | | show-indicators | 是否显示指示器 | `Boolean` | `true` | - |
| initial-swipe | 初始位置,从 0 开始算 | `Number` | `0` | - | | initial-swipe | 初始位置,从 0 开始算 | `Number` | `0` | - |
| vertical | 纵向滚动 | `Boolean` | `false` | - |
### 事件 ### 事件

View File

@ -138,7 +138,7 @@ module.exports = {
}, },
{ {
path: '/slider', path: '/slider',
title: 'Slider - 滑块' title: 'Slider - 滑块'
}, },
{ {
path: '/stepper', path: '/stepper',

View File

@ -18,9 +18,11 @@ export default create({
computed: { computed: {
style() { style() {
const { vertical, width, height } = this.$parent;
return { return {
width: this.$parent.width + 'px', width: width + 'px',
transform: `translate(${this.offset}px, 0)` height: vertical ? height + 'px' : '100%',
transform: `translate${vertical ? 'Y' : 'X'}(${this.offset}px)`
}; };
} }
}, },

View File

@ -17,9 +17,13 @@
</div> </div>
<div <div
v-if="showIndicators && count > 1" v-if="showIndicators && count > 1"
:class="b('indicators')" :class="b(indicatorsClass)"
> >
<i v-for="index in count" :class="b('indicator', { active: index - 1 === activeIndicator })" /> <i
v-for="index in count"
:key="index"
:class="b('indicator', { active: index - 1 === activeIndicator })"
/>
</div> </div>
</div> </div>
</template> </template>
@ -35,6 +39,7 @@ export default create({
props: { props: {
autoplay: Number, autoplay: Number,
vertical: Boolean,
loop: { loop: {
type: Boolean, type: Boolean,
default: true default: true
@ -56,11 +61,13 @@ export default create({
data() { data() {
return { return {
width: 0, width: 0,
height: 0,
offset: 0, offset: 0,
startX: 0, startX: 0,
startY: 0, startY: 0,
active: 0, active: 0,
deltaX: 0, deltaX: 0,
deltaY: 0,
swipes: [], swipes: [],
direction: '', direction: '',
currentDuration: 0 currentDuration: 0
@ -97,16 +104,33 @@ export default create({
}, },
trackStyle() { trackStyle() {
return { const sizeKey = this.vertical ? 'height' : 'width';
paddingLeft: this.width + 'px',
width: (this.count + 2) * this.width + 'px', const style = {
transitionDuration: `${this.currentDuration}ms`, [this.vertical ? 'paddingTop' : 'paddingLeft']: `${this[sizeKey]}px`,
transform: `translate(${this.offset}px, 0)` [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() {
return this.vertical ? 'indicators--vertical' : 'indicators';
}, },
activeIndicator() { activeIndicator() {
return (this.active + this.count) % this.count; return (this.active + this.count) % this.count;
},
size() {
return this.vertical ? this.height : this.width;
} }
}, },
@ -114,10 +138,10 @@ export default create({
initialize() { initialize() {
// reset offset when children changes // reset offset when children changes
clearTimeout(this.timer); clearTimeout(this.timer);
this.width = this.$el.getBoundingClientRect().width; ({ width: this.width, height: this.height } = this.$el.getBoundingClientRect());
this.active = this.initialSwipe; this.active = this.initialSwipe;
this.currentDuration = 0; this.currentDuration = 0;
this.offset = this.count > 1 ? -this.width * (this.active + 1) : 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;
}); });
@ -139,25 +163,41 @@ export default create({
}, },
onTouchMove(event) { onTouchMove(event) {
const delta = this.vertical ? this.deltaY : this.deltaX;
this.touchMove(event); this.touchMove(event);
if (this.direction === 'horizontal') { if (this.vertical && this.direction === 'vertical') {
event.preventDefault();
event.stopPropagation();
} else if (this.direction === 'horizontal') {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
this.move(0, this.range(this.deltaX, [-this.width, this.width]));
} }
this.move(0, this.range(delta, [-this.size, this.size]));
this.move(0, this.range(delta, [-this.size, this.size]));
}, },
onTouchEnd() { onTouchEnd() {
if (this.deltaX) { const { deltaX, deltaY } = this;
this.move(this.offsetX > 50 ? (this.deltaX > 0 ? -1 : 1) : 0);
if (deltaX) {
this.move(this.offsetX > 50 ? (deltaX > 0 ? -1 : 1) : 0);
this.currentDuration = this.duration; 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, deltaX, width } = this; const { active, count, swipes } = this;
const delta = this.vertical ? this.deltaY : this.deltaX;
if ( if (
!this.loop && !this.loop &&
@ -171,17 +211,17 @@ 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 * width : 0; swipes[0].offset = active === count - 1 && move > 0 ? count * this.size : 0;
this.active += move; this.active += move;
} else { } else {
if (active === 0) { if (active === 0) {
swipes[count - 1].offset = deltaX > 0 ? -count * width : 0; swipes[count - 1].offset = delta > 0 ? -count * this.size : 0;
} else if (active === count - 1) { } else if (active === count - 1) {
swipes[0].offset = deltaX < 0 ? count * width : 0; swipes[0].offset = delta < 0 ? count * this.size : 0;
} }
} }
this.offset = offset - (this.active + 1) * this.width; this.offset = offset - (this.active + 1) * this.size;
}, },
autoPlay() { autoPlay() {

View File

@ -17,11 +17,19 @@ $van-swipe-indicator: 6px;
} }
&__indicators { &__indicators {
position: absolute;
left: 50%; left: 50%;
bottom: 10px; bottom: 10px;
position: absolute;
height: $van-swipe-indicator; height: $van-swipe-indicator;
transform: translate3d(-50%, 0, 0); transform: translate3d(-50%, 0, 0);
&--vertical {
position: absolute;
left: 10px;
top: 50%;
width: $van-swipe-indicator;
transform: translate3d(0, -50%, 0);
}
} }
&__indicator { &__indicator {
@ -35,7 +43,7 @@ $van-swipe-indicator: 6px;
&:not(:last-child) { &:not(:last-child) {
margin-right: $van-swipe-indicator; margin-right: $van-swipe-indicator;
} }
&--active { &--active {
background-color: $orange; background-color: $orange;
} }