UNPKG

@z-cloud/virtual-taro

Version:

一个基于React + TS开发的虚拟列表,支持瀑布流、grid的组件。

135 lines (134 loc) 4.83 kB
import { jsx, jsxs } from "react/jsx-runtime"; import { useVirualizer, useIsomorphicLayoutEffect } from "../hooks/use-virtualizer.js"; import { ScrollView, View } from "@tarojs/components"; import { virtualizerUUID, getWindowRect, getRectSizeAsync, getScrollViewContextNode } from "../utils/index.js"; import Taro, { usePageScroll } from "@tarojs/taro"; import { Resizable } from "./resizable.js"; import { useState } from "react"; function NormalVirtualList({ children, className, itemClassName, style, itemStyle, dynamicSize = false, scrollViewProps, onReady, ...props }) { const [scrollId] = useState(() => `zcloud-virtual-list-${virtualizerUUID.value++}`); const virtualizer = useVirualizer(props); const { lanes = 1, horizontal } = props; const totalSize = virtualizer.getTotalSize(); let gridTemplateAreas = Array.from( { length: lanes }, (_, index) => horizontal ? `"lane${index}"` : `lane${index}` ).join(" "); if (!horizontal) { gridTemplateAreas = `"${gridTemplateAreas}"`; } usePageScroll((e) => { virtualizer.onScroll(e); }); const onScroll = (e) => { var _a; virtualizer.onScroll(e.detail); (_a = scrollViewProps == null ? void 0 : scrollViewProps.onScroll) == null ? void 0 : _a.call(scrollViewProps, e); }; const init = async () => { const windowRect = getWindowRect(); const elementRect = await getRectSizeAsync(scrollId); const scrollNode = await getScrollViewContextNode(scrollId); virtualizer.setScrollElementRect(props.followPageScroll ? windowRect : elementRect); virtualizer.scrollTo = (offset, behavior) => { if (!scrollNode) { console.warn("获取scrollNode失败"); return; } scrollNode.scrollTo({ [props.horizontal ? "left" : "top"]: offset, animated: dynamicSize ? false : behavior === "smooth" }); }; if (props.followPageScroll) { virtualizer.options.scrollMargin = elementRect.top ?? 0; virtualizer.scrollTo = (offset, behavior) => { Taro.pageScrollTo({ scrollTop: offset, // 动态尺寸不支持滚动动画 小程序都不建议使用动画 duration: behavior === "smooth" && !dynamicSize ? 300 : 0 }); }; } virtualizer.init(); onReady == null ? void 0 : onReady(virtualizer); }; useIsomorphicLayoutEffect(() => { init(); return () => virtualizer.clean(); }, [virtualizer]); return /* @__PURE__ */ jsx( ScrollView, { ...scrollViewProps, scrollX: horizontal, scrollY: !horizontal, enhanced: true, className, style: { overflow: "auto", ...style }, id: scrollId, onScroll, children: /* @__PURE__ */ jsx( View, { style: { display: "grid", gridTemplateAreas, gridTemplateColumns: `repeat(${horizontal ? 1 : lanes}, 1fr)`, gridTemplateRows: `repeat(${horizontal ? lanes : 1}, 1fr)`, alignItems: dynamicSize && !horizontal ? "start" : "stretch", justifyItems: dynamicSize && horizontal ? "start" : "stretch", columnGap: horizontal ? void 0 : props.gap, rowGap: horizontal ? props.gap : void 0, height: props.horizontal ? "100%" : totalSize, width: props.horizontal ? totalSize : "100%" }, children: virtualizer.getVirtualItems().map((virtualItem) => /* @__PURE__ */ jsxs( View, { className: itemClassName, "data-index": virtualItem.index, style: { ...itemStyle, gridArea: `lane${virtualItem.lane}`, height: horizontal || dynamicSize ? void 0 : virtualItem.size, width: !horizontal || dynamicSize ? void 0 : virtualItem.size, transform: props.horizontal ? `translateX(${virtualItem.start}px)` : `translateY(${virtualItem.start - (props.followPageScroll ? virtualizer.options.scrollMargin ?? 0 : 0)}px)` }, children: [ dynamicSize && /* @__PURE__ */ jsx( Resizable, { emitWhenMounted: true, listId: `${scrollId}-${virtualItem.index}`, style: { width: "100%" }, onResize: (res) => virtualizer.onElementSizeChange(virtualItem.index, { width: res.width, height: res.height }), children: children(virtualItem) } ), !dynamicSize && children(virtualItem) ] }, virtualItem.index )) } ) } ); } export { NormalVirtualList };