UNPKG

vue-hooks-plus

Version:
108 lines (107 loc) 3.76 kB
"use strict"; const vue = require("vue"); const useSize = require("../useSize"); const domTarget = require("../utils/domTarget"); const _interopDefaultLegacy = (e) => e && typeof e === "object" && "default" in e ? e : { default: e }; const useSize__default = /* @__PURE__ */ _interopDefaultLegacy(useSize); const useVirtualList = (list, options) => { const containerTarget = vue.ref(); const { wrapperTarget, itemHeight, overscan = 5 } = options; const size = useSize__default.default(containerTarget); const targetList = vue.ref([]); const scrollTriggerByScrollToFunc = vue.ref(false); const getVisibleCount = (containerHeight, fromIndex) => { if (typeof itemHeight === "number") { return Math.ceil(containerHeight / itemHeight); } let sum = 0; let endIndex = 0; for (let i = fromIndex; i < list.value.length; i++) { const height = itemHeight(i, list.value[i]); sum += height; endIndex = i; if (sum >= containerHeight) { break; } } return endIndex - fromIndex; }; const getOffset = (scrollTop) => { if (typeof itemHeight === "number") { return Math.floor(scrollTop / itemHeight) + 1; } let sum = 0; let offset = 0; for (let i = 0; i < list.value.length; i++) { const height = itemHeight(i, list.value[i]); sum += height; if (sum >= scrollTop) { offset = i; break; } } return offset + 1; }; const getDistanceTop = (index) => { var _a, _b; if (typeof itemHeight === "number") { const height2 = index * itemHeight; return height2; } const height = (_b = (_a = list.value) == null ? void 0 : _a.slice(0, index)) == null ? void 0 : _b.reduce((sum, _, i) => sum + (itemHeight == null ? void 0 : itemHeight(i, list == null ? void 0 : list.value[index])), 0); return height; }; const totalHeight = vue.computed(() => { if (typeof itemHeight === "number") { return list.value.length * itemHeight; } return list.value.reduce( (sum, _, index) => sum + (itemHeight == null ? void 0 : itemHeight(index, list == null ? void 0 : list.value[index])), 0 ); }); const calculateRange = () => { const container2 = domTarget.getTargetElement(containerTarget); const wrapper = domTarget.getTargetElement(wrapperTarget); if (container2 && wrapper) { const { scrollTop, clientHeight } = container2; const offset = getOffset(scrollTop); const visibleCount = getVisibleCount(clientHeight, offset); const start = Math.max(0, offset - overscan); const end = Math.min(list.value.length, offset + visibleCount + overscan); const offsetTop = getDistanceTop(start); wrapper.style.height = totalHeight.value - offsetTop + "px"; wrapper.style.marginTop = offsetTop + "px"; targetList.value = list.value.slice(start, end).map((ele, index) => ({ data: ele, index: index + start })); } }; vue.watch([size == null ? void 0 : size.width, size == null ? void 0 : size.height, list], () => { calculateRange(); }); const scrollTo = (index) => { const container2 = domTarget.getTargetElement(containerTarget); if (container2) { scrollTriggerByScrollToFunc.value = true; container2.scrollTop = getDistanceTop(index); calculateRange(); } }; const container = vue.reactive({ ref: (ele) => { containerTarget.value = ele; }, onScroll: (e) => { if (scrollTriggerByScrollToFunc.value) { scrollTriggerByScrollToFunc.value = false; return; } e.preventDefault(); calculateRange(); } }); return [targetList, container, scrollTo]; }; module.exports = useVirtualList;