virtual-seamless-scrolling
Version:
vue虚拟滚无缝动组件
409 lines (408 loc) • 11.4 kB
JavaScript
import { getCurrentScope as oe, onScopeDispose as se, unref as q, ref as y, watch as x, computed as b, getCurrentInstance as le, onMounted as G, defineComponent as U, reactive as ae, onBeforeUnmount as ue, openBlock as w, createElementBlock as S, createElementVNode as F, normalizeStyle as E, Fragment as V, renderList as W, renderSlot as P, nextTick as ce, toDisplayString as fe } from "vue";
function $(e) {
return oe() ? (se(e), !0) : !1;
}
function L(e) {
return typeof e == "function" ? e() : q(e);
}
const J = typeof window < "u" && typeof document < "u";
typeof WorkerGlobalScope < "u" && globalThis instanceof WorkerGlobalScope;
const de = (e) => e != null, ve = Object.prototype.toString, me = (e) => ve.call(e) === "[object Object]", H = () => {
};
function pe(e, o) {
function n(...r) {
return new Promise((s, i) => {
Promise.resolve(e(() => o.apply(this, r), { fn: o, thisArg: this, args: r })).then(s).catch(i);
});
}
return n;
}
function he(e, o = {}) {
let n, r, s = H;
const i = (l) => {
clearTimeout(l), s(), s = H;
};
return (l) => {
const f = L(e), t = L(o.maxWait);
return n && i(n), f <= 0 || t !== void 0 && t <= 0 ? (r && (i(r), r = null), Promise.resolve(l())) : new Promise((a, c) => {
s = o.rejectOnCancel ? c : a, t && !r && (r = setTimeout(() => {
n && i(n), r = null, a(l());
}, t)), n = setTimeout(() => {
r && i(r), r = null, a(l());
}, f);
});
};
}
function ye(e, o = 200, n = {}) {
return pe(
he(o, n),
e
);
}
function A(e) {
var o;
const n = L(e);
return (o = n == null ? void 0 : n.$el) != null ? o : n;
}
const O = J ? window : void 0, ge = J ? window.document : void 0;
function be(...e) {
let o, n, r, s;
if (typeof e[0] == "string" || Array.isArray(e[0]) ? ([n, r, s] = e, o = O) : [o, n, r, s] = e, !o)
return H;
Array.isArray(n) || (n = [n]), Array.isArray(r) || (r = [r]);
const i = [], v = () => {
i.forEach((a) => a()), i.length = 0;
}, l = (a, c, p, h) => (a.addEventListener(c, p, h), () => a.removeEventListener(c, p, h)), f = x(
() => [A(o), L(s)],
([a, c]) => {
if (v(), !a)
return;
const p = me(c) ? { ...c } : c;
i.push(
...n.flatMap((h) => r.map((g) => l(a, h, g, p)))
);
},
{ immediate: !0, flush: "post" }
), t = () => {
f(), v();
};
return $(t), t;
}
function we() {
const e = y(!1), o = le();
return o && G(() => {
e.value = !0;
}, o), e;
}
function Q(e) {
const o = we();
return b(() => (o.value, !!e()));
}
function Se(e = {}) {
const { document: o = ge } = e;
if (!o)
return y("visible");
const n = y(o.visibilityState);
return be(o, "visibilitychange", () => {
n.value = o.visibilityState;
}), n;
}
function xe(e, o, n = {}) {
const { window: r = O, ...s } = n;
let i;
const v = Q(() => r && "ResizeObserver" in r), l = () => {
i && (i.disconnect(), i = void 0);
}, f = b(() => Array.isArray(e) ? e.map((c) => A(c)) : [A(e)]), t = x(
f,
(c) => {
if (l(), v.value && r) {
i = new ResizeObserver(o);
for (const p of c)
p && i.observe(p, s);
}
},
{ immediate: !0, flush: "post" }
), a = () => {
l(), t();
};
return $(a), {
isSupported: v,
stop: a
};
}
function Te(e, o, n = {}) {
const {
root: r,
rootMargin: s = "0px",
threshold: i = 0.1,
window: v = O,
immediate: l = !0
} = n, f = Q(() => v && "IntersectionObserver" in v), t = b(() => {
const g = L(e);
return (Array.isArray(g) ? g : [g]).map(A).filter(de);
});
let a = H;
const c = y(l), p = f.value ? x(
() => [t.value, A(r), c.value],
([g, C]) => {
if (a(), !c.value || !g.length)
return;
const I = new IntersectionObserver(
o,
{
root: A(C),
rootMargin: s,
threshold: i
}
);
g.forEach((T) => T && I.observe(T)), a = () => {
I.disconnect(), a = H;
};
},
{ immediate: l, flush: "post" }
) : H, h = () => {
a(), p(), c.value = !1;
};
return $(h), {
isSupported: f,
isActive: c,
pause() {
a(), c.value = !1;
},
resume() {
c.value = !0;
},
stop: h
};
}
function _e(e, o = {}) {
const { window: n = O, scrollTarget: r, threshold: s = 0 } = o, i = y(!1);
return Te(
e,
(v) => {
let l = i.value, f = 0;
for (const t of v)
t.time >= f && (f = t.time, l = t.isIntersecting);
i.value = l;
},
{
root: r,
window: n,
threshold: s
}
), i;
}
const He = /* @__PURE__ */ U({
__name: "index",
props: {
// 从data-sources中的每个数据对象获取唯一键。或者使用每个数据源调用函数并返回其唯一键。其值在数据源中必须是唯一的,用于标识每一项的尺寸。
dataKey: {
type: String,
required: !0,
default: "id"
},
// 是否加载中
loading: {
type: Boolean,
required: !0
},
// 为列表生成的源数组,每个数组数据必须是一个对象,并且具有唯一的key get或generate fordata key属性。
dataSource: {
type: Array,
required: !0
},
// 单个滚动完成的停留间隔 单位毫秒
interval: {
type: Number,
required: !1,
default: 0
},
// 是否刷新数据 在数据源更新后按着新数据渲染 默认 false: 数据源更改后会累加数据 为 true则不会累加
refresh: {
type: Boolean,
default: !1
}
},
emits: ["scroll-end", "line-scroll-end"],
setup(e, { emit: o }) {
const n = e, r = o, s = y([]), i = y(), v = y(), l = y(), f = y([]), t = ae({
viewHeight: 0,
itemHeight: 0,
startIndex: 0,
maxCount: 1,
preLen: 0,
rafTimer: null,
isHover: !1
});
let a;
function c(u) {
var _;
cancelAnimationFrame(t.rafTimer || 0);
function m() {
t.rafTimer = requestAnimationFrame(u);
}
const d = ((_ = i.value) == null ? void 0 : _.scrollTop) || 0;
if (n.interval > 0 && d > 0 && d % t.itemHeight === 0) {
r("line-scroll-end"), clearTimeout(a), a = setTimeout(() => {
t.rafTimer = requestAnimationFrame(m);
}, n.interval);
return;
}
t.rafTimer = requestAnimationFrame(m);
}
const p = b(() => Math.min(s.value.length, t.startIndex + t.maxCount)), h = b(() => s.value.slice(t.startIndex, p.value)), g = b(() => s.value.length < t.maxCount - 1 ? [] : s.value.slice(0, t.maxCount)), C = b(
() => ({
height: `${t.itemHeight * h.value.length}px`,
transform: `translate3d(0, ${t.itemHeight * t.startIndex}px, 0)`
})
), I = b(
() => ({
transform: `translate3d(0, ${t.itemHeight * t.startIndex}px, 0)`
})
), T = () => {
if (!t.isHover) {
if (n.loading) {
M();
return;
}
if (i.value) {
let u = i.value.scrollTop;
f.value.length && u >= f.value[f.value.length - 1].bottom ? (u = 0, n.loading || r("scroll-end")) : u += 1, i.value.scrollTop = u;
}
c(T);
}
}, M = () => {
t.rafTimer !== null && window.cancelAnimationFrame(t.rafTimer);
}, R = () => {
t.isHover = !0, M();
}, k = () => {
t.isHover = !1, T();
}, Y = () => {
M();
};
function Z(u) {
let m = !1;
return function(...d) {
m || (m = !0, window.requestAnimationFrame(() => {
u.apply(this, d), m = !1;
}));
};
}
const D = Z(() => {
if (!i.value)
return;
let { scrollTop: u } = i.value;
t.startIndex = Math.floor(u / t.itemHeight), h.value.length === 0 && (i.value.scrollTop = 0, n.loading || r("scroll-end"));
}), ee = () => {
t.viewHeight = i.value ? i.value.offsetHeight : 0;
}, te = () => {
n.refresh && (t.preLen = 0, s.value = []);
const u = n.dataSource.length - t.preLen;
for (let m = 0; m < u; m++) {
const d = m + t.preLen;
s.value.push(n.dataSource[d]);
}
t.preLen = s.value.length;
}, j = ye(() => {
t.viewHeight = i.value ? i.value.offsetHeight : 0, ce(() => {
if (l.value && l.value[0]) {
const u = Math.ceil(t.viewHeight / l.value[0].offsetHeight) + 1;
if (isNaN(u))
return;
t.maxCount = Math.ceil(t.viewHeight / l.value[0].offsetHeight) + 1, t.itemHeight = l.value[0].offsetHeight;
}
});
}, 300), ne = () => {
i.value && xe(i, () => {
j();
});
};
G(() => {
ne(), ee();
}), x(
() => n.dataSource.length,
() => {
te(), j();
},
{
immediate: !0
}
), x(
() => n.loading,
(u) => {
u || T();
},
{
immediate: !0
}
);
const B = y(), re = _e(B);
let N = !1;
x(re, (u) => {
if (!N) {
N = !0;
return;
}
u ? k() : R();
});
const ie = Se();
return x(ie, (u) => {
u === "hidden" ? R() : k();
}), ue(M), (u, m) => (w(), S("div", {
class: "fs-estimated-virtuallist-container",
ref_key: "containerRef",
ref: B
}, [
F("div", {
class: "fs-estimated-virtuallist-content",
ref_key: "contentRef",
ref: i,
onMouseleave: k,
onMouseenter: R,
onMouseover: Y,
onScroll: m[0] || (m[0] = //@ts-ignore
(...d) => q(D) && q(D)(...d))
}, [
F("div", {
class: "fs-estimated-virtuallist-list",
ref_key: "listRef",
ref: v,
style: E(C.value)
}, [
(w(!0), S(V, null, W(h.value, (d, _) => (w(), S("div", {
class: "fs-estimated-virtuallist-list-item",
ref_for: !0,
ref_key: "itemRef",
ref: l,
key: d[e.dataKey] || _
}, [
P(u.$slots, "item", { item: d }, void 0, !0)
]))), 128))
], 4),
F("div", {
class: "fs-estimated-virtuallist-list",
style: E(I.value)
}, [
(w(!0), S(V, null, W(g.value, (d, _) => (w(), S("div", {
class: "fs-estimated-virtuallist-list-item",
key: d[e.dataKey] || _
}, [
P(u.$slots, "item", { item: d }, void 0, !0)
]))), 128))
], 4)
], 544)
], 512));
}
}), X = (e, o) => {
const n = e.__vccOpts || e;
for (const [r, s] of o)
n[r] = s;
return n;
}, z = /* @__PURE__ */ X(He, [["__scopeId", "data-v-de36a4ed"]]), Ae = { class: "list-header" }, Le = /* @__PURE__ */ U({
__name: "index",
props: {
titleList: {
type: Array,
required: !0
}
},
setup(e) {
return (o, n) => (w(), S("div", Ae, [
(w(!0), S(V, null, W(e.titleList, (r) => (w(), S("div", {
class: "list-header-title",
key: r.label,
style: E({ width: r.width })
}, fe(r.label), 5))), 128))
]));
}
}), K = /* @__PURE__ */ X(Le, [["__scopeId", "data-v-7f80261f"]]);
z.install = function(e) {
e.component("VirtualListScroll", z);
};
K.install = function(e) {
e.component("ListHeader", K);
};
export {
K as ListHeader,
z as VirtualListScroll
};