diff --git a/docs/demos/views/swipe.vue b/docs/demos/views/swipe.vue index 9b5e43ea8..4de4c80e3 100644 --- a/docs/demos/views/swipe.vue +++ b/docs/demos/views/swipe.vue @@ -25,6 +25,15 @@ 4 + + + + 1 + 2 + 3 + 4 + + @@ -34,11 +43,13 @@ export default { 'zh-CN': { title2: '图片懒加载', title3: '监听 change 事件', + title4: '纵向滚动', message: '当前 Swipe 索引:' }, 'en-US': { title2: 'Image Lazyload', title3: 'Change Event', + title4: 'Vertical Scrolling', message: 'Current Swipe index:' } }, @@ -68,6 +79,7 @@ export default { .van-swipe { cursor: pointer; + height: 140px; &-item { color: #fff; diff --git a/docs/markdown/en-US/swipe.md b/docs/markdown/en-US/swipe.md index 394a182a5..2a49c2a08 100644 --- a/docs/markdown/en-US/swipe.md +++ b/docs/markdown/en-US/swipe.md @@ -66,6 +66,17 @@ export default { } ``` +#### Vertical Scrolling + +```html + + 1 + 2 + 3 + 4 + +``` + ### API | Attribute | Description | Type | Default | Accepted Values | @@ -75,6 +86,7 @@ export default { | loop | Whether to enable loop | `Boolean` | `true` | - | | show-indicators | Whether to show indocators | `Boolean` | `true` | - | | initial-swipe | Index of initial swipe, start from 0 | `Number` | `0` | - | +| vertical | Vertical Scrolling | `Boolean` | `false` | - | ### Event diff --git a/docs/markdown/zh-CN/swipe.md b/docs/markdown/zh-CN/swipe.md index 28b1a40a5..99c2ed738 100644 --- a/docs/markdown/zh-CN/swipe.md +++ b/docs/markdown/zh-CN/swipe.md @@ -66,6 +66,17 @@ export default { } ``` +#### 纵向滚动 + +```html + + 1 + 2 + 3 + 4 + +``` + ### API | 参数 | 说明 | 类型 | 默认值 | 可选值 | @@ -75,6 +86,7 @@ export default { | loop | 是否开启循环播放 | `Boolean` | `true` | - | | show-indicators | 是否显示指示器 | `Boolean` | `true` | - | | initial-swipe | 初始位置,从 0 开始算 | `Number` | `0` | - | +| vertical | 纵向滚动 | `Boolean` | `false` | - | ### 事件 diff --git a/docs/src/doc.config.js b/docs/src/doc.config.js index 3b3282a1e..4154a7e0b 100644 --- a/docs/src/doc.config.js +++ b/docs/src/doc.config.js @@ -138,7 +138,7 @@ module.exports = { }, { path: '/slider', - title: 'Slider - 滑块' + title: 'Slider - 滑块' }, { path: '/stepper', diff --git a/packages/swipe-item/index.vue b/packages/swipe-item/index.vue index c85a99c3c..764e559ce 100644 --- a/packages/swipe-item/index.vue +++ b/packages/swipe-item/index.vue @@ -18,9 +18,11 @@ export default create({ computed: { style() { + const { vertical, width, height } = this.$parent; return { - width: this.$parent.width + 'px', - transform: `translate(${this.offset}px, 0)` + width: width + 'px', + height: vertical ? height + 'px' : '100%', + transform: `translate${vertical ? 'Y' : 'X'}(${this.offset}px)` }; } }, diff --git a/packages/swipe/index.vue b/packages/swipe/index.vue index 48a37447f..d38c36330 100644 --- a/packages/swipe/index.vue +++ b/packages/swipe/index.vue @@ -17,9 +17,13 @@
- +
@@ -35,6 +39,7 @@ export default create({ props: { autoplay: Number, + vertical: Boolean, loop: { type: Boolean, default: true @@ -56,11 +61,13 @@ export default create({ data() { return { width: 0, + height: 0, offset: 0, startX: 0, startY: 0, active: 0, deltaX: 0, + deltaY: 0, swipes: [], direction: '', currentDuration: 0 @@ -97,16 +104,33 @@ export default create({ }, trackStyle() { - return { - paddingLeft: this.width + 'px', - width: (this.count + 2) * this.width + 'px', - transitionDuration: `${this.currentDuration}ms`, - transform: `translate(${this.offset}px, 0)` + const sizeKey = this.vertical ? 'height' : 'width'; + + 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() { + return this.vertical ? 'indicators--vertical' : 'indicators'; }, activeIndicator() { return (this.active + this.count) % this.count; + }, + + size() { + return this.vertical ? this.height : this.width; } }, @@ -114,10 +138,10 @@ export default create({ initialize() { // reset offset when children changes clearTimeout(this.timer); - this.width = this.$el.getBoundingClientRect().width; + ({ width: this.width, height: this.height } = this.$el.getBoundingClientRect()); this.active = this.initialSwipe; 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 => { swipe.offset = 0; }); @@ -139,25 +163,41 @@ export default create({ }, onTouchMove(event) { + const delta = this.vertical ? this.deltaY : this.deltaX; + 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.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() { - if (this.deltaX) { - this.move(this.offsetX > 50 ? (this.deltaX > 0 ? -1 : 1) : 0); + const { deltaX, deltaY } = this; + + if (deltaX) { + this.move(this.offsetX > 50 ? (deltaX > 0 ? -1 : 1) : 0); this.currentDuration = this.duration; } + + if (deltaY) { + this.move(this.offsetY > 50 ? (deltaY > 0 ? -1 : 1) : 0); + this.currentDuration = this.duration; + } + this.autoPlay(); }, 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 ( !this.loop && @@ -171,17 +211,17 @@ export default create({ if (active === -1) { 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; } else { 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) { - 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() { diff --git a/packages/vant-css/src/swipe.css b/packages/vant-css/src/swipe.css index b57830295..6d53c6853 100644 --- a/packages/vant-css/src/swipe.css +++ b/packages/vant-css/src/swipe.css @@ -17,11 +17,19 @@ $van-swipe-indicator: 6px; } &__indicators { + position: absolute; left: 50%; bottom: 10px; - position: absolute; height: $van-swipe-indicator; transform: translate3d(-50%, 0, 0); + + &--vertical { + position: absolute; + left: 10px; + top: 50%; + width: $van-swipe-indicator; + transform: translate3d(0, -50%, 0); + } } &__indicator { @@ -35,7 +43,7 @@ $van-swipe-indicator: 6px; &:not(:last-child) { margin-right: $van-swipe-indicator; } - + &--active { background-color: $orange; }