UNPKG

press-ui

Version:

简单、易用的跨端组件库,兼容 Vue2 和 Vue3,同时支持 uni-app和普通 Vue 项目

260 lines (252 loc) 7.99 kB
import { Scroll } from './scroll'; function i(scroll, t, n) { function i(t, scroll, r, o) { if (!t || !t.cancelled) { r(scroll); const a = scroll.done(); if (!a) { if (!t.cancelled) { t.id = requestAnimationFrame(i.bind(null, t, scroll, r, o)); } } if (a && o) { o(scroll); } } } function r(scroll) { if (scroll && scroll.id) { cancelAnimationFrame(scroll.id); } if (scroll) { scroll.cancelled = true; } } const o = { id: 0, cancelled: false, }; i(o, scroll, t, n); return { cancel: r.bind(null, o), model: scroll, }; } export function Scroller(element, options) { options = options || {}; this._element = element; this._options = options; this._enableSnap = options.enableSnap || false; this._itemSize = options.itemSize || 0; this._enableX = options.enableX || false; this._enableY = options.enableY || false; this._shouldDispatchScrollEvent = !!options.onScroll; if (this._enableX) { this._extent = (options.scrollWidth || this._element.offsetWidth) - this._element.parentElement.offsetWidth; this._scrollWidth = options.scrollWidth; } else { this._extent = (options.scrollHeight || this._element.offsetHeight) - this._element.parentElement.offsetHeight; this._scrollHeight = options.scrollHeight; } this._position = 0; this._scroll = new Scroll(this._extent, options.friction, options.spring); this._onTransitionEnd = this.onTransitionEnd.bind(this); this.updatePosition(); } Scroller.prototype.onTouchStart = function () { this._startPosition = this._position; this._lastChangePos = this._startPosition; if (this._startPosition > 0) { this._startPosition /= 0.5; } else { if (this._startPosition < -this._extent) { this._startPosition = (this._startPosition + this._extent) / 0.5 - this._extent; } } if (this._animation) { this._animation.cancel(); this._scrolling = false; } this.updatePosition(); }; Scroller.prototype.onTouchMove = function (x, y) { let startPosition = this._startPosition; if (this._enableX) { startPosition += x; } else if (this._enableY) { startPosition += y; } if (startPosition > 0) { startPosition *= 0.5; } else if (startPosition < -this._extent) { startPosition = 0.5 * (startPosition + this._extent) - this._extent; } this._position = startPosition; this.updatePosition(); this.dispatchScroll(); }; Scroller.prototype.onTouchEnd = function (e, r, o) { if (this._enableSnap && this._position > -this._extent && this._position < 0) { if (this._enableY && ((Math.abs(r) < this._itemSize && Math.abs(o.y) < 300) || Math.abs(o.y) < 150)) { this.snap(); return; } if (this._enableX && ((Math.abs(e) < this._itemSize && Math.abs(o.x) < 300) || Math.abs(o.x) < 150)) { this.snap(); return; } } if (this._enableX) { this._scroll.set(this._position, o.x); } else if (this._enableY) { this._scroll.set(this._position, o.y); } let c; if (this._enableSnap) { const s = this._scroll._friction.x(100); const l = s % this._itemSize; c = Math.abs(l) > this._itemSize / 2 ? s - (this._itemSize - Math.abs(l)) : s - l; if (c <= 0 && c >= -this._extent) { this._scroll.setVelocityByEnd(c); } } this._lastTime = Date.now(); this._lastDelay = 0; this._scrolling = true; this._lastChangePos = this._position; this._lastIdx = Math.floor(Math.abs(this._position / this._itemSize)); this._animation = i(this._scroll, () => { const e = Date.now(); const i = (e - this._scroll._startTime) / 1e3; const r = this._scroll.x(i); this._position = r; this.updatePosition(); const o = this._scroll.dx(i); if (this._shouldDispatchScrollEvent && e - this._lastTime > this._lastDelay) { this.dispatchScroll(); this._lastDelay = Math.abs(2e3 / o); this._lastTime = e; } }, () => { if (this._enableSnap) { if (c <= 0 && c >= -this._extent) { this._position = c; this.updatePosition(); } if (typeof this._options.onSnap === 'function') { this._options.onSnap(Math.floor(Math.abs(this._position) / this._itemSize)); } } if (this._shouldDispatchScrollEvent) { this.dispatchScroll(); } this._scrolling = false; }); }; Scroller.prototype.onTransitionEnd = function () { this._element.style.transition = ''; this._element.style.webkitTransition = ''; this._element.removeEventListener('transitionend', this._onTransitionEnd); this._element.removeEventListener('webkitTransitionEnd', this._onTransitionEnd); if (this._snapping) { this._snapping = false; } this.dispatchScroll(); }; Scroller.prototype.snap = function () { const e = this._itemSize; const t = this._position % e; const i = Math.abs(t) > this._itemSize / 2 ? this._position - (e - Math.abs(t)) : this._position - t; if (this._position !== i) { this._snapping = true; this.scrollTo(-i); if (typeof this._options.onSnap === 'function') { this._options.onSnap(Math.floor(Math.abs(this._position) / this._itemSize)); } } }; Scroller.prototype.scrollTo = function (e, t) { if (this._animation) { this._animation.cancel(); this._scrolling = false; } if (typeof e === 'number') { this._position = -e; } if (this._position < -this._extent) { this._position = -this._extent; } else { if (this._position > 0) { this._position = 0; } } this._element.style.transition = `transform ${t || 0.2}s ease-out`; this._element.style.webkitTransition = `-webkit-transform ${t || 0.2}s ease-out`; this.updatePosition(); this._element.addEventListener('transitionend', this._onTransitionEnd); this._element.addEventListener('webkitTransitionEnd', this._onTransitionEnd); }; Scroller.prototype.dispatchScroll = function () { if (typeof this._options.onScroll === 'function' && Math.round(this._lastPos) !== Math.round(this._position)) { this._lastPos = this._position; const e = { target: { scrollLeft: this._enableX ? -this._position : 0, scrollTop: this._enableY ? -this._position : 0, scrollHeight: this._scrollHeight || this._element.offsetHeight, scrollWidth: this._scrollWidth || this._element.offsetWidth, offsetHeight: this._element.parentElement.offsetHeight, offsetWidth: this._element.parentElement.offsetWidth, }, }; this._options.onScroll(e); } }; Scroller.prototype.update = function (e, t, n) { let i = 0; const r = this._position; if (this._enableX) { i = this._element.childNodes.length ? (t || this._element.offsetWidth) - this._element.parentElement.offsetWidth : 0; this._scrollWidth = t; } else { i = this._element.childNodes.length ? (t || this._element.offsetHeight) - this._element.parentElement.offsetHeight : 0; this._scrollHeight = t; } if (typeof e === 'number') { this._position = -e; } if (this._position < -i) { this._position = -i; } else { if (this._position > 0) { this._position = 0; } } this._itemSize = n || this._itemSize; this.updatePosition(); if (r !== this._position) { this.dispatchScroll(); if (typeof this._options.onSnap === 'function') { this._options.onSnap(Math.floor(Math.abs(this._position) / this._itemSize)); } } this._extent = i; this._scroll._extent = i; }; Scroller.prototype.updatePosition = function () { let transform = ''; if (this._enableX) { transform = `translateX(${this._position}px) translateZ(0)`; } else { if (this._enableY) { transform = `translateY(${this._position}px) translateZ(0)`; } } this._element.style.webkitTransform = transform; this._element.style.transform = transform; }; Scroller.prototype.isScrolling = function () { return this._scrolling || this._snapping; };