123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432 |
- // Utils
- import { createNamespace } from '../utils';
- import { isHidden } from '../utils/dom/style';
- import { preventDefault } from '../utils/dom/event';
- import { doubleRaf } from '../utils/dom/raf';
- import { range } from '../utils/format/number'; // Mixins
- import { TouchMixin } from '../mixins/touch';
- import { ParentMixin } from '../mixins/relation';
- import { BindEventMixin } from '../mixins/bind-event';
- var _createNamespace = createNamespace('swipe'),
- createComponent = _createNamespace[0],
- bem = _createNamespace[1];
- export default createComponent({
- mixins: [TouchMixin, ParentMixin('vanSwipe'), BindEventMixin(function (bind, isBind) {
- bind(window, 'resize', this.resize, true);
- bind(window, 'orientationchange', this.resize, true);
- bind(window, 'visibilitychange', this.onVisibilityChange);
- if (isBind) {
- this.initialize();
- } else {
- this.clear();
- }
- })],
- props: {
- width: [Number, String],
- height: [Number, String],
- autoplay: [Number, String],
- vertical: Boolean,
- lazyRender: Boolean,
- indicatorColor: String,
- loop: {
- type: Boolean,
- default: true
- },
- duration: {
- type: [Number, String],
- default: 500
- },
- touchable: {
- type: Boolean,
- default: true
- },
- initialSwipe: {
- type: [Number, String],
- default: 0
- },
- showIndicators: {
- type: Boolean,
- default: true
- },
- stopPropagation: {
- type: Boolean,
- default: true
- }
- },
- data: function data() {
- return {
- rect: null,
- offset: 0,
- active: 0,
- deltaX: 0,
- deltaY: 0,
- swiping: false,
- computedWidth: 0,
- computedHeight: 0
- };
- },
- watch: {
- children: function children() {
- this.initialize();
- },
- initialSwipe: function initialSwipe() {
- this.initialize();
- },
- autoplay: function autoplay(_autoplay) {
- if (_autoplay > 0) {
- this.autoPlay();
- } else {
- this.clear();
- }
- }
- },
- computed: {
- count: function count() {
- return this.children.length;
- },
- maxCount: function maxCount() {
- return Math.ceil(Math.abs(this.minOffset) / this.size);
- },
- delta: function delta() {
- return this.vertical ? this.deltaY : this.deltaX;
- },
- size: function size() {
- return this[this.vertical ? 'computedHeight' : 'computedWidth'];
- },
- trackSize: function trackSize() {
- return this.count * this.size;
- },
- activeIndicator: function activeIndicator() {
- return (this.active + this.count) % this.count;
- },
- isCorrectDirection: function isCorrectDirection() {
- var expect = this.vertical ? 'vertical' : 'horizontal';
- return this.direction === expect;
- },
- trackStyle: function trackStyle() {
- var style = {
- transitionDuration: (this.swiping ? 0 : this.duration) + "ms",
- transform: "translate" + (this.vertical ? 'Y' : 'X') + "(" + this.offset + "px)"
- };
- if (this.size) {
- var mainAxis = this.vertical ? 'height' : 'width';
- var crossAxis = this.vertical ? 'width' : 'height';
- style[mainAxis] = this.trackSize + "px";
- style[crossAxis] = this[crossAxis] ? this[crossAxis] + "px" : '';
- }
- return style;
- },
- indicatorStyle: function indicatorStyle() {
- return {
- backgroundColor: this.indicatorColor
- };
- },
- minOffset: function minOffset() {
- return (this.vertical ? this.rect.height : this.rect.width) - this.size * this.count;
- }
- },
- mounted: function mounted() {
- this.bindTouchEvent(this.$refs.track);
- },
- methods: {
- // initialize swipe position
- initialize: function initialize(active) {
- if (active === void 0) {
- active = +this.initialSwipe;
- }
- if (!this.$el || isHidden(this.$el)) {
- return;
- }
- clearTimeout(this.timer);
- var rect = {
- width: this.$el.offsetWidth,
- height: this.$el.offsetHeight
- };
- this.rect = rect;
- this.swiping = true;
- this.active = active;
- this.computedWidth = +this.width || rect.width;
- this.computedHeight = +this.height || rect.height;
- this.offset = this.getTargetOffset(active);
- this.children.forEach(function (swipe) {
- swipe.offset = 0;
- });
- this.autoPlay();
- },
- // @exposed-api
- resize: function resize() {
- this.initialize(this.activeIndicator);
- },
- onVisibilityChange: function onVisibilityChange() {
- if (document.hidden) {
- this.clear();
- } else {
- this.autoPlay();
- }
- },
- onTouchStart: function onTouchStart(event) {
- if (!this.touchable) return;
- this.clear();
- this.touchStartTime = Date.now();
- this.touchStart(event);
- this.correctPosition();
- },
- onTouchMove: function onTouchMove(event) {
- if (!this.touchable || !this.swiping) return;
- this.touchMove(event);
- if (this.isCorrectDirection) {
- preventDefault(event, this.stopPropagation);
- this.move({
- offset: this.delta
- });
- }
- },
- onTouchEnd: function onTouchEnd() {
- if (!this.touchable || !this.swiping) return;
- var size = this.size,
- delta = this.delta;
- var duration = Date.now() - this.touchStartTime;
- var speed = delta / duration;
- var shouldSwipe = Math.abs(speed) > 0.25 || Math.abs(delta) > size / 2;
- if (shouldSwipe && this.isCorrectDirection) {
- var offset = this.vertical ? this.offsetY : this.offsetX;
- var pace = 0;
- if (this.loop) {
- pace = offset > 0 ? delta > 0 ? -1 : 1 : 0;
- } else {
- pace = -Math[delta > 0 ? 'ceil' : 'floor'](delta / size);
- }
- this.move({
- pace: pace,
- emitChange: true
- });
- } else if (delta) {
- this.move({
- pace: 0
- });
- }
- this.swiping = false;
- this.autoPlay();
- },
- getTargetActive: function getTargetActive(pace) {
- var active = this.active,
- count = this.count,
- maxCount = this.maxCount;
- if (pace) {
- if (this.loop) {
- return range(active + pace, -1, count);
- }
- return range(active + pace, 0, maxCount);
- }
- return active;
- },
- getTargetOffset: function getTargetOffset(targetActive, offset) {
- if (offset === void 0) {
- offset = 0;
- }
- var currentPosition = targetActive * this.size;
- if (!this.loop) {
- currentPosition = Math.min(currentPosition, -this.minOffset);
- }
- var targetOffset = offset - currentPosition;
- if (!this.loop) {
- targetOffset = range(targetOffset, this.minOffset, 0);
- }
- return targetOffset;
- },
- move: function move(_ref) {
- var _ref$pace = _ref.pace,
- pace = _ref$pace === void 0 ? 0 : _ref$pace,
- _ref$offset = _ref.offset,
- offset = _ref$offset === void 0 ? 0 : _ref$offset,
- emitChange = _ref.emitChange;
- var loop = this.loop,
- count = this.count,
- active = this.active,
- children = this.children,
- trackSize = this.trackSize,
- minOffset = this.minOffset;
- if (count <= 1) {
- return;
- }
- var targetActive = this.getTargetActive(pace);
- var targetOffset = this.getTargetOffset(targetActive, offset); // auto move first and last swipe in loop mode
- if (loop) {
- if (children[0] && targetOffset !== minOffset) {
- var outRightBound = targetOffset < minOffset;
- children[0].offset = outRightBound ? trackSize : 0;
- }
- if (children[count - 1] && targetOffset !== 0) {
- var outLeftBound = targetOffset > 0;
- children[count - 1].offset = outLeftBound ? -trackSize : 0;
- }
- }
- this.active = targetActive;
- this.offset = targetOffset;
- if (emitChange && targetActive !== active) {
- this.$emit('change', this.activeIndicator);
- }
- },
- // @exposed-api
- prev: function prev() {
- var _this = this;
- this.correctPosition();
- this.resetTouchStatus();
- doubleRaf(function () {
- _this.swiping = false;
- _this.move({
- pace: -1,
- emitChange: true
- });
- });
- },
- // @exposed-api
- next: function next() {
- var _this2 = this;
- this.correctPosition();
- this.resetTouchStatus();
- doubleRaf(function () {
- _this2.swiping = false;
- _this2.move({
- pace: 1,
- emitChange: true
- });
- });
- },
- // @exposed-api
- swipeTo: function swipeTo(index, options) {
- var _this3 = this;
- if (options === void 0) {
- options = {};
- }
- this.correctPosition();
- this.resetTouchStatus();
- doubleRaf(function () {
- var targetIndex;
- if (_this3.loop && index === _this3.count) {
- targetIndex = _this3.active === 0 ? 0 : index;
- } else {
- targetIndex = index % _this3.count;
- }
- if (options.immediate) {
- doubleRaf(function () {
- _this3.swiping = false;
- });
- } else {
- _this3.swiping = false;
- }
- _this3.move({
- pace: targetIndex - _this3.active,
- emitChange: true
- });
- });
- },
- correctPosition: function correctPosition() {
- this.swiping = true;
- if (this.active <= -1) {
- this.move({
- pace: this.count
- });
- }
- if (this.active >= this.count) {
- this.move({
- pace: -this.count
- });
- }
- },
- clear: function clear() {
- clearTimeout(this.timer);
- },
- autoPlay: function autoPlay() {
- var _this4 = this;
- var autoplay = this.autoplay;
- if (autoplay > 0 && this.count > 1) {
- this.clear();
- this.timer = setTimeout(function () {
- _this4.next();
- _this4.autoPlay();
- }, autoplay);
- }
- },
- genIndicator: function genIndicator() {
- var _this5 = this;
- var h = this.$createElement;
- var count = this.count,
- activeIndicator = this.activeIndicator;
- var slot = this.slots('indicator');
- if (slot) {
- return slot;
- }
- if (this.showIndicators && count > 1) {
- return h("div", {
- "class": bem('indicators', {
- vertical: this.vertical
- })
- }, [Array.apply(void 0, Array(count)).map(function (empty, index) {
- return h("i", {
- "class": bem('indicator', {
- active: index === activeIndicator
- }),
- "style": index === activeIndicator ? _this5.indicatorStyle : null
- });
- })]);
- }
- }
- },
- render: function render() {
- var h = arguments[0];
- return h("div", {
- "class": bem()
- }, [h("div", {
- "ref": "track",
- "style": this.trackStyle,
- "class": bem('track', {
- vertical: this.vertical
- })
- }, [this.slots()]), this.genIndicator()]);
- }
- });
|