vivo-ui
Version:
vivo ui component lib for vue
268 lines (250 loc) • 8.82 kB
JavaScript
import _defineProperty from 'babel-runtime/helpers/defineProperty';
import Tween from '../../tools/tween/index';
import { raf, caf } from '../../tools/prefix/index';
(function () {
if (typeof document !== 'undefined') {
var head = document.head || document.getElementsByTagName('head')[0],
style = document.createElement('style'),
css = " .src-components-swiper-index--swiper--27769 { overflow: hidden; } .src-components-swiper-index--swiper--27769 > ul { list-style-type: none; margin: 0; padding: 0; } .src-components-swiper-index--horizontal--3oOKy > ul { white-space: nowrap; } .src-components-swiper-index--horizontal--3oOKy > ul > li { display: inline-block; vertical-align: top; width: 100%; white-space: normal; } ";style.type = 'text/css';if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}head.appendChild(style);
}
})();
var index = { render: function render() {
var _vm = this;var _h = _vm.$createElement;var _c = _vm._self._c || _h;return _c('div', { class: [_vm.$style.swiper, _defineProperty({}, _vm.$style.horizontal, !_vm.vertical)], on: { "touchmove": _vm.touchmove, "touchend": _vm.touchend } }, [_c('ul', { ref: "list", style: _vm.style }, [_vm._t("default")], 2)]);
}, staticRenderFns: [], cssModules: { "swiper": "src-components-swiper-index--swiper--27769", "horizontal": "src-components-swiper-index--horizontal--3oOKy" },
name: 'swiper',
inheritAttrs: false,
props: {
value: {
type: Number,
default: 0
},
direction: {
type: String,
default: 'left',
validator: function validator(value) {
return ['up', 'down', 'left', 'right'].indexOf(value) !== -1;
}
},
loop: { // 是否循环
type: Boolean,
default: true
},
interval: { // 轮播间隔时间
type: Number,
default: 3000
},
duration: { // 动画时间,表示多少帧
type: Number,
default: 30
},
swipe: { // 是否可以手指滑动
type: Boolean,
default: true
},
threshold: { // 超过了多少百分比才切换
type: Number,
default: 0.2
}
},
data: function data() {
return {
index: this.value,
pos: this.value + this.loop,
height: undefined
};
},
computed: {
$style: function $style() {
return this.$options.cssModules;
},
style: function style() {
return {
height: this.height + 'px',
transform: 'translate' + (this.vertical ? 'Y' : 'X') + '(' + -this.pos * 100 + '%)'
};
},
vertical: function vertical() {
return ['up', 'down'].indexOf(this.direction) !== -1;
}
},
watch: {
value: function value(_value) {
this.index = _value;
},
index: function index(value) {
this.preventUpdate();
this.clear();
this.$emit('input', value);
value + this.loop - this.pos && this.buffer(this.pos, value + this.loop - this.pos, Math.round(Math.min(Math.abs(value + this.loop - this.pos), 1) * this.duration) || 1);
},
direction: 'preventUpdate',
interval: 'preventUpdate',
duration: 'preventUpdate',
swipe: 'preventUpdate',
threshold: 'preventUpdate',
pos: 'preventUpdate',
height: 'preventUpdate'
},
methods: {
preventUpdate: function preventUpdate() {
// 组件属性变化时阻止触发updated钩子,确保只有slot内容变化才触发
this.prevent = true;
},
update: function update() {
var _this = this;
// 内容有变化
var first = void 0,
last = void 0,
max = void 0;
// 获取子项最高的高度
this.$children.forEach(function (child, index) {
!index && (first = child.$el);
index === _this.$children.length - 1 && (last = child.$el);(!index || child.$el.offsetHeight > max) && (max = child.$el.offsetHeight);
});
// 给每个子项设置成最高高度
this.$children.forEach(function (child) {
child.$el.style.height = max + 'px';
});
// 将第一项复制到最后,将最后一项复制到最前
if (this.first) {
this.first.parentElement.removeChild(this.first);
this.first = undefined;
}
if (this.last) {
this.last.parentElement.removeChild(this.last);
this.last = undefined;
}
if (this.loop) {
this.first = first.cloneNode(true);
this.last = last.cloneNode(true);
this.$refs.list.insertBefore(this.last, first);
this.$refs.list.appendChild(this.first);
}
// 这里必须要用max记录最大值后赋值,因为只要this.height中途变化了,即使最后的结果没变,也会调用render函数,触发updated钩子。但只要最后的结果没变,watch钩子是不会执行的
this.height = max;
this.check(true);
},
check: function check(slotChange) {
if (slotChange) {
// slot内容变化
this.clear();
this.pos = Math.round(this.pos);
}
// 处理边界情况,slot内容更改后有可能大于
if (this.loop) {
if (this.pos >= this.$children.length + 1) {
this.pos = 1;
} else if (this.pos <= 0) {
this.pos = this.$children.length;
}
} else {
if (this.pos >= this.$children.length) {
this.pos = this.$children.length - 1;
} else if (this.pos < 0) {
this.pos = 0;
}
}
// 同步index
this.index = this.pos - this.loop;
this.$nextTick(function () {
// 触发位置变化事件
this.$emit('change', this.index);
this.next();
});
},
next: function next() {
var _this2 = this;
// 下一步
this.interval && (this.intervalId = setTimeout(function () {
if (['up', 'left'].indexOf(_this2.direction) !== -1) {
_this2.index = _this2.loop ? _this2.index + 1 : (_this2.index + 1) % _this2.$children.length;
} else {
_this2.index = _this2.loop ? _this2.index - 1 : (_this2.index - 1 + _this2.$children.length) % _this2.$children.length;
}
}, this.interval));
},
buffer: function buffer(b, c, d) {
var _this3 = this;
// 缓冲
var t = 0;
var fn = function fn() {
t++;
_this3.pos = Tween.Cubic.easeOut(t, b, c, d);
t === d && (_this3.pos = Math.round(_this3.pos));
t < d ? _this3.rafId = raf(fn) : _this3.check();
};
this.rafId = raf(fn);
},
clear: function clear() {
caf(this.rafId);
clearInterval(this.intervalId);
},
touchmove: function touchmove(event) {
var _this4 = this;
if (!this.swipe) {
return;
}
if (this.touchId === undefined) {
this.clear();
this.touchId = event.changedTouches[0].identifier;
this.prev = this.vertical ? event.changedTouches[0].clientY : event.changedTouches[0].clientX;
this.offset = 0;
} else {
var touch = [].slice.call(event.changedTouches).filter(function (touch) {
return touch.identifier === _this4.touchId;
})[0];
if (touch) {
// 同一个触点移动
var current = this.vertical ? touch.clientY : touch.clientX;
this.offset = (this.prev - current) / this.$refs.list[this.vertical ? 'offsetHeight' : 'offsetWidth'];
this.pos += this.offset;
this.prev = current;
}
}
},
touchend: function touchend(event) {
var _this5 = this;
if (!this.swipe) {
return;
}
if ([].slice.call(event.changedTouches).some(function (touch) {
return touch.identifier === _this5.touchId;
})) {
// 同一个触点移除了
var offset = this.pos - parseInt(this.pos);
var pos = void 0;
// 判断是否超过阈值
if (this.offset > 0 && offset >= this.threshold || this.offset <= 0 && offset > 1 - this.threshold) {
pos = Math.ceil(this.pos);
} else {
pos = Math.floor(this.pos);
}
this.touchId = undefined;
pos < 0 && (pos = 0);
pos === this.$children.length + (this.loop ? 2 : 0) && pos--;
this.buffer(this.pos, pos - this.pos, Math.round(Math.abs(pos - this.pos) * this.duration) || 1);
}
}
},
mounted: function mounted() {
this.$nextTick(this.update);
},
updated: function updated() {
this.$nextTick(function () {
if (!this.prevent) {
// slot内容更新
this.update();
} else {
this.prevent = false;
}
});
},
beforeDestroy: function beforeDestroy() {
this.clear();
}
};
export default index;