uikit
Version:
UIkit is a lightweight and modular front-end framework for developing fast and powerful web interfaces.
221 lines (184 loc) • 6.19 kB
JavaScript
import Resize from './resize';
import SliderAutoplay from './slider-autoplay';
import SliderDrag from './slider-drag';
import SliderNav from './slider-nav';
import {
$,
$$,
clamp,
fastdom,
getIndex,
hasClass,
isNumber,
isRtl,
removeClass,
trigger,
} from 'uikit-util';
export default {
mixins: [SliderAutoplay, SliderDrag, SliderNav, Resize],
props: {
clsActivated: Boolean,
easing: String,
index: Number,
finite: Boolean,
velocity: Number,
selSlides: String,
},
data: () => ({
easing: 'ease',
finite: false,
velocity: 1,
index: 0,
prevIndex: -1,
stack: [],
percent: 0,
clsActive: 'uk-active',
clsActivated: false,
Transitioner: false,
transitionOptions: {},
}),
connected() {
this.prevIndex = -1;
this.index = this.getValidIndex(this.$props.index);
this.stack = [];
},
disconnected() {
removeClass(this.slides, this.clsActive);
},
computed: {
duration({ velocity }, $el) {
return speedUp($el.offsetWidth / velocity);
},
list({ selList }, $el) {
return $(selList, $el);
},
maxIndex() {
return this.length - 1;
},
selSlides({ selList, selSlides }) {
return `${selList} ${selSlides || '> *'}`;
},
slides: {
get() {
return $$(this.selSlides, this.$el);
},
watch() {
this.$reset();
},
},
length() {
return this.slides.length;
},
},
methods: {
show(index, force = false) {
if (this.dragging || !this.length) {
return;
}
const { stack } = this;
const queueIndex = force ? 0 : stack.length;
const reset = () => {
stack.splice(queueIndex, 1);
if (stack.length) {
this.show(stack.shift(), true);
}
};
stack[force ? 'unshift' : 'push'](index);
if (!force && stack.length > 1) {
if (stack.length === 2) {
this._transitioner.forward(Math.min(this.duration, 200));
}
return;
}
const prevIndex = this.getIndex(this.index);
const prev = hasClass(this.slides, this.clsActive) && this.slides[prevIndex];
const nextIndex = this.getIndex(index, this.index);
const next = this.slides[nextIndex];
if (prev === next) {
reset();
return;
}
this.dir = getDirection(index, prevIndex);
this.prevIndex = prevIndex;
this.index = nextIndex;
if (
(prev && !trigger(prev, 'beforeitemhide', [this])) ||
!trigger(next, 'beforeitemshow', [this, prev])
) {
this.index = this.prevIndex;
reset();
return;
}
const promise = this._show(prev, next, force).then(() => {
prev && trigger(prev, 'itemhidden', [this]);
trigger(next, 'itemshown', [this]);
return new Promise((resolve) => {
fastdom.write(() => {
stack.shift();
if (stack.length) {
this.show(stack.shift(), true);
} else {
this._transitioner = null;
}
resolve();
});
});
});
prev && trigger(prev, 'itemhide', [this]);
trigger(next, 'itemshow', [this]);
return promise;
},
getIndex(index = this.index, prev = this.index) {
return clamp(getIndex(index, this.slides, prev, this.finite), 0, this.maxIndex);
},
getValidIndex(index = this.index, prevIndex = this.prevIndex) {
return this.getIndex(index, prevIndex);
},
_show(prev, next, force) {
this._transitioner = this._getTransitioner(prev, next, this.dir, {
easing: force
? next.offsetWidth < 600
? 'cubic-bezier(0.25, 0.46, 0.45, 0.94)' /* easeOutQuad */
: 'cubic-bezier(0.165, 0.84, 0.44, 1)' /* easeOutQuart */
: this.easing,
...this.transitionOptions,
});
if (!force && !prev) {
this._translate(1);
return Promise.resolve();
}
const { length } = this.stack;
return this._transitioner[length > 1 ? 'forward' : 'show'](
length > 1 ? Math.min(this.duration, 75 + 75 / (length - 1)) : this.duration,
this.percent
);
},
_getDistance(prev, next) {
return this._getTransitioner(prev, prev !== next && next).getDistance();
},
_translate(percent, prev = this.prevIndex, next = this.index) {
const transitioner = this._getTransitioner(prev !== next ? prev : false, next);
transitioner.translate(percent);
return transitioner;
},
_getTransitioner(
prev = this.prevIndex,
next = this.index,
dir = this.dir || 1,
options = this.transitionOptions
) {
return new this.Transitioner(
isNumber(prev) ? this.slides[prev] : prev,
isNumber(next) ? this.slides[next] : next,
dir * (isRtl ? -1 : 1),
options
);
},
},
};
function getDirection(index, prevIndex) {
return index === 'next' ? 1 : index === 'previous' ? -1 : index < prevIndex ? -1 : 1;
}
export function speedUp(x) {
return 0.5 * x + 300; // parabola through (400,500; 600,600; 1800,1200)
}