UNPKG

@arco-design/web-vue

Version:

Arco Design Vue 2.0: A Vue.js 3 UI Library

216 lines (215 loc) 6.42 kB
import { defineComponent, toRefs, computed, ref, nextTick, resolveComponent, openBlock, createBlock, resolveDynamicComponent, normalizeClass, normalizeStyle, withCtx, mergeProps, createElementBlock, Fragment, renderList, renderSlot } from "vue"; import { useSize } from "./hooks/use-size.js"; import VirtualListItem from "./virtual-list-item.js"; import { getPrefixCls } from "../../_utils/global-config.js"; import { isObject, isNumber } from "../../_utils/is.js"; import _export_sfc from "../../_virtual/plugin-vue_export-helper.js"; const _sfc_main = defineComponent({ name: "VirtualList", components: { VirtualListItem }, props: { height: { type: [Number, String], default: 200 }, data: { type: Array, default: () => [] }, threshold: { type: Number, default: 0 }, itemKey: { type: String, default: "key" }, fixedSize: { type: Boolean, default: false }, estimatedSize: { type: Number, default: 30 }, buffer: { type: Number, default: 10 }, component: { type: [String, Object], default: "div" }, listAttrs: { type: Object }, contentAttrs: { type: Object }, paddingPosition: { type: String, default: "content" } }, emits: { scroll: (ev) => true, reachBottom: (ev) => true }, setup(props, { emit }) { const { data, itemKey, fixedSize, estimatedSize, buffer, height } = toRefs(props); const prefixCls = getPrefixCls("virtual-list"); const mergedComponent = computed(() => { if (isObject(props.component)) { return { container: "div", list: "div", content: "div", ...props.component }; } return { container: props.component, list: "div", content: "div" }; }); const containerRef = ref(); const contentRef = ref(); const style = computed(() => { return { height: isNumber(height.value) ? `${height.value}px` : height.value, overflow: "auto" }; }); const dataKeys = computed( () => data.value.map((item, index) => { var _a; return (_a = item[itemKey.value]) != null ? _a : index; }) ); const { frontPadding, behindPadding, start, end, getStartByScroll, setItemSize, hasItemSize, setStart, getScrollOffset } = useSize({ dataKeys, contentRef, fixedSize, estimatedSize, buffer }); const currentList = computed(() => { if (props.threshold && data.value.length <= props.threshold) { return data.value; } return data.value.slice(start.value, end.value); }); const onScroll = (ev) => { const { scrollTop, scrollHeight, offsetHeight } = ev.target; const _start = getStartByScroll(scrollTop); if (_start !== start.value) { setStart(_start); nextTick(() => { scrollTo(scrollTop); }); } emit("scroll", ev); const bottom = Math.floor(scrollHeight - (scrollTop + offsetHeight)); if (bottom <= 0) { emit("reachBottom", ev); } }; const scrollTo = (options) => { var _a, _b; if (containerRef.value) { if (isNumber(options)) { containerRef.value.scrollTop = options; } else { const _index = (_b = options.index) != null ? _b : dataKeys.value.indexOf((_a = options.key) != null ? _a : ""); setStart(_index - buffer.value); containerRef.value.scrollTop = getScrollOffset(_index); nextTick(() => { if (containerRef.value) { const _scrollTop = getScrollOffset(_index); if (_scrollTop !== containerRef.value.scrollTop) { containerRef.value.scrollTop = _scrollTop; } } }); } } }; return { prefixCls, containerRef, contentRef, frontPadding, currentList, behindPadding, onScroll, setItemSize, hasItemSize, start, scrollTo, style, mergedComponent }; } }); function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { const _component_VirtualListItem = resolveComponent("VirtualListItem"); return openBlock(), createBlock(resolveDynamicComponent(_ctx.mergedComponent.container), { ref: "containerRef", class: normalizeClass(_ctx.prefixCls), style: normalizeStyle(_ctx.style), onScroll: _ctx.onScroll }, { default: withCtx(() => [ (openBlock(), createBlock(resolveDynamicComponent(_ctx.mergedComponent.list), mergeProps(_ctx.listAttrs, { style: _ctx.paddingPosition === "list" ? { paddingTop: `${_ctx.frontPadding}px`, paddingBottom: `${_ctx.behindPadding}px` } : {} }), { default: withCtx(() => [ (openBlock(), createBlock(resolveDynamicComponent(_ctx.mergedComponent.content), mergeProps({ ref: "contentRef" }, _ctx.contentAttrs, { style: _ctx.paddingPosition === "content" ? { paddingTop: `${_ctx.frontPadding}px`, paddingBottom: `${_ctx.behindPadding}px` } : {} }), { default: withCtx(() => [ (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.currentList, (item, index) => { var _a; return openBlock(), createBlock(_component_VirtualListItem, { key: (_a = item[_ctx.itemKey]) != null ? _a : _ctx.start + index, "has-item-size": _ctx.hasItemSize, "set-item-size": _ctx.setItemSize }, { default: withCtx(() => [ renderSlot(_ctx.$slots, "item", { item, index: _ctx.start + index }) ]), _: 2 }, 1032, ["has-item-size", "set-item-size"]); }), 128)) ]), _: 3 }, 16, ["style"])) ]), _: 3 }, 16, ["style"])) ]), _: 3 }, 40, ["class", "style", "onScroll"]); } var VirtualList = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]); export { VirtualList as default };