@tarojs/components-advanced 4.1.12-beta.2 → 4.1.12-beta.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/components/index.js +2 -0
  2. package/dist/components/index.js.map +1 -1
  3. package/dist/components/list/NoMore.d.ts +30 -0
  4. package/dist/components/list/NoMore.js +10 -0
  5. package/dist/components/list/NoMore.js.map +1 -0
  6. package/dist/components/list/hooks/useItemSizeCache.d.ts +13 -0
  7. package/dist/components/list/hooks/useItemSizeCache.js +40 -0
  8. package/dist/components/list/hooks/useItemSizeCache.js.map +1 -0
  9. package/dist/components/list/hooks/useListNestedScroll.d.ts +18 -0
  10. package/dist/components/list/hooks/useListNestedScroll.js +61 -0
  11. package/dist/components/list/hooks/useListNestedScroll.js.map +1 -0
  12. package/dist/components/list/hooks/useListScrollElementAttach.d.ts +25 -0
  13. package/dist/components/list/hooks/useListScrollElementAttach.js +88 -0
  14. package/dist/components/list/hooks/useListScrollElementAttach.js.map +1 -0
  15. package/dist/components/list/hooks/useListScrollElementAttachWeapp.d.ts +27 -0
  16. package/dist/components/list/hooks/useListScrollElementAttachWeapp.js +153 -0
  17. package/dist/components/list/hooks/useListScrollElementAttachWeapp.js.map +1 -0
  18. package/dist/components/list/hooks/useMeasureStartOffset.d.ts +12 -0
  19. package/dist/components/list/hooks/useMeasureStartOffset.js +84 -0
  20. package/dist/components/list/hooks/useMeasureStartOffset.js.map +1 -0
  21. package/dist/components/list/hooks/useMeasureStartOffsetWeapp.d.ts +13 -0
  22. package/dist/components/list/hooks/useMeasureStartOffsetWeapp.js +85 -0
  23. package/dist/components/list/hooks/useMeasureStartOffsetWeapp.js.map +1 -0
  24. package/dist/components/list/hooks/useRefresher.d.ts +74 -0
  25. package/dist/components/list/hooks/useRefresher.js +503 -0
  26. package/dist/components/list/hooks/useRefresher.js.map +1 -0
  27. package/dist/components/list/hooks/useResizeObserver.d.ts +26 -0
  28. package/dist/components/list/hooks/useResizeObserver.js +152 -0
  29. package/dist/components/list/hooks/useResizeObserver.js.map +1 -0
  30. package/dist/components/list/hooks/useScrollCorrection.d.ts +19 -0
  31. package/dist/components/list/hooks/useScrollCorrection.js +73 -0
  32. package/dist/components/list/hooks/useScrollCorrection.js.map +1 -0
  33. package/dist/components/list/hooks/useScrollParentAutoFind.d.ts +20 -0
  34. package/dist/components/list/hooks/useScrollParentAutoFind.js +81 -0
  35. package/dist/components/list/hooks/useScrollParentAutoFind.js.map +1 -0
  36. package/dist/components/list/index.d.ts +64 -7
  37. package/dist/components/list/index.js +1041 -162
  38. package/dist/components/list/index.js.map +1 -1
  39. package/dist/components/list/utils.d.ts +16 -0
  40. package/dist/components/list/utils.js +19 -0
  41. package/dist/components/list/utils.js.map +1 -0
  42. package/dist/components/virtual-list/vue/list.d.ts +12 -12
  43. package/dist/components/virtual-waterfall/vue/waterfall.d.ts +11 -11
  44. package/dist/components/water-flow/flow-item.js +6 -4
  45. package/dist/components/water-flow/flow-item.js.map +1 -1
  46. package/dist/components/water-flow/flow-section.js +1 -1
  47. package/dist/components/water-flow/flow-section.js.map +1 -1
  48. package/dist/components/water-flow/index.d.ts +1 -1
  49. package/dist/components/water-flow/interface.d.ts +18 -2
  50. package/dist/components/water-flow/root.d.ts +35 -4
  51. package/dist/components/water-flow/root.js +114 -42
  52. package/dist/components/water-flow/root.js.map +1 -1
  53. package/dist/components/water-flow/section.d.ts +7 -1
  54. package/dist/components/water-flow/section.js +54 -9
  55. package/dist/components/water-flow/section.js.map +1 -1
  56. package/dist/components/water-flow/utils.d.ts +4 -0
  57. package/dist/components/water-flow/utils.js +5 -1
  58. package/dist/components/water-flow/utils.js.map +1 -1
  59. package/dist/components/water-flow/water-flow-node-cache.d.ts +24 -0
  60. package/dist/components/water-flow/water-flow-node-cache.js +161 -0
  61. package/dist/components/water-flow/water-flow-node-cache.js.map +1 -0
  62. package/dist/components/water-flow/water-flow.d.ts +2 -3
  63. package/dist/components/water-flow/water-flow.js +286 -31
  64. package/dist/components/water-flow/water-flow.js.map +1 -1
  65. package/dist/index.js +3 -0
  66. package/dist/index.js.map +1 -1
  67. package/dist/utils/index.d.ts +1 -0
  68. package/dist/utils/index.js +1 -0
  69. package/dist/utils/index.js.map +1 -1
  70. package/dist/utils/scrollElementContext.d.ts +15 -0
  71. package/dist/utils/scrollElementContext.js +14 -0
  72. package/dist/utils/scrollElementContext.js.map +1 -0
  73. package/dist/utils/scrollParent.d.ts +33 -0
  74. package/dist/utils/scrollParent.js +88 -0
  75. package/dist/utils/scrollParent.js.map +1 -0
  76. package/package.json +9 -8
@@ -0,0 +1,152 @@
1
+ import Taro from '@tarojs/taro';
2
+ import { useRef, useCallback, useEffect } from 'react';
3
+ import { isH5, isMiniProgram } from '../utils.js';
4
+
5
+ function useResizeObserver(options) {
6
+ const { enabled, isHorizontal, listId, onResize } = options;
7
+ // H5: ResizeObserver 实例
8
+ const observerRef = useRef(null);
9
+ // 小程序: IntersectionObserver 实例 Map
10
+ const intersectionObserversRef = useRef(new Map());
11
+ // 已观察的元素 Map(用于去重)
12
+ const observedElementsRef = useRef(new Map());
13
+ /**
14
+ * H5 实现:使用 ResizeObserver
15
+ */
16
+ const observeH5 = useCallback((element, index) => {
17
+ if (!element || !enabled)
18
+ return;
19
+ // 避免重复观察
20
+ if (observedElementsRef.current.has(index))
21
+ return;
22
+ // 创建 ResizeObserver(懒加载)
23
+ if (!observerRef.current) {
24
+ observerRef.current = new ResizeObserver((entries) => {
25
+ entries.forEach((entry) => {
26
+ const idx = Number(entry.target.getAttribute('data-index'));
27
+ if (isNaN(idx))
28
+ return;
29
+ const size = isHorizontal
30
+ ? entry.contentRect.width
31
+ : entry.contentRect.height;
32
+ onResize(idx, size);
33
+ });
34
+ });
35
+ }
36
+ // 设置 data-index 属性
37
+ element.setAttribute('data-index', String(index));
38
+ // 开始观察
39
+ observerRef.current.observe(element);
40
+ observedElementsRef.current.set(index, element);
41
+ }, [enabled, isHorizontal, onResize]);
42
+ /**
43
+ * 小程序实现:使用 IntersectionObserver + SelectorQuery
44
+ * 使用唯一 id 选择器,避免多 List 并存时误命中(index>=0 为 item,index<0 为 header)
45
+ * 使用 Taro.nextTick 延后 observe,确保 setData 已提交、节点已挂载,避免 "Node is not found" 报错
46
+ */
47
+ const observeMiniProgram = useCallback((_element, index) => {
48
+ if (!enabled)
49
+ return;
50
+ // 避免重复观察
51
+ if (intersectionObserversRef.current.has(index))
52
+ return;
53
+ const selector = index >= 0
54
+ ? `#${listId}-list-item-inner-${index}`
55
+ : `#${listId}-list-header-inner-${-index - 1}`;
56
+ const doObserve = () => {
57
+ try {
58
+ // 创建 IntersectionObserver
59
+ const observer = Taro.createIntersectionObserver(Taro.getCurrentInstance().page, {
60
+ observeAll: true
61
+ });
62
+ // 相对于 List 容器
63
+ observer.relativeTo(`#${listId}`);
64
+ // 观察元素进入可见区域(唯一 id 避免跨 List 误命中)
65
+ observer.observe(selector, (res) => {
66
+ if (res.intersectionRatio > 0) {
67
+ Taro.createSelectorQuery()
68
+ .select(selector)
69
+ .boundingClientRect((rect) => {
70
+ if (rect) {
71
+ const size = isHorizontal ? rect.width : rect.height;
72
+ onResize(index, size);
73
+ }
74
+ })
75
+ .exec();
76
+ }
77
+ });
78
+ intersectionObserversRef.current.set(index, observer);
79
+ }
80
+ catch (_a) {
81
+ // ignore observe failure
82
+ }
83
+ };
84
+ Taro.nextTick(doObserve);
85
+ }, [enabled, isHorizontal, listId, onResize]);
86
+ /**
87
+ * 观察元素(平台自动适配)
88
+ */
89
+ const observe = useCallback((element, index) => {
90
+ if (!enabled)
91
+ return;
92
+ if (isH5) {
93
+ observeH5(element, index);
94
+ }
95
+ else if (isMiniProgram) {
96
+ observeMiniProgram(element, index);
97
+ }
98
+ }, [enabled, observeH5, observeMiniProgram]);
99
+ /**
100
+ * 取消观察元素
101
+ */
102
+ const unobserve = useCallback((element) => {
103
+ if (!element)
104
+ return;
105
+ const index = Number(element.getAttribute('data-index'));
106
+ if (isNaN(index))
107
+ return;
108
+ if (isH5 && observerRef.current) {
109
+ observerRef.current.unobserve(element);
110
+ observedElementsRef.current.delete(index);
111
+ }
112
+ else if (isMiniProgram) {
113
+ const observer = intersectionObserversRef.current.get(index);
114
+ if (observer) {
115
+ observer.disconnect();
116
+ intersectionObserversRef.current.delete(index);
117
+ }
118
+ }
119
+ }, []);
120
+ /**
121
+ * 断开所有观察
122
+ */
123
+ const disconnect = useCallback(() => {
124
+ if (isH5 && observerRef.current) {
125
+ observerRef.current.disconnect();
126
+ observerRef.current = null;
127
+ observedElementsRef.current.clear();
128
+ }
129
+ else if (isMiniProgram) {
130
+ intersectionObserversRef.current.forEach((observer) => {
131
+ observer.disconnect();
132
+ });
133
+ intersectionObserversRef.current.clear();
134
+ }
135
+ }, []);
136
+ /**
137
+ * 组件卸载时清理
138
+ */
139
+ useEffect(() => {
140
+ return () => {
141
+ disconnect();
142
+ };
143
+ }, [disconnect]);
144
+ return {
145
+ observe,
146
+ unobserve,
147
+ disconnect
148
+ };
149
+ }
150
+
151
+ export { useResizeObserver };
152
+ //# sourceMappingURL=useResizeObserver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useResizeObserver.js","sources":["../../../../src/components/list/hooks/useResizeObserver.ts"],"sourcesContent":["import Taro from '@tarojs/taro'\nimport { useCallback, useEffect, useRef } from 'react'\n\nimport { isH5, isMiniProgram } from '../utils'\n\n/**\n * useResizeObserver Hook - 尺寸变化监听(平台适配)\n *\n * H5: 使用 ResizeObserver API\n * 小程序: 使用 IntersectionObserver + SelectorQuery\n */\n\ninterface UseResizeObserverOptions {\n /** 是否启用监听 */\n enabled: boolean\n\n /** 是否水平滚动(监听 width 还是 height) */\n isHorizontal: boolean\n\n /** List 容器 ID(小程序用于 SelectorQuery) */\n listId: string\n\n /** 尺寸变化回调 */\n onResize: (index: number, size: number) => void\n}\n\ninterface UseResizeObserverReturn {\n /** 观察指定元素(传入 ref 和索引) */\n observe: (element: HTMLElement | null, index: number) => void\n\n /** 取消观察指定元素 */\n unobserve: (element: HTMLElement | null) => void\n\n /** 断开所有观察 */\n disconnect: () => void\n}\n\nexport function useResizeObserver(\n options: UseResizeObserverOptions\n): UseResizeObserverReturn {\n const { enabled, isHorizontal, listId, onResize } = options\n\n // H5: ResizeObserver 实例\n const observerRef = useRef<ResizeObserver | null>(null)\n\n // 小程序: IntersectionObserver 实例 Map\n const intersectionObserversRef = useRef<Map<number, Taro.IntersectionObserver>>(new Map())\n\n // 已观察的元素 Map(用于去重)\n const observedElementsRef = useRef<Map<number, HTMLElement | null>>(new Map())\n\n /**\n * H5 实现:使用 ResizeObserver\n */\n const observeH5 = useCallback((element: HTMLElement | null, index: number) => {\n if (!element || !enabled) return\n\n // 避免重复观察\n if (observedElementsRef.current.has(index)) return\n\n // 创建 ResizeObserver(懒加载)\n if (!observerRef.current) {\n observerRef.current = new ResizeObserver((entries) => {\n entries.forEach((entry) => {\n const idx = Number(entry.target.getAttribute('data-index'))\n if (isNaN(idx)) return\n\n const size = isHorizontal\n ? entry.contentRect.width\n : entry.contentRect.height\n\n onResize(idx, size)\n })\n })\n }\n\n // 设置 data-index 属性\n element.setAttribute('data-index', String(index))\n\n // 开始观察\n observerRef.current.observe(element)\n observedElementsRef.current.set(index, element)\n }, [enabled, isHorizontal, onResize])\n\n /**\n * 小程序实现:使用 IntersectionObserver + SelectorQuery\n * 使用唯一 id 选择器,避免多 List 并存时误命中(index>=0 为 item,index<0 为 header)\n * 使用 Taro.nextTick 延后 observe,确保 setData 已提交、节点已挂载,避免 \"Node is not found\" 报错\n */\n const observeMiniProgram = useCallback((_element: any, index: number) => {\n if (!enabled) return\n\n // 避免重复观察\n if (intersectionObserversRef.current.has(index)) return\n\n const selector = index >= 0\n ? `#${listId}-list-item-inner-${index}`\n : `#${listId}-list-header-inner-${-index - 1}`\n\n const doObserve = () => {\n try {\n // 创建 IntersectionObserver\n const observer = Taro.createIntersectionObserver(Taro.getCurrentInstance().page as any, {\n observeAll: true\n })\n\n // 相对于 List 容器\n observer.relativeTo(`#${listId}`)\n\n // 观察元素进入可见区域(唯一 id 避免跨 List 误命中)\n observer.observe(selector, (res) => {\n if (res.intersectionRatio > 0) {\n Taro.createSelectorQuery()\n .select(selector)\n .boundingClientRect((rect: any) => {\n if (rect) {\n const size = isHorizontal ? rect.width : rect.height\n onResize(index, size)\n }\n })\n .exec()\n }\n })\n\n intersectionObserversRef.current.set(index, observer)\n } catch {\n // ignore observe failure\n }\n }\n\n Taro.nextTick(doObserve)\n }, [enabled, isHorizontal, listId, onResize])\n\n /**\n * 观察元素(平台自动适配)\n */\n const observe = useCallback((element: HTMLElement | null, index: number) => {\n if (!enabled) return\n\n if (isH5) {\n observeH5(element, index)\n } else if (isMiniProgram) {\n observeMiniProgram(element, index)\n }\n }, [enabled, observeH5, observeMiniProgram])\n\n /**\n * 取消观察元素\n */\n const unobserve = useCallback((element: HTMLElement | null) => {\n if (!element) return\n\n const index = Number(element.getAttribute('data-index'))\n if (isNaN(index)) return\n\n if (isH5 && observerRef.current) {\n observerRef.current.unobserve(element)\n observedElementsRef.current.delete(index)\n } else if (isMiniProgram) {\n const observer = intersectionObserversRef.current.get(index)\n if (observer) {\n observer.disconnect()\n intersectionObserversRef.current.delete(index)\n }\n }\n }, [])\n\n /**\n * 断开所有观察\n */\n const disconnect = useCallback(() => {\n if (isH5 && observerRef.current) {\n observerRef.current.disconnect()\n observerRef.current = null\n observedElementsRef.current.clear()\n } else if (isMiniProgram) {\n intersectionObserversRef.current.forEach((observer) => {\n observer.disconnect()\n })\n intersectionObserversRef.current.clear()\n }\n }, [])\n\n /**\n * 组件卸载时清理\n */\n useEffect(() => {\n return () => {\n disconnect()\n }\n }, [disconnect])\n\n return {\n observe,\n unobserve,\n disconnect\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { type MutableRefObject } from 'react';
2
+ interface UseScrollCorrectionOptions {
3
+ /** 是否启用修正 */
4
+ enabled: boolean;
5
+ /** 可见区域起始索引(取值时读 ref.current,避免 stale) */
6
+ visibleStartIndexRef: MutableRefObject<number>;
7
+ /** 设置滚动位置的回调 */
8
+ setScrollOffset: (offset: number | ((prev: number) => number)) => void;
9
+ }
10
+ interface UseScrollCorrectionReturn {
11
+ /** 记录尺寸变化 */
12
+ recordSizeChange: (index: number, oldSize: number, newSize: number) => void;
13
+ /** 标记用户正在滚动 */
14
+ markUserScrolling: () => void;
15
+ /** 清空修正队列 */
16
+ clearQueue: () => void;
17
+ }
18
+ export declare function useScrollCorrection(options: UseScrollCorrectionOptions): UseScrollCorrectionReturn;
19
+ export {};
@@ -0,0 +1,73 @@
1
+ import { useRef, useCallback } from 'react';
2
+
3
+ function useScrollCorrection(options) {
4
+ const { enabled, visibleStartIndexRef, setScrollOffset } = options;
5
+ // 修正队列
6
+ const queueRef = useRef([]);
7
+ // 修正定时器
8
+ const timerRef = useRef(null);
9
+ // 用户最后滚动时间
10
+ const lastUserScrollTimeRef = useRef(0);
11
+ /**
12
+ * 记录尺寸变化
13
+ */
14
+ const recordSizeChange = useCallback((index, oldSize, newSize) => {
15
+ if (!enabled)
16
+ return;
17
+ const diff = newSize - oldSize;
18
+ // 阈值过滤:小于 1px 的变化忽略
19
+ if (Math.abs(diff) < 1)
20
+ return;
21
+ // 添加到队列
22
+ queueRef.current.push({ index, diff });
23
+ // 清除旧定时器
24
+ if (timerRef.current) {
25
+ clearTimeout(timerRef.current);
26
+ }
27
+ // 延迟执行修正(批量窗口 100ms)
28
+ timerRef.current = setTimeout(() => {
29
+ const now = Date.now();
30
+ // 如果用户最近 300ms 内主动滚动,跳过修正
31
+ if (now - lastUserScrollTimeRef.current < 300) {
32
+ queueRef.current = [];
33
+ return;
34
+ }
35
+ // 批量计算修正量(仅修正可见区域之前的变化;读 ref 获取最新值)
36
+ const visibleStart = visibleStartIndexRef.current;
37
+ const totalCorrection = queueRef.current
38
+ .filter(item => item.index < visibleStart)
39
+ .reduce((sum, item) => sum + item.diff, 0);
40
+ // 应用修正
41
+ if (Math.abs(totalCorrection) > 1) {
42
+ setScrollOffset(prev => prev + totalCorrection);
43
+ }
44
+ // 清空队列
45
+ queueRef.current = [];
46
+ }, 100);
47
+ }, [enabled, visibleStartIndexRef, setScrollOffset]);
48
+ /**
49
+ * 标记用户正在滚动
50
+ * 在 onScroll 事件中调用
51
+ */
52
+ const markUserScrolling = useCallback(() => {
53
+ lastUserScrollTimeRef.current = Date.now();
54
+ }, []);
55
+ /**
56
+ * 清空修正队列
57
+ */
58
+ const clearQueue = useCallback(() => {
59
+ if (timerRef.current) {
60
+ clearTimeout(timerRef.current);
61
+ timerRef.current = null;
62
+ }
63
+ queueRef.current = [];
64
+ }, []);
65
+ return {
66
+ recordSizeChange,
67
+ markUserScrolling,
68
+ clearQueue
69
+ };
70
+ }
71
+
72
+ export { useScrollCorrection };
73
+ //# sourceMappingURL=useScrollCorrection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useScrollCorrection.js","sources":["../../../../src/components/list/hooks/useScrollCorrection.ts"],"sourcesContent":["import { type MutableRefObject, useCallback, useRef } from 'react'\n\n/**\n * useScrollCorrection Hook - ScrollTop/Left 修正\n *\n * 当列表项尺寸变化时,自动修正滚动位置,避免视觉跳动\n *\n * 策略:\n * 1. 批量处理:100ms 窗口内的多次变化合并\n * 2. 智能判断:用户滚动后 300ms 内不修正\n * 3. 范围限制:仅修正可见区域之前的变化\n * 4. 阈值过滤:小于 1px 的变化忽略\n */\n\ninterface ScrollCorrectionItem {\n index: number\n diff: number // 尺寸变化量\n}\n\ninterface UseScrollCorrectionOptions {\n /** 是否启用修正 */\n enabled: boolean\n\n /** 可见区域起始索引(取值时读 ref.current,避免 stale) */\n visibleStartIndexRef: MutableRefObject<number>\n\n /** 设置滚动位置的回调 */\n setScrollOffset: (offset: number | ((prev: number) => number)) => void\n}\n\ninterface UseScrollCorrectionReturn {\n /** 记录尺寸变化 */\n recordSizeChange: (index: number, oldSize: number, newSize: number) => void\n\n /** 标记用户正在滚动 */\n markUserScrolling: () => void\n\n /** 清空修正队列 */\n clearQueue: () => void\n}\n\nexport function useScrollCorrection(\n options: UseScrollCorrectionOptions\n): UseScrollCorrectionReturn {\n const { enabled, visibleStartIndexRef, setScrollOffset } = options\n\n // 修正队列\n const queueRef = useRef<ScrollCorrectionItem[]>([])\n\n // 修正定时器\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n // 用户最后滚动时间\n const lastUserScrollTimeRef = useRef(0)\n\n /**\n * 记录尺寸变化\n */\n const recordSizeChange = useCallback((\n index: number,\n oldSize: number,\n newSize: number\n ) => {\n if (!enabled) return\n\n const diff = newSize - oldSize\n\n // 阈值过滤:小于 1px 的变化忽略\n if (Math.abs(diff) < 1) return\n\n // 添加到队列\n queueRef.current.push({ index, diff })\n\n // 清除旧定时器\n if (timerRef.current) {\n clearTimeout(timerRef.current)\n }\n\n // 延迟执行修正(批量窗口 100ms)\n timerRef.current = setTimeout(() => {\n const now = Date.now()\n\n // 如果用户最近 300ms 内主动滚动,跳过修正\n if (now - lastUserScrollTimeRef.current < 300) {\n queueRef.current = []\n return\n }\n\n // 批量计算修正量(仅修正可见区域之前的变化;读 ref 获取最新值)\n const visibleStart = visibleStartIndexRef.current\n const totalCorrection = queueRef.current\n .filter(item => item.index < visibleStart)\n .reduce((sum, item) => sum + item.diff, 0)\n\n // 应用修正\n if (Math.abs(totalCorrection) > 1) {\n setScrollOffset(prev => prev + totalCorrection)\n }\n\n // 清空队列\n queueRef.current = []\n }, 100)\n }, [enabled, visibleStartIndexRef, setScrollOffset])\n\n /**\n * 标记用户正在滚动\n * 在 onScroll 事件中调用\n */\n const markUserScrolling = useCallback(() => {\n lastUserScrollTimeRef.current = Date.now()\n }, [])\n\n /**\n * 清空修正队列\n */\n const clearQueue = useCallback(() => {\n if (timerRef.current) {\n clearTimeout(timerRef.current)\n timerRef.current = null\n }\n queueRef.current = []\n }, [])\n\n return {\n recordSizeChange,\n markUserScrolling,\n clearQueue\n }\n}\n"],"names":[],"mappings":";;AAyCM,SAAU,mBAAmB,CACjC,OAAmC,EAAA;IAEnC,MAAM,EAAE,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,GAAG,OAAO;;AAGlE,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAyB,EAAE,CAAC;;AAGnD,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAuC,IAAI,CAAC;;AAGnE,IAAA,MAAM,qBAAqB,GAAG,MAAM,CAAC,CAAC,CAAC;AAEvC;;AAEG;IACH,MAAM,gBAAgB,GAAG,WAAW,CAAC,CACnC,KAAa,EACb,OAAe,EACf,OAAe,KACb;AACF,QAAA,IAAI,CAAC,OAAO;YAAE;AAEd,QAAA,MAAM,IAAI,GAAG,OAAO,GAAG,OAAO;;AAG9B,QAAA,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE;;QAGxB,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;;AAGtC,QAAA,IAAI,QAAQ,CAAC,OAAO,EAAE;AACpB,YAAA,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC;;;AAIhC,QAAA,QAAQ,CAAC,OAAO,GAAG,UAAU,CAAC,MAAK;AACjC,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;;YAGtB,IAAI,GAAG,GAAG,qBAAqB,CAAC,OAAO,GAAG,GAAG,EAAE;AAC7C,gBAAA,QAAQ,CAAC,OAAO,GAAG,EAAE;gBACrB;;;AAIF,YAAA,MAAM,YAAY,GAAG,oBAAoB,CAAC,OAAO;AACjD,YAAA,MAAM,eAAe,GAAG,QAAQ,CAAC;iBAC9B,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,GAAG,YAAY;AACxC,iBAAA,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,KAAK,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;;YAG5C,IAAI,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE;gBACjC,eAAe,CAAC,IAAI,IAAI,IAAI,GAAG,eAAe,CAAC;;;AAIjD,YAAA,QAAQ,CAAC,OAAO,GAAG,EAAE;SACtB,EAAE,GAAG,CAAC;KACR,EAAE,CAAC,OAAO,EAAE,oBAAoB,EAAE,eAAe,CAAC,CAAC;AAEpD;;;AAGG;AACH,IAAA,MAAM,iBAAiB,GAAG,WAAW,CAAC,MAAK;AACzC,QAAA,qBAAqB,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE;KAC3C,EAAE,EAAE,CAAC;AAEN;;AAEG;AACH,IAAA,MAAM,UAAU,GAAG,WAAW,CAAC,MAAK;AAClC,QAAA,IAAI,QAAQ,CAAC,OAAO,EAAE;AACpB,YAAA,YAAY,CAAC,QAAQ,CAAC,OAAO,CAAC;AAC9B,YAAA,QAAQ,CAAC,OAAO,GAAG,IAAI;;AAEzB,QAAA,QAAQ,CAAC,OAAO,GAAG,EAAE;KACtB,EAAE,EAAE,CAAC;IAEN,OAAO;QACL,gBAAgB;QAChB,iBAAiB;QACjB;KACD;AACH;;;;"}
@@ -0,0 +1,20 @@
1
+ import type { RefObject } from 'react';
2
+ export type ScrollParentAutoFindStatus = 'pending' | 'found' | 'not-found';
3
+ /**
4
+ * 自动查找 content 元素的真实滚动父节点。
5
+ * 用于 nestedScroll 模式下无 scrollElement props/Context 时,作为第三优先级来源。
6
+ *
7
+ * - H5:DOM 遍历 findScrollParent(contentEl)
8
+ * - 小程序:Taro 虚拟 DOM findScrollParentTaro(contentId)
9
+ * - ref 未就绪时自动重试
10
+ * - 找到后通过 setState 触发 re-render,供 effectiveScrollElement 读取
11
+ * - status 用于 probe 阶段:pending=尚未完成,found=已找到,not-found=已尝试未找到
12
+ */
13
+ export declare function useScrollParentAutoFind(contentRef: RefObject<HTMLElement | null>, options: {
14
+ enabled: boolean;
15
+ isHorizontal?: boolean;
16
+ contentId?: string;
17
+ }): {
18
+ scrollParentRef: RefObject<HTMLElement | null>;
19
+ status: ScrollParentAutoFindStatus;
20
+ };
@@ -0,0 +1,81 @@
1
+ import { useRef, useState, useEffect } from 'react';
2
+ import { findScrollParentTaro, findScrollParent } from '../../../utils/scrollParent.js';
3
+ import { isWeapp } from '../utils.js';
4
+
5
+ const MAX_RETRY = 20;
6
+ const RETRY_DELAY = 50;
7
+ /**
8
+ * 自动查找 content 元素的真实滚动父节点。
9
+ * 用于 nestedScroll 模式下无 scrollElement props/Context 时,作为第三优先级来源。
10
+ *
11
+ * - H5:DOM 遍历 findScrollParent(contentEl)
12
+ * - 小程序:Taro 虚拟 DOM findScrollParentTaro(contentId)
13
+ * - ref 未就绪时自动重试
14
+ * - 找到后通过 setState 触发 re-render,供 effectiveScrollElement 读取
15
+ * - status 用于 probe 阶段:pending=尚未完成,found=已找到,not-found=已尝试未找到
16
+ */
17
+ function useScrollParentAutoFind(contentRef, options) {
18
+ const { enabled, isHorizontal = false, contentId } = options;
19
+ const scrollParentRef = useRef(null);
20
+ const [status, setStatus] = useState('pending');
21
+ const [retryTrigger, setRetryTrigger] = useState(0);
22
+ const retryCountRef = useRef(0);
23
+ useEffect(() => {
24
+ if (!enabled) {
25
+ retryCountRef.current = 0;
26
+ scrollParentRef.current = null;
27
+ setStatus('pending');
28
+ return;
29
+ }
30
+ if (isWeapp) {
31
+ // 小程序:基于 contentId 在 Taro 虚拟 DOM 中查找 scroll-view
32
+ if (!contentId) {
33
+ setStatus('not-found');
34
+ return;
35
+ }
36
+ const found = findScrollParentTaro(contentId);
37
+ if (found) {
38
+ retryCountRef.current = 0;
39
+ scrollParentRef.current = found;
40
+ setStatus('found');
41
+ }
42
+ else {
43
+ if (retryCountRef.current < MAX_RETRY) {
44
+ retryCountRef.current += 1;
45
+ const id = setTimeout(() => setRetryTrigger((t) => t + 1), RETRY_DELAY);
46
+ return () => clearTimeout(id);
47
+ }
48
+ scrollParentRef.current = null;
49
+ setStatus('not-found');
50
+ }
51
+ return;
52
+ }
53
+ // H5:DOM 遍历
54
+ const contentEl = contentRef.current;
55
+ if (!contentEl) {
56
+ if (retryCountRef.current < MAX_RETRY) {
57
+ retryCountRef.current += 1;
58
+ const id = setTimeout(() => setRetryTrigger((t) => t + 1), RETRY_DELAY);
59
+ return () => clearTimeout(id);
60
+ }
61
+ setStatus('not-found');
62
+ return;
63
+ }
64
+ retryCountRef.current = 0;
65
+ const found = findScrollParent(contentEl, !isHorizontal);
66
+ if (found) {
67
+ if (found !== scrollParentRef.current) {
68
+ scrollParentRef.current = found;
69
+ setStatus('found');
70
+ }
71
+ }
72
+ else {
73
+ scrollParentRef.current = null;
74
+ setStatus('not-found');
75
+ }
76
+ }, [enabled, contentRef, isHorizontal, contentId, retryTrigger]);
77
+ return { scrollParentRef, status };
78
+ }
79
+
80
+ export { useScrollParentAutoFind };
81
+ //# sourceMappingURL=useScrollParentAutoFind.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useScrollParentAutoFind.js","sources":["../../../../src/components/list/hooks/useScrollParentAutoFind.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\n\nimport { findScrollParent, findScrollParentTaro } from '../../../utils/scrollParent'\nimport { isWeapp } from '../utils'\n\nimport type { RefObject } from 'react'\n\nconst MAX_RETRY = 20\nconst RETRY_DELAY = 50\n\nexport type ScrollParentAutoFindStatus = 'pending' | 'found' | 'not-found'\n\n/**\n * 自动查找 content 元素的真实滚动父节点。\n * 用于 nestedScroll 模式下无 scrollElement props/Context 时,作为第三优先级来源。\n *\n * - H5:DOM 遍历 findScrollParent(contentEl)\n * - 小程序:Taro 虚拟 DOM findScrollParentTaro(contentId)\n * - ref 未就绪时自动重试\n * - 找到后通过 setState 触发 re-render,供 effectiveScrollElement 读取\n * - status 用于 probe 阶段:pending=尚未完成,found=已找到,not-found=已尝试未找到\n */\nexport function useScrollParentAutoFind(\n contentRef: RefObject<HTMLElement | null>,\n options: { enabled: boolean, isHorizontal?: boolean, contentId?: string }\n): { scrollParentRef: RefObject<HTMLElement | null>, status: ScrollParentAutoFindStatus } {\n const { enabled, isHorizontal = false, contentId } = options\n const scrollParentRef = useRef<HTMLElement | null>(null)\n const [status, setStatus] = useState<ScrollParentAutoFindStatus>('pending')\n const [retryTrigger, setRetryTrigger] = useState(0)\n const retryCountRef = useRef(0)\n\n useEffect(() => {\n if (!enabled) {\n retryCountRef.current = 0\n scrollParentRef.current = null\n setStatus('pending')\n return\n }\n\n if (isWeapp) {\n // 小程序:基于 contentId 在 Taro 虚拟 DOM 中查找 scroll-view\n if (!contentId) {\n setStatus('not-found')\n return\n }\n const found = findScrollParentTaro(contentId)\n if (found) {\n retryCountRef.current = 0\n scrollParentRef.current = found as unknown as HTMLElement\n setStatus('found')\n } else {\n if (retryCountRef.current < MAX_RETRY) {\n retryCountRef.current += 1\n const id = setTimeout(() => setRetryTrigger((t) => t + 1), RETRY_DELAY)\n return () => clearTimeout(id)\n }\n scrollParentRef.current = null\n setStatus('not-found')\n }\n return\n }\n\n // H5:DOM 遍历\n const contentEl = contentRef.current\n if (!contentEl) {\n if (retryCountRef.current < MAX_RETRY) {\n retryCountRef.current += 1\n const id = setTimeout(() => setRetryTrigger((t) => t + 1), RETRY_DELAY)\n return () => clearTimeout(id)\n }\n setStatus('not-found')\n return\n }\n\n retryCountRef.current = 0\n const found = findScrollParent(contentEl, !isHorizontal)\n if (found) {\n if (found !== scrollParentRef.current) {\n scrollParentRef.current = found\n setStatus('found')\n }\n } else {\n scrollParentRef.current = null\n setStatus('not-found')\n }\n }, [enabled, contentRef, isHorizontal, contentId, retryTrigger])\n\n return { scrollParentRef, status }\n}\n"],"names":[],"mappings":";;;;AAOA,MAAM,SAAS,GAAG,EAAE;AACpB,MAAM,WAAW,GAAG,EAAE;AAItB;;;;;;;;;AASG;AACa,SAAA,uBAAuB,CACrC,UAAyC,EACzC,OAAyE,EAAA;IAEzE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,KAAK,EAAE,SAAS,EAAE,GAAG,OAAO;AAC5D,IAAA,MAAM,eAAe,GAAG,MAAM,CAAqB,IAAI,CAAC;IACxD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAA6B,SAAS,CAAC;IAC3E,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;AACnD,IAAA,MAAM,aAAa,GAAG,MAAM,CAAC,CAAC,CAAC;IAE/B,SAAS,CAAC,MAAK;QACb,IAAI,CAAC,OAAO,EAAE;AACZ,YAAA,aAAa,CAAC,OAAO,GAAG,CAAC;AACzB,YAAA,eAAe,CAAC,OAAO,GAAG,IAAI;YAC9B,SAAS,CAAC,SAAS,CAAC;YACpB;;QAGF,IAAI,OAAO,EAAE;;YAEX,IAAI,CAAC,SAAS,EAAE;gBACd,SAAS,CAAC,WAAW,CAAC;gBACtB;;AAEF,YAAA,MAAM,KAAK,GAAG,oBAAoB,CAAC,SAAS,CAAC;YAC7C,IAAI,KAAK,EAAE;AACT,gBAAA,aAAa,CAAC,OAAO,GAAG,CAAC;AACzB,gBAAA,eAAe,CAAC,OAAO,GAAG,KAA+B;gBACzD,SAAS,CAAC,OAAO,CAAC;;iBACb;AACL,gBAAA,IAAI,aAAa,CAAC,OAAO,GAAG,SAAS,EAAE;AACrC,oBAAA,aAAa,CAAC,OAAO,IAAI,CAAC;oBAC1B,MAAM,EAAE,GAAG,UAAU,CAAC,MAAM,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC;AACvE,oBAAA,OAAO,MAAM,YAAY,CAAC,EAAE,CAAC;;AAE/B,gBAAA,eAAe,CAAC,OAAO,GAAG,IAAI;gBAC9B,SAAS,CAAC,WAAW,CAAC;;YAExB;;;AAIF,QAAA,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO;QACpC,IAAI,CAAC,SAAS,EAAE;AACd,YAAA,IAAI,aAAa,CAAC,OAAO,GAAG,SAAS,EAAE;AACrC,gBAAA,aAAa,CAAC,OAAO,IAAI,CAAC;gBAC1B,MAAM,EAAE,GAAG,UAAU,CAAC,MAAM,eAAe,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC;AACvE,gBAAA,OAAO,MAAM,YAAY,CAAC,EAAE,CAAC;;YAE/B,SAAS,CAAC,WAAW,CAAC;YACtB;;AAGF,QAAA,aAAa,CAAC,OAAO,GAAG,CAAC;QACzB,MAAM,KAAK,GAAG,gBAAgB,CAAC,SAAS,EAAE,CAAC,YAAY,CAAC;QACxD,IAAI,KAAK,EAAE;AACT,YAAA,IAAI,KAAK,KAAK,eAAe,CAAC,OAAO,EAAE;AACrC,gBAAA,eAAe,CAAC,OAAO,GAAG,KAAK;gBAC/B,SAAS,CAAC,OAAO,CAAC;;;aAEf;AACL,YAAA,eAAe,CAAC,OAAO,GAAG,IAAI;YAC9B,SAAS,CAAC,WAAW,CAAC;;AAE1B,KAAC,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,CAAC,CAAC;AAEhE,IAAA,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE;AACpC;;;;"}
@@ -1,7 +1,9 @@
1
1
  import React from 'react';
2
2
  import ListItem from './ListItem';
3
+ import NoMore from './NoMore';
3
4
  import StickyHeader from './StickyHeader';
4
5
  import StickySection from './StickySection';
6
+ /** 与官方 List.d.ts / ScrollView / harmony 对齐,不增减已有语义;扩展项仅用于高级能力 */
5
7
  export interface ListProps {
6
8
  showScrollbar?: boolean;
7
9
  scrollTop?: number;
@@ -10,27 +12,82 @@ export interface ListProps {
10
12
  onScroll?: (e: {
11
13
  scrollTop: number;
12
14
  scrollLeft: number;
15
+ detail: {
16
+ scrollTop: number;
17
+ scrollLeft: number;
18
+ };
13
19
  }) => void;
14
20
  onScrollToUpper?: () => void;
15
21
  onScrollToLower?: () => void;
16
22
  upperThreshold?: number;
17
23
  lowerThreshold?: number;
18
- cacheCount?: number;
24
+ /** 与 ScrollView cacheExtent 对齐(视口外渲染距离),可选 */
25
+ cacheExtent?: number;
26
+ /** 与 ScrollView enableBackToTop 对齐 */
27
+ enableBackToTop?: boolean;
28
+ /** 与 ScrollView onScrollStart 对齐 */
29
+ onScrollStart?: () => void;
30
+ /** 与 ScrollView onScrollEnd 对齐 */
31
+ onScrollEnd?: () => void;
32
+ scrollIntoView?: string;
33
+ /** 透传给最外层 ScrollView 的 className,便于自定义样式 */
34
+ className?: string;
19
35
  stickyHeader?: boolean;
20
36
  space?: number;
37
+ cacheCount?: number;
21
38
  itemData?: any[];
22
39
  itemSize?: number | ((index: number, data?: any[]) => number);
23
40
  height?: number | string;
24
41
  width?: number | string;
25
42
  style?: React.CSSProperties;
26
43
  children?: React.ReactNode;
27
- headerHeight?: number;
28
- headerWidth?: number;
29
- itemHeight?: number;
30
- itemWidth?: number;
44
+ /** Header 沿滚动方向尺寸;未传时回退到 itemSize */
45
+ headerSize?: number;
46
+ useResizeObserver?: boolean;
47
+ onItemSizeChange?: (index: number, size: number) => void;
48
+ showNoMore?: boolean;
49
+ noMoreText?: string;
50
+ noMoreStyle?: React.CSSProperties;
51
+ renderNoMore?: () => React.ReactNode;
52
+ onScrollIndex?: (start: number, end: number) => void;
53
+ /** 是否开启下拉刷新;与 Refresher 子组件二选一或同时存在(Refresher 子覆盖同名字段) */
54
+ refresherEnabled?: boolean;
55
+ refresherThreshold?: number;
56
+ refresherDefaultStyle?: 'black' | 'white' | 'none';
57
+ refresherBackground?: string;
58
+ refresherTriggered?: boolean;
59
+ onRefresherPulling?: (e?: {
60
+ detail?: {
61
+ deltaY?: number;
62
+ };
63
+ }) => void;
64
+ onRefresherRefresh?: () => void | Promise<void>;
65
+ onRefresherRestore?: () => void;
66
+ onRefresherAbort?: () => void;
67
+ onRefresherWillRefresh?: () => void;
68
+ onRefresherStatusChange?: (e?: {
69
+ detail?: {
70
+ status?: number;
71
+ dy?: number;
72
+ };
73
+ }) => void;
74
+ /** 是否嵌套模式,与 plato 对齐;true=使用父级滚动,需配合 scrollElement 或 Context;不传或 false=default */
75
+ nestedScroll?: boolean;
76
+ /** 自定义滚动容器 ref,nestedScroll 模式下从 props 或 Context 获取 */
77
+ scrollElement?: React.RefObject<HTMLElement | null>;
78
+ /** 暴露滚动容器 ref,供内层 List/WaterFlow(nestedScroll)嵌套时传入 scrollElement */
79
+ scrollRef?: React.MutableRefObject<HTMLElement | null>;
80
+ }
81
+ export interface ListHandle {
82
+ scroll: (options?: {
83
+ top?: number;
84
+ left?: number;
85
+ }) => void;
31
86
  }
32
87
  export declare function accumulate(arr: number[]): number[];
33
88
  export declare function isShaking(diffList: number[]): boolean;
34
- declare const List: React.FC<ListProps>;
35
- export { List, ListItem, StickyHeader, StickySection };
89
+ /** 向后兼容:ListScrollElementContext 已统一为 ScrollElementContext,无 Context 时兜底为 fallback */
90
+ export { ScrollElementContextOrFallback as ListScrollElementContext } from '../../utils/scrollElementContext';
91
+ declare const List: React.ForwardRefExoticComponent<ListProps & React.RefAttributes<ListHandle>>;
92
+ export { List, ListItem, NoMore, StickyHeader, StickySection };
36
93
  export default List;