uikit
Version:
UIkit is a lightweight and modular front-end framework for developing fast and powerful web interfaces.
227 lines (186 loc) • 6.16 kB
JavaScript
import {
$,
addClass,
children,
clamp,
getIndex,
hasClass,
isNumber,
isRtl,
removeClass,
trigger,
} from 'uikit-util';
import I18n from './i18n';
import SliderAutoplay from './slider-autoplay';
import SliderDrag from './slider-drag';
import SliderNav from './slider-nav';
const easeOutQuad = 'cubic-bezier(0.25, 0.46, 0.45, 0.94)';
const easeOutQuart = 'cubic-bezier(0.165, 0.84, 0.44, 1)';
export default {
mixins: [SliderAutoplay, SliderDrag, SliderNav, I18n],
props: {
clsActivated: String,
easing: String,
index: Number,
finite: Boolean,
velocity: Number,
},
data: () => ({
easing: 'ease',
finite: false,
velocity: 1,
index: 0,
prevIndex: -1,
stack: [],
percent: 0,
clsActive: 'uk-active',
clsActivated: '',
clsEnter: 'uk-slide-enter',
clsLeave: 'uk-slide-leave',
clsSlideActive: 'uk-slide-active',
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) => speedUp($el.offsetWidth / velocity),
list: ({ selList }, $el) => $(selList, $el),
maxIndex() {
return this.length - 1;
},
slides() {
return children(this.list);
},
length() {
return this.slides.length;
},
},
watch: {
slides(slides, prev) {
if (prev) {
this.$emit();
}
},
},
events: {
itemshow({ target }) {
addClass(target, this.clsEnter, this.clsSlideActive);
},
itemshown({ target }) {
removeClass(target, this.clsEnter);
},
itemhide({ target }) {
addClass(target, this.clsLeave);
},
itemhidden({ target }) {
removeClass(target, this.clsLeave, this.clsSlideActive);
},
},
methods: {
async show(index, force = false) {
if (this.dragging || !this.length || this.parallax) {
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;
}
prev && trigger(prev, 'itemhide', [this]);
trigger(next, 'itemshow', [this]);
await this._show(prev, next, force);
prev && trigger(prev, 'itemhidden', [this]);
trigger(next, 'itemshown', [this]);
stack.shift();
this._transitioner = null;
if (stack.length) {
requestAnimationFrame(() => stack.length && this.show(stack.shift(), true));
}
},
getIndex(index = this.index, prev = this.index) {
return clamp(
getIndex(index, this.slides, prev, this.finite),
0,
Math.max(0, this.maxIndex),
);
},
getValidIndex(index = this.index, prevIndex = this.prevIndex) {
return this.getIndex(index, prevIndex);
},
async _show(prev, next, force) {
this._transitioner = this._getTransitioner(prev, next, this.dir, {
easing: force ? (next.offsetWidth < 600 ? easeOutQuad : easeOutQuart) : this.easing,
...this.transitionOptions,
});
if (!force && !prev) {
this._translate(1);
return;
}
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,
);
},
_translate(percent, prev = this.prevIndex, next = this.index) {
const transitioner = this._getTransitioner(prev === next ? false : prev, 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)
}