@tarojs/components-advanced 4.1.12-beta.13 → 4.1.12-beta.15

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.
@@ -1,6 +1,6 @@
1
1
  interface UseItemSizeCacheOptions {
2
2
  isHorizontal: boolean;
3
- estimatedItemSize: number;
3
+ estimatedSize: number;
4
4
  itemCount: number;
5
5
  }
6
6
  interface UseItemSizeCacheReturn {
@@ -1,7 +1,7 @@
1
1
  import { useRef, useCallback } from 'react';
2
2
 
3
3
  function useItemSizeCache(options) {
4
- const { estimatedItemSize } = options;
4
+ const { estimatedSize } = options;
5
5
  // 缓存 Map:key = 索引,value = 尺寸信息
6
6
  const cacheRef = useRef(new Map());
7
7
  /**
@@ -13,8 +13,8 @@ function useItemSizeCache(options) {
13
13
  if ((cached === null || cached === void 0 ? void 0 : cached.isMeasured) && cached.measuredSize !== null) {
14
14
  return cached.measuredSize;
15
15
  }
16
- return estimatedItemSize;
17
- }, [estimatedItemSize]);
16
+ return estimatedSize;
17
+ }, [estimatedSize]);
18
18
  /**
19
19
  * 设置项的尺寸(实际测量后调用)
20
20
  */
@@ -26,10 +26,10 @@ function useItemSizeCache(options) {
26
26
  }
27
27
  cacheRef.current.set(index, {
28
28
  measuredSize: size,
29
- estimatedSize: estimatedItemSize,
29
+ estimatedSize,
30
30
  isMeasured: true
31
31
  });
32
- }, [estimatedItemSize]);
32
+ }, [estimatedSize]);
33
33
  return {
34
34
  getItemSize,
35
35
  setItemSize
@@ -1 +1 @@
1
- {"version":3,"file":"useItemSizeCache.js","sources":["../../../../src/components/list/hooks/useItemSizeCache.ts"],"sourcesContent":["import { useCallback, useRef } from 'react'\n\n/**\n * useItemSizeCache Hook - 动态尺寸缓存管理\n *\n * 支持垂直滚动(高度)和水平滚动(宽度)两种模式\n */\n\n/** 单个项的尺寸缓存 */\ninterface ItemMeasureCache {\n measuredSize: number | null // 实际测量尺寸\n estimatedSize: number // 估算尺寸\n isMeasured: boolean // 是否已测量\n}\n\ninterface UseItemSizeCacheOptions {\n isHorizontal: boolean // 是否水平滚动\n estimatedItemSize: number // 估算尺寸\n itemCount: number // 项总数\n}\n\ninterface UseItemSizeCacheReturn {\n /** 获取项的尺寸(高度或宽度) */\n getItemSize: (index: number) => number\n\n /** 设置项的尺寸 */\n setItemSize: (index: number, size: number) => void\n}\n\nexport function useItemSizeCache(\n options: UseItemSizeCacheOptions\n): UseItemSizeCacheReturn {\n const { estimatedItemSize } = options\n\n // 缓存 Map:key = 索引,value = 尺寸信息\n const cacheRef = useRef<Map<number, ItemMeasureCache>>(new Map())\n\n /**\n * 获取项的尺寸\n * 优先返回实际测量值,否则返回估算值\n */\n const getItemSize = useCallback((index: number): number => {\n const cached = cacheRef.current.get(index)\n\n if (cached?.isMeasured && cached.measuredSize !== null) {\n return cached.measuredSize\n }\n\n return estimatedItemSize\n }, [estimatedItemSize])\n\n /**\n * 设置项的尺寸(实际测量后调用)\n */\n const setItemSize = useCallback((index: number, size: number) => {\n const cached = cacheRef.current.get(index)\n\n // 尺寸变化小于 1px,忽略(避免微小抖动)\n if (cached?.measuredSize && Math.abs(cached.measuredSize - size) < 1) {\n return\n }\n\n cacheRef.current.set(index, {\n measuredSize: size,\n estimatedSize: estimatedItemSize,\n isMeasured: true\n })\n }, [estimatedItemSize])\n\n return {\n getItemSize,\n setItemSize\n }\n}\n"],"names":[],"mappings":";;AA6BM,SAAU,gBAAgB,CAC9B,OAAgC,EAAA;AAEhC,IAAA,MAAM,EAAE,iBAAiB,EAAE,GAAG,OAAO;;IAGrC,MAAM,QAAQ,GAAG,MAAM,CAAgC,IAAI,GAAG,EAAE,CAAC;AAEjE;;;AAGG;AACH,IAAA,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,KAAa,KAAY;QACxD,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AAE1C,QAAA,IAAI,CAAA,MAAM,KAAN,IAAA,IAAA,MAAM,uBAAN,MAAM,CAAE,UAAU,KAAI,MAAM,CAAC,YAAY,KAAK,IAAI,EAAE;YACtD,OAAO,MAAM,CAAC,YAAY;;AAG5B,QAAA,OAAO,iBAAiB;AAC1B,KAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC;AAEvB;;AAEG;IACH,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,KAAa,EAAE,IAAY,KAAI;QAC9D,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;;QAG1C,IAAI,CAAA,MAAM,KAAN,IAAA,IAAA,MAAM,uBAAN,MAAM,CAAE,YAAY,KAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE;YACpE;;AAGF,QAAA,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE;AAC1B,YAAA,YAAY,EAAE,IAAI;AAClB,YAAA,aAAa,EAAE,iBAAiB;AAChC,YAAA,UAAU,EAAE;AACb,SAAA,CAAC;AACJ,KAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC;IAEvB,OAAO;QACL,WAAW;QACX;KACD;AACH;;;;"}
1
+ {"version":3,"file":"useItemSizeCache.js","sources":["../../../../src/components/list/hooks/useItemSizeCache.ts"],"sourcesContent":["import { useCallback, useRef } from 'react'\n\n/**\n * useItemSizeCache Hook - 动态尺寸缓存管理\n *\n * 支持垂直滚动(高度)和水平滚动(宽度)两种模式\n */\n\n/** 单个项的尺寸缓存 */\ninterface ItemMeasureCache {\n measuredSize: number | null // 实际测量尺寸\n estimatedSize: number // 估算尺寸\n isMeasured: boolean // 是否已测量\n}\n\ninterface UseItemSizeCacheOptions {\n isHorizontal: boolean // 是否水平滚动\n estimatedSize: number // 估算尺寸\n itemCount: number // 项总数\n}\n\ninterface UseItemSizeCacheReturn {\n /** 获取项的尺寸(高度或宽度) */\n getItemSize: (index: number) => number\n\n /** 设置项的尺寸 */\n setItemSize: (index: number, size: number) => void\n}\n\nexport function useItemSizeCache(\n options: UseItemSizeCacheOptions\n): UseItemSizeCacheReturn {\n const { estimatedSize } = options\n\n // 缓存 Map:key = 索引,value = 尺寸信息\n const cacheRef = useRef<Map<number, ItemMeasureCache>>(new Map())\n\n /**\n * 获取项的尺寸\n * 优先返回实际测量值,否则返回估算值\n */\n const getItemSize = useCallback((index: number): number => {\n const cached = cacheRef.current.get(index)\n\n if (cached?.isMeasured && cached.measuredSize !== null) {\n return cached.measuredSize\n }\n\n return estimatedSize\n }, [estimatedSize])\n\n /**\n * 设置项的尺寸(实际测量后调用)\n */\n const setItemSize = useCallback((index: number, size: number) => {\n const cached = cacheRef.current.get(index)\n\n // 尺寸变化小于 1px,忽略(避免微小抖动)\n if (cached?.measuredSize && Math.abs(cached.measuredSize - size) < 1) {\n return\n }\n\n cacheRef.current.set(index, {\n measuredSize: size,\n estimatedSize,\n isMeasured: true\n })\n }, [estimatedSize])\n\n return {\n getItemSize,\n setItemSize\n }\n}\n"],"names":[],"mappings":";;AA6BM,SAAU,gBAAgB,CAC9B,OAAgC,EAAA;AAEhC,IAAA,MAAM,EAAE,aAAa,EAAE,GAAG,OAAO;;IAGjC,MAAM,QAAQ,GAAG,MAAM,CAAgC,IAAI,GAAG,EAAE,CAAC;AAEjE;;;AAGG;AACH,IAAA,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,KAAa,KAAY;QACxD,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;AAE1C,QAAA,IAAI,CAAA,MAAM,KAAN,IAAA,IAAA,MAAM,uBAAN,MAAM,CAAE,UAAU,KAAI,MAAM,CAAC,YAAY,KAAK,IAAI,EAAE;YACtD,OAAO,MAAM,CAAC,YAAY;;AAG5B,QAAA,OAAO,aAAa;AACtB,KAAC,EAAE,CAAC,aAAa,CAAC,CAAC;AAEnB;;AAEG;IACH,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,KAAa,EAAE,IAAY,KAAI;QAC9D,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;;QAG1C,IAAI,CAAA,MAAM,KAAN,IAAA,IAAA,MAAM,uBAAN,MAAM,CAAE,YAAY,KAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE;YACpE;;AAGF,QAAA,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE;AAC1B,YAAA,YAAY,EAAE,IAAI;YAClB,aAAa;AACb,YAAA,UAAU,EAAE;AACb,SAAA,CAAC;AACJ,KAAC,EAAE,CAAC,aAAa,CAAC,CAAC;IAEnB,OAAO;QACL,WAAW;QACX;KACD;AACH;;;;"}
@@ -6,6 +6,10 @@ export interface ListScrollElementAttachRefs {
6
6
  onScroll: ((e: {
7
7
  scrollTop: number;
8
8
  scrollLeft: number;
9
+ detail: {
10
+ scrollTop: number;
11
+ scrollLeft: number;
12
+ };
9
13
  }) => void) | undefined;
10
14
  onScrollToUpper: (() => void) | undefined;
11
15
  onScrollToLower: (() => void) | undefined;
@@ -56,7 +56,9 @@ function useListScrollElementAttach(enabled, effectiveScrollElement, effectiveSt
56
56
  const clientSize = isHorizontal ? target.clientWidth : target.clientHeight;
57
57
  r.scrollCorrection.markUserScrolling();
58
58
  updateRenderOffset(effectiveAdjusted, false, 'scrollElement');
59
- (_a = r.onScroll) === null || _a === void 0 ? void 0 : _a.call(r, { scrollTop: isHorizontal ? 0 : scrollPos, scrollLeft: isHorizontal ? scrollPos : 0 });
59
+ const scrollTop = isHorizontal ? 0 : scrollPos;
60
+ const scrollLeft = isHorizontal ? scrollPos : 0;
61
+ (_a = r.onScroll) === null || _a === void 0 ? void 0 : _a.call(r, { scrollTop, scrollLeft, detail: { scrollTop, scrollLeft } });
60
62
  const { upper, lower } = r.threshold;
61
63
  const innerContentLen = r.listContentLength;
62
64
  const nowInUpper = effectiveAdjusted <= upper;
@@ -1 +1 @@
1
- {"version":3,"file":"useListScrollElementAttach.js","sources":["../../../../src/components/list/hooks/useListScrollElementAttach.ts"],"sourcesContent":["import { useEffect, useRef } from 'react'\n\nimport type { RefObject } from 'react'\n\nexport interface ListScrollElementAttachRefs {\n scrollCorrection: { markUserScrolling: () => void }\n onScroll: ((e: { scrollTop: number, scrollLeft: number }) => void) | undefined\n onScrollToUpper: (() => void) | undefined\n onScrollToLower: (() => void) | undefined\n threshold: { upper: number, lower: number }\n listContentLength: number\n}\n\n/**\n * scrollElement 模式下:监听外部滚动驱动 renderOffset,并从 scrollElement 获取 containerLength\n */\nexport function useListScrollElementAttach(\n enabled: boolean,\n effectiveScrollElement: RefObject<HTMLElement | null> | null,\n effectiveStartOffset: number,\n isHorizontal: boolean,\n setContainerLength: (v: number) => void,\n updateRenderOffset: (offset: number, sync?: boolean, source?: string) => void,\n scrollRefProp: React.MutableRefObject<HTMLElement | null> | undefined,\n refsRef: RefObject<ListScrollElementAttachRefs>\n) {\n const effectiveStartOffsetRef = useRef(effectiveStartOffset)\n effectiveStartOffsetRef.current = effectiveStartOffset\n\n useEffect(() => {\n if (!enabled || !effectiveScrollElement) return\n const el = effectiveScrollElement.current\n if (!el || typeof ResizeObserver === 'undefined') return\n\n const update = () => {\n const measured = isHorizontal ? el.clientWidth : el.clientHeight\n if (measured > 0) setContainerLength(measured)\n if (scrollRefProp) scrollRefProp.current = el\n }\n update()\n const ro = new ResizeObserver(update)\n ro.observe(el)\n return () => ro.disconnect()\n }, [enabled, effectiveScrollElement, isHorizontal, scrollRefProp, setContainerLength])\n\n useEffect(() => {\n if (!enabled || !effectiveScrollElement) return\n\n let cancelled = false\n let teardown: (() => void) | null = null\n const maxRetries = 20\n\n const tryAttach = (retryCount = 0) => {\n if (cancelled) return\n const target = effectiveScrollElement.current\n if (!target) {\n if (retryCount < maxRetries) {\n requestAnimationFrame(() => tryAttach(retryCount + 1))\n }\n return\n }\n\n const refs = refsRef.current\n if (!refs) return\n\n let inUpperZone = true\n let inLowerZone = false\n\n const handler = () => {\n const r = refsRef.current\n if (!r) return\n const scrollPos = isHorizontal ? target.scrollLeft : target.scrollTop\n const adjustedPos = scrollPos - effectiveStartOffsetRef.current\n const effectiveAdjusted = Math.max(0, adjustedPos)\n const clientSize = isHorizontal ? target.clientWidth : target.clientHeight\n r.scrollCorrection.markUserScrolling()\n updateRenderOffset(effectiveAdjusted, false, 'scrollElement')\n r.onScroll?.({ scrollTop: isHorizontal ? 0 : scrollPos, scrollLeft: isHorizontal ? scrollPos : 0 })\n\n const { upper, lower } = r.threshold\n const innerContentLen = r.listContentLength\n const nowInUpper = effectiveAdjusted <= upper\n const nowInLower = innerContentLen > 0 && effectiveAdjusted + clientSize >= innerContentLen - lower\n if (nowInUpper && !inUpperZone) r.onScrollToUpper?.()\n if (nowInLower && !inLowerZone) r.onScrollToLower?.()\n inUpperZone = nowInUpper\n inLowerZone = nowInLower\n }\n\n const initialScroll = isHorizontal ? target.scrollLeft : target.scrollTop\n const initialAdjusted = Math.max(0, initialScroll - effectiveStartOffsetRef.current)\n updateRenderOffset(initialAdjusted, false, 'scrollElement')\n\n target.addEventListener('scroll', handler, { passive: true })\n teardown = () => target.removeEventListener('scroll', handler)\n }\n\n tryAttach()\n return () => {\n cancelled = true\n teardown?.()\n }\n }, [enabled, effectiveScrollElement, isHorizontal, effectiveStartOffset, updateRenderOffset, refsRef])\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useListScrollElementAttach.js","sources":["../../../../src/components/list/hooks/useListScrollElementAttach.ts"],"sourcesContent":["import { useEffect, useRef } from 'react'\n\nimport type { RefObject } from 'react'\n\nexport interface ListScrollElementAttachRefs {\n scrollCorrection: { markUserScrolling: () => void }\n onScroll: ((e: { scrollTop: number, scrollLeft: number, detail: { scrollTop: number, scrollLeft: number } }) => void) | undefined\n onScrollToUpper: (() => void) | undefined\n onScrollToLower: (() => void) | undefined\n threshold: { upper: number, lower: number }\n listContentLength: number\n}\n\n/**\n * scrollElement 模式下:监听外部滚动驱动 renderOffset,并从 scrollElement 获取 containerLength\n */\nexport function useListScrollElementAttach(\n enabled: boolean,\n effectiveScrollElement: RefObject<HTMLElement | null> | null,\n effectiveStartOffset: number,\n isHorizontal: boolean,\n setContainerLength: (v: number) => void,\n updateRenderOffset: (offset: number, sync?: boolean, source?: string) => void,\n scrollRefProp: React.MutableRefObject<HTMLElement | null> | undefined,\n refsRef: RefObject<ListScrollElementAttachRefs>\n) {\n const effectiveStartOffsetRef = useRef(effectiveStartOffset)\n effectiveStartOffsetRef.current = effectiveStartOffset\n\n useEffect(() => {\n if (!enabled || !effectiveScrollElement) return\n const el = effectiveScrollElement.current\n if (!el || typeof ResizeObserver === 'undefined') return\n\n const update = () => {\n const measured = isHorizontal ? el.clientWidth : el.clientHeight\n if (measured > 0) setContainerLength(measured)\n if (scrollRefProp) scrollRefProp.current = el\n }\n update()\n const ro = new ResizeObserver(update)\n ro.observe(el)\n return () => ro.disconnect()\n }, [enabled, effectiveScrollElement, isHorizontal, scrollRefProp, setContainerLength])\n\n useEffect(() => {\n if (!enabled || !effectiveScrollElement) return\n\n let cancelled = false\n let teardown: (() => void) | null = null\n const maxRetries = 20\n\n const tryAttach = (retryCount = 0) => {\n if (cancelled) return\n const target = effectiveScrollElement.current\n if (!target) {\n if (retryCount < maxRetries) {\n requestAnimationFrame(() => tryAttach(retryCount + 1))\n }\n return\n }\n\n const refs = refsRef.current\n if (!refs) return\n\n let inUpperZone = true\n let inLowerZone = false\n\n const handler = () => {\n const r = refsRef.current\n if (!r) return\n const scrollPos = isHorizontal ? target.scrollLeft : target.scrollTop\n const adjustedPos = scrollPos - effectiveStartOffsetRef.current\n const effectiveAdjusted = Math.max(0, adjustedPos)\n const clientSize = isHorizontal ? target.clientWidth : target.clientHeight\n r.scrollCorrection.markUserScrolling()\n updateRenderOffset(effectiveAdjusted, false, 'scrollElement')\n const scrollTop = isHorizontal ? 0 : scrollPos\n const scrollLeft = isHorizontal ? scrollPos : 0\n r.onScroll?.({ scrollTop, scrollLeft, detail: { scrollTop, scrollLeft } })\n\n const { upper, lower } = r.threshold\n const innerContentLen = r.listContentLength\n const nowInUpper = effectiveAdjusted <= upper\n const nowInLower = innerContentLen > 0 && effectiveAdjusted + clientSize >= innerContentLen - lower\n if (nowInUpper && !inUpperZone) r.onScrollToUpper?.()\n if (nowInLower && !inLowerZone) r.onScrollToLower?.()\n inUpperZone = nowInUpper\n inLowerZone = nowInLower\n }\n\n const initialScroll = isHorizontal ? target.scrollLeft : target.scrollTop\n const initialAdjusted = Math.max(0, initialScroll - effectiveStartOffsetRef.current)\n updateRenderOffset(initialAdjusted, false, 'scrollElement')\n\n target.addEventListener('scroll', handler, { passive: true })\n teardown = () => target.removeEventListener('scroll', handler)\n }\n\n tryAttach()\n return () => {\n cancelled = true\n teardown?.()\n }\n }, [enabled, effectiveScrollElement, isHorizontal, effectiveStartOffset, updateRenderOffset, refsRef])\n}\n"],"names":[],"mappings":"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"}
@@ -100,10 +100,9 @@ fallbackContainerLength) {
100
100
  const effectiveAdjusted = Math.max(0, adjustedPos);
101
101
  r.scrollCorrection.markUserScrolling();
102
102
  updateRenderOffset(effectiveAdjusted, false, 'scrollElement');
103
- (_l = r.onScroll) === null || _l === void 0 ? void 0 : _l.call(r, {
104
- scrollTop: isHorizontal ? 0 : scrollPos,
105
- scrollLeft: isHorizontal ? scrollPos : 0,
106
- });
103
+ const scrollTop = isHorizontal ? 0 : scrollPos;
104
+ const scrollLeft = isHorizontal ? scrollPos : 0;
105
+ (_l = r.onScroll) === null || _l === void 0 ? void 0 : _l.call(r, { scrollTop, scrollLeft, detail: { scrollTop, scrollLeft } });
107
106
  // 兜底:measure 未完成时 containerLengthRef 为 0,用 fallback 参与触顶/触底判断,避免漏触发
108
107
  const clientSize = containerLengthRef.current || fallbackContainerLength || 0;
109
108
  if (clientSize > 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"useListScrollElementAttachWeapp.js","sources":["../../../../src/components/list/hooks/useListScrollElementAttachWeapp.ts"],"sourcesContent":["import Taro from '@tarojs/taro'\nimport { useEffect, useRef } from 'react'\n\nimport type { MutableRefObject, RefObject } from 'react'\nimport type { ListScrollElementAttachRefs } from './useListScrollElementAttach'\n\n/**\n * 小程序版 scrollElement 模式:监听外部 scroll-view 的滚动事件驱动 renderOffset,\n * 并通过 createSelectorQuery 测量容器尺寸。\n *\n * 与 H5 版 useListScrollElementAttach 的区别:\n * - 容器尺寸通过 createSelectorQuery 测量(无 ResizeObserver)\n * - 滚动事件通过 TaroElement.addEventListener,格式为 TaroEvent(detail 合并到 target 上)\n * - 若 scroll-view 无 id,自动分配临时 id 供 SelectorQuery 使用\n */\nexport function useListScrollElementAttachWeapp(\n enabled: boolean,\n effectiveScrollElement: RefObject<HTMLElement | null> | null,\n effectiveStartOffsetRef: MutableRefObject<number>,\n effectiveStartOffset: number,\n isHorizontal: boolean,\n setContainerLength: (v: number) => void,\n updateRenderOffset: (offset: number, sync?: boolean, source?: string) => void,\n scrollRefProp: React.MutableRefObject<HTMLElement | null> | undefined,\n refsRef: RefObject<ListScrollElementAttachRefs>,\n /**\n * 【兜底】容器尺寸测量失败或未完成时的回退值。\n *\n * 使用场景:\n * 1. 首次 scroll:SelectorQuery.exec 异步,scroll 事件可能早于测量回调,containerLengthRef 仍为 0\n * 2. 测量长期失败:SelectorQuery 返回空或 rect 尺寸为 0(如 id 错误、节点未挂载)\n *\n * 兜底逻辑:\n * - measure 回调:rect 为空或 measured≤0 时,若有 fallback 则写入 containerLengthRef 与 setContainerLength\n * - scroll handler:containerLengthRef 为 0 时,用 fallback 参与 onScrollToUpper/Lower 判断\n *\n * 取值建议:与 List 的 initialContainerLength 一致(默认 400,或 height/width prop),避免与 renderRange 等逻辑冲突。\n * 注意:fallback 与真实视口差异大时,onScrollToUpper/Lower 可能误触发;measure 每 150ms 轮询,正常会很快覆盖。\n */\n fallbackContainerLength?: number\n) {\n const containerLengthRef = useRef(0)\n const autoIdRef = useRef(`_ls_${Math.random().toString(36).slice(2, 9)}`)\n\n useEffect(() => {\n if (!enabled || !effectiveScrollElement) return\n const el = effectiveScrollElement.current as any\n if (!el) return\n if (scrollRefProp) scrollRefProp.current = el\n\n if (!el.id) {\n el.id = autoIdRef.current\n }\n const scrollViewId = el.id\n\n const measure = () => {\n const instance = Taro.getCurrentInstance()\n const query = instance?.page\n ? Taro.createSelectorQuery().in(instance.page as any)\n : Taro.createSelectorQuery()\n query\n .select(`#${scrollViewId}`)\n .boundingClientRect()\n .exec((res) => {\n const rect = res?.[0]\n if (rect) {\n const measured = isHorizontal ? rect.width : rect.height\n if (measured > 0) {\n containerLengthRef.current = measured\n setContainerLength(measured)\n return\n }\n }\n // 兜底:rect 为空或 measured≤0 时,使用 fallback 避免 containerLengthRef 长期为 0\n if (fallbackContainerLength != null && fallbackContainerLength > 0) {\n containerLengthRef.current = fallbackContainerLength\n setContainerLength(fallbackContainerLength)\n }\n })\n }\n\n measure()\n const interval = setInterval(measure, 150)\n return () => clearInterval(interval)\n }, [enabled, effectiveScrollElement, isHorizontal, scrollRefProp, setContainerLength, fallbackContainerLength])\n\n useEffect(() => {\n if (!enabled || !effectiveScrollElement) return\n\n let cancelled = false\n let teardown: (() => void) | null = null\n const maxRetries = 20\n\n const tryAttach = (retryCount = 0) => {\n if (cancelled) return\n const target = effectiveScrollElement.current as any\n if (!target) {\n if (retryCount < maxRetries) {\n setTimeout(() => tryAttach(retryCount + 1), 50)\n }\n return\n }\n\n let inUpperZone = true\n let inLowerZone = false\n\n const handler = (e: any) => {\n const r = refsRef.current\n if (!r) return\n\n const scrollPos = isHorizontal\n ? (e?.target?.scrollLeft ?? e?.mpEvent?.detail?.scrollLeft ?? 0)\n : (e?.target?.scrollTop ?? e?.mpEvent?.detail?.scrollTop ?? 0)\n const startOffset = effectiveStartOffsetRef.current\n const adjustedPos = scrollPos - startOffset\n const effectiveAdjusted = Math.max(0, adjustedPos)\n\n r.scrollCorrection.markUserScrolling()\n updateRenderOffset(effectiveAdjusted, false, 'scrollElement')\n r.onScroll?.({\n scrollTop: isHorizontal ? 0 : scrollPos,\n scrollLeft: isHorizontal ? scrollPos : 0,\n })\n\n // 兜底:measure 未完成时 containerLengthRef 为 0,用 fallback 参与触顶/触底判断,避免漏触发\n const clientSize = containerLengthRef.current || fallbackContainerLength || 0\n if (clientSize > 0) {\n const { upper, lower } = r.threshold\n const innerContentLen = r.listContentLength\n const nowInUpper = effectiveAdjusted <= upper\n const nowInLower = innerContentLen > 0 && effectiveAdjusted + clientSize >= innerContentLen - lower\n if (nowInUpper && !inUpperZone) r.onScrollToUpper?.()\n if (nowInLower && !inLowerZone) r.onScrollToLower?.()\n inUpperZone = nowInUpper\n inLowerZone = nowInLower\n }\n }\n\n target.addEventListener('scroll', handler)\n teardown = () => target.removeEventListener('scroll', handler)\n\n // 初始 renderOffset:weapp 无法直接读 target.scrollTop,需通过 SelectorQuery 查询\n const scrollViewId = target.id || autoIdRef.current\n if (!target.id) target.id = scrollViewId\n const instance = Taro.getCurrentInstance()\n const query = instance?.page\n ? Taro.createSelectorQuery().in(instance.page as any)\n : Taro.createSelectorQuery()\n query.select(`#${scrollViewId}`).scrollOffset().exec((res) => {\n const info = res?.[0]\n if (info) {\n const scrollTopVal = info.scrollTop ?? 0\n const scrollLeftVal = info.scrollLeft ?? 0\n const scrollPos = isHorizontal ? scrollLeftVal : scrollTopVal\n const startOffset = effectiveStartOffsetRef.current\n const initialAdjusted = Math.max(0, scrollPos - startOffset)\n updateRenderOffset(initialAdjusted, false, 'scrollElement')\n }\n })\n }\n\n tryAttach()\n return () => {\n cancelled = true\n teardown?.()\n }\n }, [enabled, effectiveScrollElement, isHorizontal, effectiveStartOffsetRef, effectiveStartOffset, updateRenderOffset, refsRef, fallbackContainerLength])\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useListScrollElementAttachWeapp.js","sources":["../../../../src/components/list/hooks/useListScrollElementAttachWeapp.ts"],"sourcesContent":["import Taro from '@tarojs/taro'\nimport { useEffect, useRef } from 'react'\n\nimport type { MutableRefObject, RefObject } from 'react'\nimport type { ListScrollElementAttachRefs } from './useListScrollElementAttach'\n\n/**\n * 小程序版 scrollElement 模式:监听外部 scroll-view 的滚动事件驱动 renderOffset,\n * 并通过 createSelectorQuery 测量容器尺寸。\n *\n * 与 H5 版 useListScrollElementAttach 的区别:\n * - 容器尺寸通过 createSelectorQuery 测量(无 ResizeObserver)\n * - 滚动事件通过 TaroElement.addEventListener,格式为 TaroEvent(detail 合并到 target 上)\n * - 若 scroll-view 无 id,自动分配临时 id 供 SelectorQuery 使用\n */\nexport function useListScrollElementAttachWeapp(\n enabled: boolean,\n effectiveScrollElement: RefObject<HTMLElement | null> | null,\n effectiveStartOffsetRef: MutableRefObject<number>,\n effectiveStartOffset: number,\n isHorizontal: boolean,\n setContainerLength: (v: number) => void,\n updateRenderOffset: (offset: number, sync?: boolean, source?: string) => void,\n scrollRefProp: React.MutableRefObject<HTMLElement | null> | undefined,\n refsRef: RefObject<ListScrollElementAttachRefs>,\n /**\n * 【兜底】容器尺寸测量失败或未完成时的回退值。\n *\n * 使用场景:\n * 1. 首次 scroll:SelectorQuery.exec 异步,scroll 事件可能早于测量回调,containerLengthRef 仍为 0\n * 2. 测量长期失败:SelectorQuery 返回空或 rect 尺寸为 0(如 id 错误、节点未挂载)\n *\n * 兜底逻辑:\n * - measure 回调:rect 为空或 measured≤0 时,若有 fallback 则写入 containerLengthRef 与 setContainerLength\n * - scroll handler:containerLengthRef 为 0 时,用 fallback 参与 onScrollToUpper/Lower 判断\n *\n * 取值建议:与 List 的 initialContainerLength 一致(默认 400,或 height/width prop),避免与 renderRange 等逻辑冲突。\n * 注意:fallback 与真实视口差异大时,onScrollToUpper/Lower 可能误触发;measure 每 150ms 轮询,正常会很快覆盖。\n */\n fallbackContainerLength?: number\n) {\n const containerLengthRef = useRef(0)\n const autoIdRef = useRef(`_ls_${Math.random().toString(36).slice(2, 9)}`)\n\n useEffect(() => {\n if (!enabled || !effectiveScrollElement) return\n const el = effectiveScrollElement.current as any\n if (!el) return\n if (scrollRefProp) scrollRefProp.current = el\n\n if (!el.id) {\n el.id = autoIdRef.current\n }\n const scrollViewId = el.id\n\n const measure = () => {\n const instance = Taro.getCurrentInstance()\n const query = instance?.page\n ? Taro.createSelectorQuery().in(instance.page as any)\n : Taro.createSelectorQuery()\n query\n .select(`#${scrollViewId}`)\n .boundingClientRect()\n .exec((res) => {\n const rect = res?.[0]\n if (rect) {\n const measured = isHorizontal ? rect.width : rect.height\n if (measured > 0) {\n containerLengthRef.current = measured\n setContainerLength(measured)\n return\n }\n }\n // 兜底:rect 为空或 measured≤0 时,使用 fallback 避免 containerLengthRef 长期为 0\n if (fallbackContainerLength != null && fallbackContainerLength > 0) {\n containerLengthRef.current = fallbackContainerLength\n setContainerLength(fallbackContainerLength)\n }\n })\n }\n\n measure()\n const interval = setInterval(measure, 150)\n return () => clearInterval(interval)\n }, [enabled, effectiveScrollElement, isHorizontal, scrollRefProp, setContainerLength, fallbackContainerLength])\n\n useEffect(() => {\n if (!enabled || !effectiveScrollElement) return\n\n let cancelled = false\n let teardown: (() => void) | null = null\n const maxRetries = 20\n\n const tryAttach = (retryCount = 0) => {\n if (cancelled) return\n const target = effectiveScrollElement.current as any\n if (!target) {\n if (retryCount < maxRetries) {\n setTimeout(() => tryAttach(retryCount + 1), 50)\n }\n return\n }\n\n let inUpperZone = true\n let inLowerZone = false\n\n const handler = (e: any) => {\n const r = refsRef.current\n if (!r) return\n\n const scrollPos = isHorizontal\n ? (e?.target?.scrollLeft ?? e?.mpEvent?.detail?.scrollLeft ?? 0)\n : (e?.target?.scrollTop ?? e?.mpEvent?.detail?.scrollTop ?? 0)\n const startOffset = effectiveStartOffsetRef.current\n const adjustedPos = scrollPos - startOffset\n const effectiveAdjusted = Math.max(0, adjustedPos)\n\n r.scrollCorrection.markUserScrolling()\n updateRenderOffset(effectiveAdjusted, false, 'scrollElement')\n const scrollTop = isHorizontal ? 0 : scrollPos\n const scrollLeft = isHorizontal ? scrollPos : 0\n r.onScroll?.({ scrollTop, scrollLeft, detail: { scrollTop, scrollLeft } })\n\n // 兜底:measure 未完成时 containerLengthRef 为 0,用 fallback 参与触顶/触底判断,避免漏触发\n const clientSize = containerLengthRef.current || fallbackContainerLength || 0\n if (clientSize > 0) {\n const { upper, lower } = r.threshold\n const innerContentLen = r.listContentLength\n const nowInUpper = effectiveAdjusted <= upper\n const nowInLower = innerContentLen > 0 && effectiveAdjusted + clientSize >= innerContentLen - lower\n if (nowInUpper && !inUpperZone) r.onScrollToUpper?.()\n if (nowInLower && !inLowerZone) r.onScrollToLower?.()\n inUpperZone = nowInUpper\n inLowerZone = nowInLower\n }\n }\n\n target.addEventListener('scroll', handler)\n teardown = () => target.removeEventListener('scroll', handler)\n\n // 初始 renderOffset:weapp 无法直接读 target.scrollTop,需通过 SelectorQuery 查询\n const scrollViewId = target.id || autoIdRef.current\n if (!target.id) target.id = scrollViewId\n const instance = Taro.getCurrentInstance()\n const query = instance?.page\n ? Taro.createSelectorQuery().in(instance.page as any)\n : Taro.createSelectorQuery()\n query.select(`#${scrollViewId}`).scrollOffset().exec((res) => {\n const info = res?.[0]\n if (info) {\n const scrollTopVal = info.scrollTop ?? 0\n const scrollLeftVal = info.scrollLeft ?? 0\n const scrollPos = isHorizontal ? scrollLeftVal : scrollTopVal\n const startOffset = effectiveStartOffsetRef.current\n const initialAdjusted = Math.max(0, scrollPos - startOffset)\n updateRenderOffset(initialAdjusted, false, 'scrollElement')\n }\n })\n }\n\n tryAttach()\n return () => {\n cancelled = true\n teardown?.()\n }\n }, [enabled, effectiveScrollElement, isHorizontal, effectiveStartOffsetRef, effectiveStartOffset, updateRenderOffset, refsRef, fallbackContainerLength])\n}\n"],"names":[],"mappings":"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"}
@@ -12,6 +12,10 @@ export interface ListProps {
12
12
  onScroll?: (e: {
13
13
  scrollTop: number;
14
14
  scrollLeft: number;
15
+ detail: {
16
+ scrollTop: number;
17
+ scrollLeft: number;
18
+ };
15
19
  }) => void;
16
20
  onScrollToUpper?: () => void;
17
21
  onScrollToLower?: () => void;
@@ -37,12 +41,9 @@ export interface ListProps {
37
41
  width?: number | string;
38
42
  style?: React.CSSProperties;
39
43
  children?: React.ReactNode;
40
- headerHeight?: number;
41
- headerWidth?: number;
42
- itemHeight?: number;
43
- itemWidth?: number;
44
+ /** Header 沿滚动方向尺寸;未传时回退到 itemSize */
45
+ headerSize?: number;
44
46
  useResizeObserver?: boolean;
45
- estimatedItemSize?: number;
46
47
  onItemSizeChange?: (index: number, size: number) => void;
47
48
  showNoMore?: boolean;
48
49
  noMoreText?: string;
@@ -65,13 +65,31 @@ function resolveScrollTargetOffset(options, isHorizontal) {
65
65
  }
66
66
  // eslint-disable-next-line complexity -- List 多端/多模式逻辑集中,已抽离 useListNestedScroll、useListScrollElementAttach、resolveScrollTargetOffset 等
67
67
  const InnerList = (props, ref) => {
68
- var _a, _b, _c;
68
+ var _a, _b;
69
69
  const { stickyHeader = false, space = 0, height = 400, width = '100%', showScrollbar = true, scrollTop: controlledScrollTop, scrollX = false, scrollY = true, onScroll, onScrollToUpper, onScrollToLower, onScrollStart, onScrollEnd, upperThreshold = 50, lowerThreshold = 50, cacheCount = 2, cacheExtent, enableBackToTop, className, style, children, nestedScroll, scrollElement, scrollRef: scrollRefProp, } = props;
70
70
  const isHorizontal = scrollX === true;
71
71
  const listType = nestedScroll === true ? 'nested' : 'default';
72
72
  const { effectiveScrollElement, effectiveStartOffset, effectiveStartOffsetRef, useScrollElementMode, needAutoFind, autoFindStatus, contentWrapperRef, contentId, } = useListNestedScroll(listType, scrollElement, undefined, isHorizontal);
73
73
  const DEFAULT_ITEM_WIDTH = 120;
74
74
  const DEFAULT_ITEM_HEIGHT = 40;
75
+ const defaultItemSize = isHorizontal ? DEFAULT_ITEM_WIDTH : DEFAULT_ITEM_HEIGHT;
76
+ const normalizeSize = React.useCallback((value) => {
77
+ if (typeof value !== 'number' || !Number.isFinite(value) || value <= 0)
78
+ return null;
79
+ return value;
80
+ }, []);
81
+ const resolveItemSizeByIndex = React.useCallback((index, fallback) => {
82
+ const { itemSize, itemData } = props;
83
+ const numberSize = normalizeSize(itemSize);
84
+ if (numberSize != null)
85
+ return numberSize;
86
+ if (typeof itemSize === 'function') {
87
+ const functionSize = normalizeSize(itemSize(index, itemData));
88
+ if (functionSize != null)
89
+ return functionSize;
90
+ }
91
+ return fallback;
92
+ }, [props.itemSize, props.itemData, normalizeSize]);
75
93
  // 滚动状态管理
76
94
  const containerRef = React.useRef(null);
77
95
  // 生成唯一 List ID(用于小程序 ResizeObserver)
@@ -326,8 +344,7 @@ const InnerList = (props, ref) => {
326
344
  return result;
327
345
  }, [children]);
328
346
  // 动态尺寸管理
329
- const defaultEstimatedSize = isHorizontal ? DEFAULT_ITEM_WIDTH : DEFAULT_ITEM_HEIGHT;
330
- const estimatedSize = (_a = props.estimatedItemSize) !== null && _a !== void 0 ? _a : defaultEstimatedSize;
347
+ const estimatedSize = resolveItemSizeByIndex(0, defaultItemSize);
331
348
  // 计算总 item 数量(跨所有 section)
332
349
  const totalItemCount = React.useMemo(() => {
333
350
  return sections.reduce((sum, section) => sum + section.items.length, 0);
@@ -346,7 +363,7 @@ const InnerList = (props, ref) => {
346
363
  // 动态尺寸缓存
347
364
  const sizeCache = useItemSizeCache({
348
365
  isHorizontal,
349
- estimatedItemSize: estimatedSize,
366
+ estimatedSize,
350
367
  itemCount: totalItemCount
351
368
  });
352
369
  // header 动态尺寸缓存(sectionIndex -> size)
@@ -375,6 +392,9 @@ const InnerList = (props, ref) => {
375
392
  onScrollToLowerRef.current = onScrollToLower;
376
393
  const thresholdRef = React.useRef({ upper: upperThreshold, lower: lowerThreshold });
377
394
  thresholdRef.current = { upper: upperThreshold, lower: lowerThreshold };
395
+ const listContentLengthRef = React.useRef(0);
396
+ const inUpperZoneRef = React.useRef(true);
397
+ const inLowerZoneRef = React.useRef(false);
378
398
  // 小程序 + 动高(virtual-list 风格):测量变化后同帧重排,不做程序性 scrollTop 回拉
379
399
  const scheduleWeappDynamicReflow = React.useCallback(() => {
380
400
  if (!isWeapp || props.useResizeObserver !== true)
@@ -440,30 +460,12 @@ const InnerList = (props, ref) => {
440
460
  });
441
461
  }
442
462
  }, [sizeCache, scrollCorrection, estimatedSize, isWeapp, props.useResizeObserver, scheduleWeappDynamicReflow]);
443
- const getDefaultHeaderSize = () => {
444
- if (isHorizontal) {
445
- if (typeof props.headerWidth === 'number')
446
- return props.headerWidth;
447
- if (typeof props.itemWidth === 'number')
448
- return props.itemWidth;
449
- if (typeof props.itemSize === 'number')
450
- return props.itemSize;
451
- if (typeof props.itemSize === 'function')
452
- return props.itemSize(0, props.itemData) || DEFAULT_ITEM_WIDTH;
453
- return DEFAULT_ITEM_WIDTH;
454
- }
455
- else {
456
- if (typeof props.headerHeight === 'number')
457
- return props.headerHeight;
458
- if (typeof props.itemHeight === 'number')
459
- return props.itemHeight;
460
- if (typeof props.itemSize === 'number')
461
- return props.itemSize;
462
- if (typeof props.itemSize === 'function')
463
- return props.itemSize(0, props.itemData) || DEFAULT_ITEM_HEIGHT;
464
- return DEFAULT_ITEM_HEIGHT;
465
- }
466
- };
463
+ const getDefaultHeaderSize = React.useCallback(() => {
464
+ const headerSize = normalizeSize(props.headerSize);
465
+ if (headerSize != null)
466
+ return headerSize;
467
+ return resolveItemSizeByIndex(0, defaultItemSize);
468
+ }, [props.headerSize, resolveItemSizeByIndex, defaultItemSize, normalizeSize]);
467
469
  // 获取 header 尺寸(支持动态测量)
468
470
  const getHeaderSize = React.useCallback((sectionIndex) => {
469
471
  if (props.useResizeObserver === true) {
@@ -472,30 +474,13 @@ const InnerList = (props, ref) => {
472
474
  return cached;
473
475
  }
474
476
  return getDefaultHeaderSize();
475
- }, [props.useResizeObserver, props.headerHeight, props.headerWidth, props.itemHeight, props.itemWidth, props.itemSize, props.itemData, isHorizontal]);
477
+ }, [props.useResizeObserver, getDefaultHeaderSize]);
476
478
  const getItemSize = React.useCallback((index) => {
477
479
  if (props.useResizeObserver === true) {
478
480
  return sizeCache.getItemSize(index);
479
481
  }
480
- if (isHorizontal) {
481
- if (typeof props.itemWidth === 'number')
482
- return props.itemWidth;
483
- if (typeof props.itemSize === 'number')
484
- return props.itemSize;
485
- if (typeof props.itemSize === 'function')
486
- return props.itemSize(index, props.itemData) || DEFAULT_ITEM_WIDTH;
487
- return DEFAULT_ITEM_WIDTH;
488
- }
489
- else {
490
- if (typeof props.itemHeight === 'number')
491
- return props.itemHeight;
492
- if (typeof props.itemSize === 'number')
493
- return props.itemSize;
494
- if (typeof props.itemSize === 'function')
495
- return props.itemSize(index, props.itemData) || DEFAULT_ITEM_HEIGHT;
496
- return DEFAULT_ITEM_HEIGHT;
497
- }
498
- }, [props.useResizeObserver, props.itemWidth, props.itemHeight, props.itemSize, props.itemData, isHorizontal, sizeCache]);
482
+ return resolveItemSizeByIndex(index, defaultItemSize);
483
+ }, [props.useResizeObserver, sizeCache, resolveItemSizeByIndex, defaultItemSize]);
499
484
  // 分组累积高度/宽度,sizeCacheVersion 变化时重算
500
485
  const sectionOffsets = React.useMemo(() => {
501
486
  const offsets = [0];
@@ -510,7 +495,7 @@ const InnerList = (props, ref) => {
510
495
  globalItemIndex += section.items.length;
511
496
  });
512
497
  return offsets;
513
- }, [sections, space, isHorizontal, props.headerHeight, props.headerWidth, props.itemHeight, props.itemWidth, props.itemSize, props.itemData, getItemSize, getHeaderSize, sizeCacheVersion]);
498
+ }, [sections, space, getItemSize, getHeaderSize, sizeCacheVersion]);
514
499
  // 外层虚拟滚动:可见分组
515
500
  const [startSection, endSection] = React.useMemo(() => {
516
501
  let start = 0;
@@ -570,6 +555,7 @@ const InnerList = (props, ref) => {
570
555
  }
571
556
  }, [visibleStartItem, visibleEndItem, props.onScrollIndex]);
572
557
  const handleScroll = React.useCallback((e) => {
558
+ var _a, _b, _c, _d;
573
559
  let newOffset;
574
560
  if (e.detail) {
575
561
  newOffset = isHorizontal ? e.detail.scrollLeft : e.detail.scrollTop;
@@ -578,6 +564,14 @@ const InnerList = (props, ref) => {
578
564
  newOffset = isHorizontal ? e.scrollLeft : e.scrollTop;
579
565
  }
580
566
  const effectiveOffset = newOffset;
567
+ const currentThreshold = thresholdRef.current;
568
+ const { upper, lower } = currentThreshold;
569
+ const currentContainerLength = containerRef.current
570
+ ? (isHorizontal ? containerRef.current.clientWidth : containerRef.current.clientHeight)
571
+ : containerLength;
572
+ const nowInUpper = effectiveOffset <= upper;
573
+ const currentContentLength = listContentLengthRef.current;
574
+ const nowInLower = currentContentLength > 0 && effectiveOffset + currentContainerLength >= currentContentLength - lower;
581
575
  const diff = effectiveOffset - lastScrollTopRef.current;
582
576
  scrollDiffListRef.current.shift();
583
577
  scrollDiffListRef.current.push(diff);
@@ -587,19 +581,29 @@ const InnerList = (props, ref) => {
587
581
  if (programmaticCooldownRef.current) {
588
582
  lastScrollTopRef.current = effectiveOffset;
589
583
  setRenderOffset(effectiveOffset);
590
- onScroll === null || onScroll === void 0 ? void 0 : onScroll({
591
- scrollTop: isHorizontal ? 0 : newOffset,
592
- scrollLeft: isHorizontal ? newOffset : 0
593
- });
584
+ const scrollTop = isHorizontal ? 0 : newOffset;
585
+ const scrollLeft = isHorizontal ? newOffset : 0;
586
+ onScroll === null || onScroll === void 0 ? void 0 : onScroll({ scrollTop, scrollLeft, detail: { scrollTop, scrollLeft } });
587
+ if (nowInUpper && !inUpperZoneRef.current)
588
+ (_a = onScrollToUpperRef.current) === null || _a === void 0 ? void 0 : _a.call(onScrollToUpperRef);
589
+ if (nowInLower && !inLowerZoneRef.current)
590
+ (_b = onScrollToLowerRef.current) === null || _b === void 0 ? void 0 : _b.call(onScrollToLowerRef);
591
+ inUpperZoneRef.current = nowInUpper;
592
+ inLowerZoneRef.current = nowInLower;
594
593
  return;
595
594
  }
596
595
  scrollCorrection.markUserScrolling();
597
596
  updateRenderOffset(effectiveOffset, false, 'onScroll');
598
- onScroll === null || onScroll === void 0 ? void 0 : onScroll({
599
- scrollTop: isHorizontal ? 0 : newOffset,
600
- scrollLeft: isHorizontal ? newOffset : 0
601
- });
602
- }, [isHorizontal, onScroll, updateRenderOffset, scrollCorrection, props.useResizeObserver]);
597
+ const scrollTop = isHorizontal ? 0 : newOffset;
598
+ const scrollLeft = isHorizontal ? newOffset : 0;
599
+ onScroll === null || onScroll === void 0 ? void 0 : onScroll({ scrollTop, scrollLeft, detail: { scrollTop, scrollLeft } });
600
+ if (nowInUpper && !inUpperZoneRef.current)
601
+ (_c = onScrollToUpperRef.current) === null || _c === void 0 ? void 0 : _c.call(onScrollToUpperRef);
602
+ if (nowInLower && !inLowerZoneRef.current)
603
+ (_d = onScrollToLowerRef.current) === null || _d === void 0 ? void 0 : _d.call(onScrollToLowerRef);
604
+ inUpperZoneRef.current = nowInUpper;
605
+ inLowerZoneRef.current = nowInLower;
606
+ }, [isHorizontal, onScroll, updateRenderOffset, scrollCorrection, props.useResizeObserver, containerLength]);
603
607
  // 小程序:onScrollEnd 优先结束 isUserScrolling,timeout 兜底
604
608
  const handleNativeScrollEnd = React.useCallback(() => {
605
609
  if (isWeapp) {
@@ -744,9 +748,7 @@ const InnerList = (props, ref) => {
744
748
  // ScrollView 属性
745
749
  const scrollViewProps = Object.assign(Object.assign(Object.assign(Object.assign({ scrollY: !scrollX && scrollY, scrollX, style: containerStyle, className, enhanced: true, showScrollbar,
746
750
  upperThreshold,
747
- lowerThreshold, scrollWithAnimation: false, onScroll: handleScroll, onScrollToUpper,
748
- onScrollToLower,
749
- onScrollStart, onScrollEnd: handleNativeScrollEnd, enableBackToTop }, (isWeapp ? { scrollAnchoring: true } : {})), (typeof cacheExtent === 'number' ? { cacheExtent } : {})), scrollViewRefresherProps), scrollViewRefresherHandlers);
751
+ lowerThreshold, scrollWithAnimation: false, onScroll: handleScroll, onScrollStart, onScrollEnd: handleNativeScrollEnd, enableBackToTop }, (isWeapp ? { scrollAnchoring: true } : {})), (typeof cacheExtent === 'number' ? { cacheExtent } : {})), scrollViewRefresherProps), scrollViewRefresherHandlers);
750
752
  // H5 对齐小程序:refresherTriggered=true 时顶部立即显示加载指示器,滚到顶部并锁定滚动直至设为 false
751
753
  React.useEffect(() => {
752
754
  if (!isH5 || !refresherConfig || supportsNativeRefresher || !h5RefresherProps.isRefreshing)
@@ -835,7 +837,6 @@ const InnerList = (props, ref) => {
835
837
  const listContentLength = sectionOffsets[sectionOffsets.length - 1] + noMoreHeight;
836
838
  const totalLength = listContentLength;
837
839
  // scrollElement 模式下 onScrollToLower 需用内层内容高度判断,供 scroll handler 读取
838
- const listContentLengthRef = React.useRef(0);
839
840
  listContentLengthRef.current = listContentLength;
840
841
  const scrollAttachRefsRef = React.useRef(null);
841
842
  scrollAttachRefsRef.current = {
@@ -874,7 +875,7 @@ const InnerList = (props, ref) => {
874
875
  }
875
876
  }
876
877
  return null;
877
- }, [stickyHeader, renderOffset, sectionOffsets, sections, isHorizontal, props.headerHeight, props.headerWidth, props.itemHeight, props.itemWidth, props.itemSize, props.itemData]);
878
+ }, [stickyHeader, renderOffset, sectionOffsets, sections]);
878
879
  // 渲染分组+item双层虚拟滚动
879
880
  const renderSections = () => {
880
881
  const nodes = [];
@@ -1218,7 +1219,7 @@ const InnerList = (props, ref) => {
1218
1219
  height: refresherHeightForH5,
1219
1220
  zIndex: 0,
1220
1221
  transform: `translateY(${h5RefresherTranslateY}px)`,
1221
- }, children: renderRefresherContent() }), jsxs(View, { style: Object.assign(Object.assign(Object.assign({}, listWrapperStyle), pullTranslate), { zIndex: 1, background: (_c = (_b = style === null || style === void 0 ? void 0 : style.background) !== null && _b !== void 0 ? _b : style === null || style === void 0 ? void 0 : style.backgroundColor) !== null && _c !== void 0 ? _c : '#fff' }), children: [stickyHeaderNode, renderSections(), renderNoMoreContent()] })] })) : (jsxs(Fragment, { children: [stickyHeaderNode, renderSections(), renderNoMoreContent()] })) }));
1222
+ }, children: renderRefresherContent() }), jsxs(View, { style: Object.assign(Object.assign(Object.assign({}, listWrapperStyle), pullTranslate), { zIndex: 1, background: (_b = (_a = style === null || style === void 0 ? void 0 : style.background) !== null && _a !== void 0 ? _a : style === null || style === void 0 ? void 0 : style.backgroundColor) !== null && _b !== void 0 ? _b : '#fff' }), children: [stickyHeaderNode, renderSections(), renderNoMoreContent()] })] })) : (jsxs(Fragment, { children: [stickyHeaderNode, renderSections(), renderNoMoreContent()] })) }));
1222
1223
  }
1223
1224
  return (jsxs(ScrollView, Object.assign({ ref: containerRef }, scrollViewProps, { id: listId, children: [supportsNativeRefresher && renderRefresherContent(), renderContentArea()] })));
1224
1225
  };