[breaking change] reconstruct Swipe component (#194)

* Swipe: reconstruct

* [bugfix]: Swipe autoplay

[bugfix] AddressEdit doc link
This commit is contained in:
neverland 2017-10-12 06:22:12 -05:00 committed by GitHub
parent 77f6a798e4
commit 560ccfdec2
12 changed files with 242 additions and 681 deletions

View File

@ -139,4 +139,4 @@ export default {
| address | 详细地址 | `String` |
#### 省市县列表数据格式
请参考 [Area](/zanui/vue/component/area) 组件。
请参考 [Area](#/zh-CN/component/area) 组件。

View File

@ -1,10 +1,34 @@
<style>
.demo-swipe {
padding-bottom: 30px;
.van-swipe {
height: 200px;
cursor: pointer;
&-item {
color: #fff;
min-height: 140px;
font-size: 20px;
text-align: center;
line-height: 150px;
&:nth-child(even) {
background-color: #39a9ed;
}
&:nth-child(odd) {
background-color: #66c6f2;
}
}
img {
width: 100%;
height: 240px;
display: block;
padding: 30px 60px;
box-sizing: border-box;
background-color: #fff;
pointer-events: none;
}
}
}
@ -14,21 +38,13 @@
export default {
data() {
return {
autoImages: [
'https://img.yzcdn.cn/upload_files/2017/03/09/FvkZahKoq1vkxLQFdVWeLf2UCqDz.png',
'https://img.yzcdn.cn/upload_files/2017/03/09/Fk0rpe_svu9d5Xk3MUCWd1QeMXOu.png'
],
images: [
'https://img.yzcdn.cn/upload_files/2017/03/14/FmTPs0SeyQaAOSK1rRe1sL8RcwSY.jpeg',
'https://img.yzcdn.cn/upload_files/2017/03/15/FvexrWlG_WxtCE9Omo5l27n_mAG_.jpeg'
'https://img.yzcdn.cn/public_files/2017/09/05/3bd347e44233a868c99cf0fe560232be.jpg',
'https://img.yzcdn.cn/public_files/2017/09/05/c0dab461920687911536621b345a0bc9.jpg',
'https://img.yzcdn.cn/public_files/2017/09/05/4e3ea0898b1c2c416eec8c11c5360833.jpg',
'https://img.yzcdn.cn/public_files/2017/09/05/fd08f07665ed67d50e11b32a21ce0682.jpg'
]
};
},
methods: {
handlePageEnd(page, index) {
console.log(page, index);
}
}
};
</script>
@ -46,14 +62,27 @@ Vue.component(SwipeItem.name, SwipeItem);
### 代码演示
#### 基础用法
通过`autoplay`属性设置自动轮播间隔
:::demo 基础用法
```html
<van-swipe :autoplay="3000">
<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>
```
:::
#### 图片懒加载
配合 [Lazyload](#/zh-CN/component/lazyload) 组件实现图片懒加载
:::demo 图片懒加载
```html
<van-swipe>
<van-swipe-item v-for="(img, index) in images" :key="index">
<a href="https://youzan.com" target="_blank">
<img v-lazy="img" alt="">
</a>
<van-swipe-item v-for="(image, index) in images" :key="index">
<img v-lazy="image" />
</van-swipe-item>
</van-swipe>
```
@ -63,84 +92,25 @@ export default {
data() {
return {
images: [
'https://img.yzcdn.cn/upload_files/2017/03/14/FmTPs0SeyQaAOSK1rRe1sL8RcwSY.jpeg',
'https://img.yzcdn.cn/upload_files/2017/03/15/FvexrWlG_WxtCE9Omo5l27n_mAG_.jpeg'
'https://img.yzcdn.cn/1.jpg',
'https://img.yzcdn.cn/2.jpg'
]
};
}
};
```
:::
#### 隐藏指示器
需要设置`show-indicators`属性为`false`,即会隐藏指示器。
:::demo 隐藏指示器
```html
<van-swipe :show-indicators="false">
<van-swipe-item v-for="(img, index) in autoImages" :key="index">
<img v-lazy="img" alt="">
</van-swipe-item>
</van-swipe>
```
```javascript
export default {
data() {
return {
autoImages: [
'https://img.yzcdn.cn/upload_files/2017/03/09/FvkZahKoq1vkxLQFdVWeLf2UCqDz.png',
'https://img.yzcdn.cn/upload_files/2017/03/09/Fk0rpe_svu9d5Xk3MUCWd1QeMXOu.png'
]
};
}
};
```
:::
#### 自动轮播
需要设置`auto-play`属性为`true`,即会自动轮播。
:::demo 自动轮播
```html
<van-swipe auto-play @pagechange:end="handlePageEnd">
<van-swipe-item v-for="(img, index) in autoImages" :key="index">
<img v-lazy="img" alt="">
</van-swipe-item>
</van-swipe>
```
```javascript
export default {
data() {
return {
autoImages: [
'https://img.yzcdn.cn/upload_files/2017/03/09/FvkZahKoq1vkxLQFdVWeLf2UCqDz.png',
'https://img.yzcdn.cn/upload_files/2017/03/09/Fk0rpe_svu9d5Xk3MUCWd1QeMXOu.png'
]
};
},
methods: {
handlePageEnd(page, index) {
console.log(page, index);
}
}
};
}
```
:::
### API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| autoPlay | 是否自动轮播 | `Boolean` | `false` | `true`, `false` |
| showIndicators | 是否显示指示器 | `Boolean` | `true` | `true`, `false` |
| autoplay | 自动轮播间隔,单位为 ms | `Number` | - | - |
| duration | 动画时长,单位为 ms | `Number` | `500` | - |
| showIndicators | 是否显示指示器 | `Boolean` | `true` | - |
### 事件
| 事件名 | 说明 | 参数 |
| 事件名 | 说明 | 参数 |
|-----------|-----------|-----------|
| `pagechange:end` | 每一页轮播结束后触发 | `(elem, currIndex)``elem`为触发页当前的DOM节点 |
| change | 每一页轮播结束后触发 | index, 当前页的索引 |

View File

@ -4,6 +4,10 @@
<style lang="postcss">
body {
color: #333;
line-height: 1;
background-color: #f8f8f8;
font-family: Arial, Helvetica, "STHeiti STXihei", "Microsoft YaHei", Tohoma, sans-serif;
-webkit-font-smoothing: antialiased;
}
</style>

View File

@ -1,5 +1,5 @@
<template>
<div class="van-swipe-item">
<div class="van-swipe-item" :style="style">
<slot></slot>
</div>
</template>
@ -10,13 +10,27 @@ export default {
beforeCreate() {
this.$parent.swipes.push(this);
this.$parent.childrenOffset.push(0);
},
data() {
return {
offset: 0,
index: this.$parent.swipes.indexOf(this)
};
},
computed: {
style() {
return {
width: this.$parent.width + 'px',
transform: `translate3d(${this.offset}px, 0, 0)`
};
}
},
destroyed() {
const index = this.$parent.swipes.indexOf(this);
if (index > -1) {
this.$parent.swipes.splice(index, 1);
}
this.$parent.swipes.splice(this.index, 1);
}
};
</script>

View File

@ -1,97 +1,161 @@
<template>
<div class="van-swipe">
<div class="van-swipe__items">
<div
:style="trackStyle"
class="van-swipe__track"
@touchstart="onTouchStart"
@touchmove="onTouchMove"
@touchend="onTouchEnd"
@touchcancel="onTouchEnd"
@transitionend="$emit('change', activeIndicator)"
>
<slot></slot>
</div>
<div
class="van-swipe__indicators"
v-if="showIndicators && swipes.length > 1"
>
<span class="van-swipe__indicator" v-for="(item, index) in swipes.length" :key="index" :class="{
'van-swipe__indicator--active': currIndex === index
}">
</span>
<div class="van-swipe__indicators" v-if="showIndicators && count > 1">
<i v-for="index in count" :class="{ 'van-swipe__indicator--active': index - 1 === activeIndicator }" />
</div>
</div>
</div>
</template>
<script>
import Input from './input';
import Scroll from './scroll';
import SpringDummy from './spring_dummy';
export default {
name: 'van-swipe',
props: {
autoPlay: Boolean,
autoplay: Number,
showIndicators: {
type: Boolean,
default: true
},
duration: {
type: Number,
default: 500
}
},
data() {
return {
currIndex: 0,
swipes: []
offset: 0,
startX: 0,
startY: 0,
active: 0,
deltaX: 0,
swipes: [],
childrenOffset: [],
direction: '',
currentDuration: 0,
width: window.innerWidth
};
},
mounted() {
this.input = new Input(this.$el, {
listenMoving: true
});
this.input.on('move', function(dist, isEnd, e, extra) {
if (extra.orgDirection) {
e.preventDefault();
scroll.movePage(dist.x, isEnd);
}
});
this.scroll = new Scroll(this.$el, {
autoPlay: this.autoPlay
});
const scroll = this.scroll;
scroll.on('pageChangeEnd', this.onPageChangeEnd);
const dummy = new SpringDummy(scroll, this.input);
dummy.on('bounce', function(dist, isEnd) {
scroll.movePage(dist.x, isEnd);
}).on('autoPlay', function(dist, isEnd) {
scroll.movePage(dist.x, isEnd);
});
this.dummy = dummy;
this.move(0);
this.autoPlay();
},
watch: {
swipes(value) {
if (this.autoPlay && value.length > 1) {
this.dummy.initMove();
} else {
this.dummy.clearMove();
}
this.scroll.update();
return value;
computed: {
count() {
return this.swipes.length;
},
autoPlay(value) {
if (value && this.swipes.length > 1) {
this.dummy.initMove();
} else {
this.dummy.clearMove();
}
return value;
trackStyle() {
return this.count === 1 ? {} : {
paddingLeft: this.width + 'px',
width: (this.count + 2) * this.width + 'px',
transitionDuration: `${this.currentDuration}ms`,
transform: `translate3d(${this.offset}px, 0, 0)`
};
},
activeIndicator() {
return (this.active + this.count) % this.count;
}
},
methods: {
onPageChangeEnd(page, currIndex) {
this.currIndex = +currIndex;
this.$emit('pagechange:end', page, currIndex);
onTouchStart(event) {
clearTimeout(this.timer);
this.deltaX = 0;
this.direction = '';
this.currentDuration = 0;
this.startX = event.touches[0].clientX;
this.startY = event.touches[0].clientY;
if (this.active === -1) {
this.move(this.count);
}
if (this.active === this.count) {
this.move(-this.count);
}
},
onTouchMove(event) {
this.direction = this.direction || this.getDirection(event.touches[0]);
if (this.direction === 'horizontal') {
event.preventDefault();
this.deltaX = event.touches[0].clientX - this.startX;
this.move(0, this.range(this.deltaX, [-this.width, this.width]));
}
},
onTouchEnd() {
if (this.deltaX) {
this.move(Math.abs(this.deltaX) > 50 ? (this.deltaX > 0 ? -1 : 1) : 0);
this.currentDuration = this.duration;
}
this.autoPlay();
},
move(move = 0, offset = 0) {
const { active, count, swipes, deltaX, width } = this;
if (move) {
if (active === -1) {
swipes[count - 1].offset = 0;
}
swipes[0].offset = active === count - 1 ? count * width : 0;
this.active += move;
} else {
if (active === 0) {
swipes[count - 1].offset = deltaX > 0 ? -count * width : 0;
} else if (active === count - 1) {
swipes[0].offset = deltaX < 0 ? count * width : 0;
}
}
this.offset = offset - (this.active + 1) * this.width;
},
autoPlay() {
const { autoplay } = this;
if (autoplay && this.count > 1) {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
this.currentDuration = 0;
if (this.active === this.count) {
this.move(-this.count);
}
setTimeout(() => {
this.currentDuration = this.duration;
this.move(1);
this.autoPlay();
}, 30);
}, autoplay);
}
},
getDirection(touch) {
const distanceX = Math.abs(touch.clientX - this.startX);
const distanceY = Math.abs(touch.clientY - this.startY);
return distanceX > distanceY ? 'horizontal' : distanceX < distanceY ? 'vertical' : '';
},
range(num, arr) {
return Math.min(Math.max(num, arr[0]), arr[1]);
}
}
};

View File

@ -1,119 +0,0 @@
import Vue from 'vue';
import { EventEmitter, extend, bindEvents, removeEvents } from './utils';
function Input(host, options) {
EventEmitter.apply(this, arguments);
this.isStarting = false;
this.startPt = null;
this.endPt = null;
this.isDeaf = false;
this.options = extend({
listenMoving: false
}, options);
this.host = host;
this.onTouchStart = this.onTouchStart.bind(this);
this.onTouchMove = this.onTouchMove.bind(this);
this.onTouchEnd = this.onTouchEnd.bind(this);
this.bind(this.host);
}
Input.prototype = Object.create(new EventEmitter());
extend(Input.prototype, {
bind: function(host) {
if (Vue.prototype.$isServer) return;
bindEvents(host, 'dragstart', e => e.preventDefault());
bindEvents(host, 'touchstart mousedown', this.onTouchStart);
if (this.options.listenMoving) {
bindEvents(window, 'touchmove mousemove', this.onTouchMove);
}
bindEvents(window, 'touchend mouseup touchcancel', this.onTouchEnd);
},
onTouchStart: function(e) {
if (this.isDeaf || this.isStarting) {
return;
}
this.isStarting = true;
this.orgDirection = null;
this.startPt = this.pointerEventToXY(e);
},
onTouchMove: function(e) {
if (!this.isStarting) {
return;
}
this.caculate(e);
},
onTouchEnd: function(e) {
if (!this.isStarting) {
return;
}
this.isStarting = false;
this.caculate(e, true);
},
caculate: function(e, isEnd) {
var distY, distX;
this.endPt = this.pointerEventToXY(e);
distY = this.startPt.y - this.endPt.y;
distX = this.startPt.x - this.endPt.x;
if (distY) {
this.emit(distY > 0 ? 'up' : 'down', distY, isEnd, e);
}
if (distX) {
this.emit(distX > 0 ? 'left' : 'right', distX, isEnd, e);
}
if (this.orgDirection == null) {
this.orgDirection = Math.abs(distX) > Math.abs(distY);
}
this.emit('move', { x: distX, y: distY }, isEnd, e, { orgDirection: this.orgDirection });
},
pointerEventToXY: function(e) {
var out = { x: 0, y: 0 };
var type = e.type;
if (e.originalEvent) {
e = e.originalEvent;
}
if (['touchstart', 'touchmove', 'touchend', 'touchcancel'].indexOf(type) > -1) {
var touch = e.touches[0] || e.changedTouches[0];
out.x = touch.pageX;
out.y = touch.pageY;
} else if (
['mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'mouseenter', 'mouseleave'].indexOf(type) > -1
) {
out.x = e.pageX;
out.y = e.pageY;
}
return out;
},
deaf: function() {
this.isDeaf = true;
},
undeaf: function() {
this.isDeaf = false;
},
destroy: function() {
if (Vue.prototype.$isServer) return;
removeEvents(this.host, 'touchstart mousedown', this.onTouchStart);
if (this.options.listenMoving) {
removeEvents(window, 'touchmove mousemove', this.onTouchMove);
}
removeEvents(window, 'touchend mouseup touchcancel', this.onTouchEnd);
}
});
export default Input;

View File

@ -1,146 +0,0 @@
import { EventEmitter, extend } from './utils';
const setElementsStyles = (elems, styles) => {
Array.prototype.forEach.call(elems, item => {
extend(item.style, styles);
});
};
function Scroll(wrapElem, options) {
EventEmitter.apply(this, arguments);
this.wrapElem = wrapElem;
this.wrapSize = {
width: () => wrapElem.clientWidth,
height: () => wrapElem.clientHeight
};
this.options = extend({
loop: true,
autoPlay: false,
startIndex: 0
}, options);
this.init.apply(this, arguments);
}
Scroll.prototype = Object.create(new EventEmitter());
extend(Scroll.prototype, {
init: function() {
this.update();
},
getCurrentDist: function() {
return this.mCache.currentDist;
},
update: function() {
const oldPages = this.pages;
this.pages = this.wrapElem.querySelectorAll('.van-swipe-item');
if (oldPages && oldPages.length === this.pages.length) {
const isSame = Array.prototype.every.call(this.pages, (elem, index) => {
return this.pages[index] === oldPages[index];
});
if (isSame) {
return;
}
}
var defaultStyle = {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%'
};
setElementsStyles(this.pages, defaultStyle);
this.mCache = {
dist: 0,
offsetPage: 0
};
this.setCurrentPage(0);
this.movePage(this.options.startIndex * this.wrapSize.width(), true);
},
renderPage: function(dist = 0, currentOffsetPage = 0) {
var wrapWidth = this.wrapSize.width();
var offset = currentOffsetPage * wrapWidth - dist;
var page;
var leftPage;
var rightPage;
var leftOffset = offset - wrapWidth;
var rightOffset = offset + wrapWidth;
leftPage = this.pages[this.mapLoopPage(currentOffsetPage - 1)];
if (leftPage) {
if (Math.abs(leftOffset) <= wrapWidth) {
leftPage.style['-webkit-transform'] = 'translate3d(' + leftOffset + 'px, 0, 0)';
} else {
if (this.pages.length > 2) {
leftPage.style['-webkit-transform'] = 'translate3d(-9999px, 0, 0)';
}
}
}
rightPage = this.pages[this.mapLoopPage(currentOffsetPage + 1)];
if (rightPage) {
if (Math.abs(rightOffset) <= wrapWidth) {
rightPage.style['-webkit-transform'] = 'translate3d(' + rightOffset + 'px, 0, 0)';
} else {
if (this.pages.length > 2) {
rightPage.style['-webkit-transform'] = 'translate3d(-9999px, 0, 0)';
}
}
}
page = this.getCurrentPage();
if (page) {
page.style['-webkit-transform'] = 'translate3d(' + offset + 'px, 0, 0)';
page.style['display'] = 'block';
}
},
movePage: function(dist, isEnd) {
var currentOffsetPage;
this.mCache.currentDist = dist + this.mCache.dist;
if (isEnd) {
this.mCache.dist += dist;
}
currentOffsetPage = Math.round(this.mCache.currentDist / this.wrapSize.width()) || 0;
if (currentOffsetPage !== this.mCache.offsetPage) {
this.setCurrentPage(currentOffsetPage);
// 翻页
this.emit('pageChangeEnd', this.getCurrentPage()
, this.currentIndex, this.mCache.offsetPage);
this.mCache.offsetPage = currentOffsetPage;
}
this.renderPage(this.mCache.currentDist, currentOffsetPage);
},
getCurrentPage: function() {
return this.pages[this.currentIndex];
},
mapLoopPage: function(num) {
if (this.options.loop) {
var direction = num < 0 ? -1 : 1;
var l = this.pages.length;
return Math.abs(l + direction * Math.abs(num) % l) % l;
} else {
if (num >= this.pages.length || num < 0) {
return this.pages.length;
} else {
return num;
}
}
},
setCurrentPage: function(num) {
this.currentIndex = this.mapLoopPage(num);
}
});
export default Scroll;

View File

@ -1,145 +0,0 @@
import { requestAnimationFrame, cancelAnimationFrame, EventEmitter, extend } from './utils';
function SpringDummy(scroll, input, options) {
var wrapElem = scroll.wrapElem;
var self = this;
EventEmitter.apply(this, arguments);
this.scroll = scroll;
this.input = input;
this.input.on('move', this.movementReact.bind(this));
this.wrapSize = {
width: () => wrapElem.clientWidth,
height: () => wrapElem.clientHieght
};
this.options = extend({
intervalTween: 3000,
threshold: 20
}, options);
if (this.scroll.options.autoPlay) {
this.initMove();
}
this.on('bounceEnd', function() {
if (self.scroll.options.autoPlay) {
self.initMove();
}
self.input.undeaf();
}).on('bounceStart', function() {
self.input.deaf();
});
}
SpringDummy.prototype = Object.create(new EventEmitter());
extend(SpringDummy.prototype, {
clearTransition: function() {
cancelAnimationFrame(this.transitionReq);
},
movementReact: function(pt, isEnd, e, extra) {
if (isEnd) {
this.launch(extra.orgDirection ? pt.x : 0);
}
this.clearMove();
},
launch: function(dist) {
var self = this;
var direction = dist / Math.abs(dist);
var addition = 0;
var w = self.wrapSize.width();
var tempOffsetPage = Math.round(dist / w);
var offsetPage = this.scroll.mCache.offsetPage;
// 翻到对应页
addition = w * tempOffsetPage;
// addition为0是原位置
if (addition === 0) {
if (Math.abs(dist) > self.options.threshold) {
// 翻到下一页
addition = w * direction;
}
}
if (!self.scroll.options.loop) {
if (offsetPage <= 0) {
if (Math.abs(dist) > self.options.threshold && direction > 0) {
addition = w * direction;
} else {
addition = w * (tempOffsetPage - offsetPage);
}
}
if (this.scroll.pages.length === 1) {
addition = 0;
} else if (offsetPage >= this.scroll.pages.length - 1) {
if (Math.abs(dist) > self.options.threshold && direction < 0) {
addition = w * direction;
} else {
addition = w * (tempOffsetPage - offsetPage + this.scroll.pages.length - 1);
}
}
}
this.initTween(addition - dist, 150, 'bounce');
},
initTween: function(dist, duration, eventName) {
if (dist === 0) {
return;
}
var elapse;
var self = this;
var startTime = new Date();
this.cancelTween();
this.emit(eventName + 'Start');
function round() {
elapse = new Date() - startTime;
if (elapse > duration) {
self.emit(eventName, { x: dist }, true);
self.emit(eventName + 'End');
return;
}
self.emit(eventName, { x: dist / duration * elapse }, false);
self.tweenRid = requestAnimationFrame(round);
}
round();
},
cancelTween: function() {
cancelAnimationFrame(this.tweenRid);
},
initMove: function() {
var self = this;
var scroll = this.scroll;
var intervalTween = self.options.intervalTween;
this.clearMove();
function round() {
if ((scroll.currentIndex === scroll.pages.length - 1) && !scroll.options.loop) {
self.initTween(-self.wrapSize.width() * (scroll.pages.length - 1), 200, 'autoPlay');
} else {
self.initTween(self.wrapSize.width(), 200, 'autoPlay');
}
self.moveTid = setTimeout(round, intervalTween);
}
self.moveTid = setTimeout(round, intervalTween);
},
clearMove: function() {
clearTimeout(this.moveTid);
}
});
export default SpringDummy;

View File

@ -1,77 +0,0 @@
import Vue from 'vue';
var extend = Object.assign.bind(Object);
function EventEmitter() {
this.__events = {};
}
EventEmitter.prototype = {
on: function(name, cb) {
this.__events[name] || (this.__events[name] = []);
this.__events[name].push(cb);
return this;
},
emit: function(name) {
var arr = this.__events[name];
var argus = Array.prototype.slice.call(arguments, 1);
var self = this;
if (arr) {
arr.forEach(function(cb) {
cb.apply(self, argus);
});
}
},
removeListener: function(name, fn) {
if (!this.__events[name]) {
return;
}
let index;
if (fn) {
index = this.__events[name].indexOf(fn);
if (index > 0) {
this.__events[name].splice(index, 1);
}
} else {
delete this.__events[name];
}
}
};
const isSupportRequestAnimationFrame = !Vue.prototype.$isServer &&
(window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame);
const isSupportCancelAnimationFrame = !Vue.prototype.$isServer &&
(window.cancelAnimationFrame ||
window.mozCancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.msCancelAnimationFrame);
const requestAnimationFrame = isSupportRequestAnimationFrame || function(callback, element) {
return window.setTimeout(callback, 1000 / 60);
};
const cancelAnimationFrame = isSupportCancelAnimationFrame || function(id) {
clearTimeout(id);
};
const bindEvents = (elem, eventNames, fn) => {
eventNames = eventNames.split(/\s+/);
eventNames.forEach(eventName => elem.addEventListener(eventName, fn));
};
const removeEvents = (elem, eventNames, fn) => {
eventNames = eventNames.split(/\s+/);
eventNames.forEach(eventName => elem.removeEventListener(eventName, fn));
};
export {
extend,
EventEmitter,
requestAnimationFrame,
cancelAnimationFrame,
bindEvents,
removeEvents
};

View File

@ -3,9 +3,10 @@
.van-card {
color: $text-color;
height: 90px;
height: 100px;
background: #fafafa;
position: relative;
box-sizing: border-box;
padding: 5px 15px 5px 115px;
&:not(:first-child) {

View File

@ -29,3 +29,7 @@ ul {
padding: 0;
list-style: none;
}
button {
font-family: inherit;
}

View File

@ -1,53 +1,44 @@
@import './common/var.css';
$van-swipe-indicator: 6px;
.van-swipe {
position: relative;
overflow: hidden;
width: 100%;
height: 100%;
&__indicators {
position: absolute;
bottom: 10px;
left: 50%;
transform: translateX(-50%);
}
&__indicator {
width: 5px;
height: 5px;
display: inline-block;
border-radius: 100%;
background: $gray-dark;
opacity: .8;
margin: 0 3px;
z-index: 1;
&--active {
background: $orange;
opacity: 1;
}
}
&__items {
position: relative;
overflow: hidden;
height: 100%;
}
position: relative;
user-select: none;
&-item {
display: none;
float: left;
height: 100%;
width: 100%;
text-align: center;
}
img {
width: 100%;
height: auto;
&__track {
height: 100%;
overflow: hidden;
}
&__indicators {
left: 50%;
bottom: 10px;
position: absolute;
height: $van-swipe-indicator;
transform: translate3d(-50%, 0, 0);
> i {
border-radius: 100%;
vertical-align: top;
display: inline-block;
background-color: $gray-dark;
width: $van-swipe-indicator;
height: $van-swipe-indicator;
&:not(:last-child) {
margin-right: $van-swipe-indicator;
}
}
&:first-child {
display: block;
.van-swipe__indicator {
&--active {
background-color: $orange;
}
}
}
}