UNPKG

v3-virtual-scroll

Version:
172 lines (171 loc) 5.73 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; import { defineComponent, ref, computed, onUnmounted, onActivated, nextTick, openBlock, createElementBlock, unref, normalizeStyle, createElementVNode, Fragment, renderList, renderSlot } from "vue"; function debound(fn, t) { let timer = null; return (...args) => { if (timer) { return; } timer = setTimeout(() => { fn(...args); timer = null; }, t); }; } class Loader { constructor(options = {}) { __publicField(this, "isLoading", false); __publicField(this, "loadCbs", []); __publicField(this, "doneCbs", []); __publicField(this, "load", () => { this.isLoading = true; this.doLoad(); }); __publicField(this, "done", () => { this.isLoading = false; this.doDone(); }); __publicField(this, "onLoad", (cb) => { this.loadCbs.push(cb); }); __publicField(this, "onDone", (cb) => { this.doneCbs.push(cb); }); __publicField(this, "doLoad", () => { this.loadCbs.forEach((cb) => { cb(); }); }); __publicField(this, "doDone", () => { this.doneCbs.forEach((cb) => { cb(); }); }); this.init(options); } init(options) { const { isLoading, loadCbs, doneCbs } = options; if (isLoading) { this.isLoading = isLoading; } if (loadCbs) { this.loadCbs.push(...loadCbs); } if (doneCbs) { this.loadCbs.push(...doneCbs); } } } var Index_vue_vue_type_style_index_0_scoped_true_lang = ""; var _export_sfc = (sfc, props) => { const target = sfc.__vccOpts || sfc; for (const [key, val] of props) { target[key] = val; } return target; }; const _sfc_main = /* @__PURE__ */ defineComponent({ props: { list: { default: () => [] }, key: { default: "id" }, height: { default: window.screen.height }, itemHeight: { default: 0 }, startOffset: { default: 0 }, endOffset: { default: 0 } }, emits: ["onTouchEnd", "onTouchTop"], setup(__props, { emit: emits }) { const props = __props; let scrollTop = ref(0); let scrollContainer = ref(null); const count = computed(() => ~~(props.height / props.itemHeight) + 2); const lastIndex = computed(() => props.list.length - 1); const _startIndex = computed(() => ~~(scrollTop.value / props.itemHeight)); const _endIndex = computed(() => Math.min(_startIndex.value + count.value, lastIndex.value)); const startOffset = computed(() => props.startOffset || count.value); const endOffset = computed(() => props.endOffset || count.value); const startIndex = computed(() => { let start = _startIndex.value - startOffset.value; return start < 0 ? 0 : start; }); const endIndex = computed(() => { let end = _endIndex.value + endOffset.value; return end > lastIndex.value ? lastIndex.value : end; }); const renderList$1 = computed(() => props.list.slice(startIndex.value, endIndex.value)); const containerStyle = computed(() => ({ height: props.height + "px" })); const wrapperStyle = computed(() => { return { paddingTop: startIndex.value * props.itemHeight + "px", paddingBottom: (lastIndex.value - endIndex.value) * props.itemHeight + "px" }; }); const topLoader = new Loader(); const bottomLoader = new Loader(); let curListLength = 0; topLoader.onLoad(() => { curListLength = props.list.length; }); topLoader.onDone(() => { const { itemHeight, list } = props; const scrollHeigt = (list.length - curListLength) * itemHeight; setScroll(scrollHeigt); }); const onScoll = debound((e) => { scrollTop.value = e.target.scrollTop; handleScroll(); }, 30); function setScroll(value) { const container = scrollContainer.value; container.scrollTop = value; } function handleScroll() { if (scrollTop.value === 0 && !topLoader.isLoading) { topLoader.load(); emits("onTouchTop", topLoader.done); return; } if (endIndex.value >= lastIndex.value && !bottomLoader.isLoading) { bottomLoader.load(); emits("onTouchEnd", bottomLoader.done); } } onUnmounted(() => { document.removeEventListener("scroll", onScoll); }); onActivated(() => { nextTick(() => { setScroll(scrollTop.value); }); }); return (_ctx, _cache) => { return openBlock(), createElementBlock("div", { class: "virtual-container", onScroll: _cache[0] || (_cache[0] = (...args) => unref(onScoll) && unref(onScoll)(...args)), style: normalizeStyle(unref(containerStyle)), ref_key: "scrollContainer", ref: scrollContainer }, [ createElementVNode("div", { class: "virtual-container__wrapper", style: normalizeStyle(unref(wrapperStyle)) }, [ (openBlock(true), createElementBlock(Fragment, null, renderList(unref(renderList$1), (item) => { return openBlock(), createElementBlock("div", { key: item[__props.key] }, [ renderSlot(_ctx.$slots, "default", { item }, void 0, true) ]); }), 128)) ], 4) ], 36); }; } }); var V3VirtualScroll = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-d5797efa"]]); export { V3VirtualScroll, V3VirtualScroll as default };