@tarojs/components-advanced 4.1.12-beta.28 → 4.1.12-beta.32

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 +1 @@
1
- {"version":3,"file":"useRefresher.js","sources":["../../../../src/components/list/hooks/useRefresher.tsx"],"sourcesContent":["import { Slot, View } from '@tarojs/components'\nimport React, { useCallback, useRef, useState } from 'react'\n\nimport { supportsNativeRefresher } from '../utils'\n\n/**\n * List 组件内部的 refresher 配置类型(独立于 Refresher 组件)\n * 与 ScrollView refresher 相关属性语义对齐\n */\nexport interface ListRefresherConfig {\n refresherEnabled?: boolean\n refresherThreshold?: number\n refresherDefaultStyle?: 'black' | 'white' | 'none'\n refresherBackground?: string\n refresherTriggered?: boolean\n /** 自定义刷新内容(来自 Refresher 子组件的 children) */\n children?: React.ReactNode\n onRefresherPulling?: (e?: { detail?: { deltaY?: number } }) => void\n onRefresherRefresh?: () => void | Promise<void>\n onRefresherRestore?: () => void\n onRefresherAbort?: () => void\n onRefresherWillRefresh?: () => void\n onRefresherStatusChange?: (e?: { detail?: { status?: number, dy?: number } }) => void\n}\n\n/**\n * useRefresher - 平台适配的下拉刷新\n *\n * - 小程序:weapp / jd / tt 使用 ScrollView 原生 refresher-*\n * - H5:对齐 taro-components-react pull-down-refresh(2.x 同源)逻辑:触顶 + 增量拖拽 + 阻尼 + 释放保持高度再回弹\n */\n\nconst BOUNCE_MS = 300\nconst AT_TOP_THRESHOLD = 3\n/** 最大下拉距离(px) */\nconst DISTANCE_Y_MAX_LIMIT = 150\n/** 阻尼系数:超过此值不再累加位移,与 2.x default damping 一致 */\nconst DAMPING = 100\n/** 角度上限(度),小于此值才视为下拉意图 */\nconst DEG_LIMIT = 40\n/** 默认刷新层高度(对齐 Dynamic),无自定义 children 时使用 */\nexport const DEFAULT_REFRESHER_HEIGHT = 50\n\n/** 下拉刷新状态枚举(对齐微信小程序 RefreshStatus) */\nexport const enum RefreshStatus {\n /** 空闲 */\n Idle = 0,\n /** 超过下拉刷新阈值 */\n CanRefresh = 1,\n /** 刷新中 */\n Refreshing = 2,\n /** 刷新完成 */\n Completed = 3,\n /** 刷新失败 */\n Failed = 4,\n}\n\n/**\n * 单次位移的阻尼(与 2.x PullDownRefresh.damping 一致)\n * ratio = 已拖拽总距离 / 屏幕高度,damped = diff * (1 - ratio) * 0.6;且当已超过 DAMPING 时不再加\n */\nfunction dampIncrement(\n diff: number,\n totalMove: number,\n currentPull: number,\n screenHeight: number\n): number {\n if (diff <= 0) return 0\n if (currentPull >= DAMPING) return 0\n const ratio = Math.min(totalMove / screenHeight, 1)\n return diff * (1 - ratio) * 0.6\n}\n\ninterface UseRefresherReturn {\n scrollViewRefresherProps: {\n refresherEnabled?: boolean\n refresherThreshold?: number\n refresherDefaultStyle?: string\n refresherBackground?: string\n refresherTriggered?: boolean\n }\n scrollViewRefresherHandlers: {\n onRefresherPulling?: (e: any) => void\n onRefresherRefresh?: (e: any) => void\n onRefresherRestore?: () => void\n onRefresherAbort?: () => void\n }\n h5RefresherProps: {\n touchHandlers: Record<string, unknown>\n pullDistance: number\n isRefreshing: boolean\n /** H5 单结构下恒为 true,仅兼容旧类型 */\n showRefresherLayer: boolean\n }\n addImperativeTouchListeners?: (el: HTMLElement) => () => void\n renderRefresherContent: () => React.ReactNode | null\n}\n\nexport function useRefresher(\n config: ListRefresherConfig | null,\n /** 列表逻辑顶部对应的 scrollTop,用于触顶判断;H5「顶栏悬浮+只滚列表」时传 0,imperative 内以 DOM scrollTop 为准 */\n scrollTopAtLogicalTop: number,\n /** scrollElement 模式下可选:下拉起始点须在 List 内才触发刷新;未传时默认 true(沿用原逻辑) */\n getIsTouchInListArea?: (ev: TouchEvent) => boolean\n): UseRefresherReturn {\n const [internalRefreshing, setInternalRefreshing] = useState(false)\n const [pullDistance, setPullDistance] = useState(0)\n const pullDistanceRef = useRef(0)\n const rafRef = useRef<number | null>(null)\n const setPullDistanceRef = useRef(setPullDistance)\n const setInternalRefreshingRef = useRef(setInternalRefreshing)\n setPullDistanceRef.current = setPullDistance\n setInternalRefreshingRef.current = setInternalRefreshing\n pullDistanceRef.current = pullDistance\n\n const isControlled = typeof config?.refresherTriggered === 'boolean'\n const isRefreshing = isControlled ? (config?.refresherTriggered ?? false) : internalRefreshing\n const isRefreshingRef = useRef(isRefreshing)\n isRefreshingRef.current = isRefreshing\n /** 刷新中锁:runRefresh 内同步置 true,避免 setState 未重渲染前再次触摸触发刷新 */\n const refreshingLockRef = useRef(false)\n /** H5 当前刷新状态,用于 onRefresherStatusChange 避免重复触发 */\n const refreshStatusRef = useRef<RefreshStatus>(RefreshStatus.Idle)\n /** H5 是否启用下拉刷新:refresherEnabled === false 时不挂 touch、不显示顶栏 */\n const h5RefresherEnabled = !!config && config.refresherEnabled !== false\n\n /** touch 只挂一次,回调里读 ref 才能拿到最新配置,避免改预设后仍用旧值 */\n const thresholdRef = useRef(config?.refresherThreshold ?? 45)\n thresholdRef.current = config?.refresherThreshold ?? 45\n const configRef = useRef(config)\n configRef.current = config\n\n /** H5:触发 onRefresherStatusChange 回调(仅状态变化时触发) */\n const emitStatusChangeRef = useRef((status: RefreshStatus, dy: number) => {\n if (refreshStatusRef.current !== status) {\n refreshStatusRef.current = status\n configRef.current?.onRefresherStatusChange?.({ detail: { status, dy } })\n }\n })\n const isControlledRef = useRef(isControlled)\n isControlledRef.current = isControlled\n /** H5 顶栏悬浮时 List 传 0,触顶即 scrollTop<=0+阈值;否则由 List 传列表顶对应的 scrollTop */\n const scrollTopWhenAtTop = !supportsNativeRefresher && config ? scrollTopAtLogicalTop : 0\n const topThresholdPx = scrollTopWhenAtTop + AT_TOP_THRESHOLD\n const topThresholdPxRef = useRef(topThresholdPx)\n topThresholdPxRef.current = topThresholdPx\n\n const getIsTouchInListAreaRef = useRef(getIsTouchInListArea)\n getIsTouchInListAreaRef.current = getIsTouchInListArea\n\n // ========================================\n // 小程序:原生 refresher-* API\n // ========================================\n const scrollViewRefresherProps = config && supportsNativeRefresher ? {\n refresherEnabled: config.refresherEnabled ?? true,\n refresherThreshold: config.refresherThreshold ?? 45,\n refresherDefaultStyle: config.refresherDefaultStyle ?? 'black',\n refresherBackground: config.refresherBackground ?? '#fff',\n refresherTriggered: isRefreshing,\n } : {}\n\n const scrollViewRefresherHandlers = config && supportsNativeRefresher ? {\n onRefresherPulling: (e: any) => {\n config.onRefresherPulling?.({ detail: { deltaY: e.detail?.deltaY ?? 0 } })\n },\n onRefresherRefresh: async () => {\n if (!isControlled) setInternalRefreshing(true)\n try {\n await config.onRefresherRefresh?.()\n } finally {\n if (!isControlled) setInternalRefreshing(false)\n }\n },\n onRefresherRestore: () => config.onRefresherRestore?.(),\n onRefresherAbort: () => config.onRefresherAbort?.(),\n // 小程序特有事件:即将触发刷新(拖动超过 threshold 时)\n onRefresherWillRefresh: () => config.onRefresherWillRefresh?.(),\n // 小程序特有事件:下拉刷新状态变化\n onRefresherStatusChange: (e: any) => {\n config.onRefresherStatusChange?.({ detail: { status: e.detail?.status, dy: e.detail?.dy } })\n },\n } : {}\n\n // ========================================\n // H5:单一结构 + 原生 touch 监听(passive: false);refresherEnabled=false 时不挂\n // ========================================\n const addImperativeTouchListeners = React.useCallback((el: HTMLElement) => {\n if (supportsNativeRefresher || !configRef.current || !h5RefresherEnabled) return () => {}\n const scrollEl = el as HTMLDivElement\n const startY = { current: 0 }\n const startX = { current: 0 }\n const lastY = { current: 0 }\n let touchStartedAtTop = false\n /** 下拉起始点是否在 List 内(scrollElement 模式);未传 getIsTouchInListArea 时恒为 true */\n let touchStartedInListArea = true\n let dragOnEdge = false\n let lastPull = 0\n /** 用于 onTouchEnd 判断是否触发刷新;刷新完成后必须置 0,否则下次点击(无 touchMove)会误用上次的 lastPull 再次触发 */\n const lastPullRef = { current: 0 }\n const pullAtReleaseRef = { current: 0 }\n const screenHeight = typeof window !== 'undefined' ? window.screen?.height ?? 600 : 600\n\n const setPull = (v: number) => {\n lastPull = v\n lastPullRef.current = v\n setPullDistanceRef.current(v)\n }\n\n const runBounceBack = (fromValue: number, onComplete?: () => void) => {\n if (rafRef.current != null) cancelAnimationFrame(rafRef.current)\n const startTime = performance.now()\n const animate = () => {\n const t = Math.min((performance.now() - startTime) / BOUNCE_MS, 1)\n const ease = 1 - Math.pow(1 - t, 3)\n const v = fromValue * (1 - ease)\n setPullDistanceRef.current(v)\n lastPullRef.current = v\n lastPull = v\n if (t < 1) {\n rafRef.current = requestAnimationFrame(animate)\n } else {\n setPullDistanceRef.current(0)\n // 修复闭包问题:使用 ref 获取最新值\n if (!isControlledRef.current) setInternalRefreshingRef.current(false)\n rafRef.current = null\n onComplete?.()\n }\n }\n rafRef.current = requestAnimationFrame(animate)\n }\n\n /** 未达阈值松手回弹结束:通知中止 */\n const runBounceBackAbort = (fromValue: number) => {\n if (rafRef.current != null) cancelAnimationFrame(rafRef.current)\n const startTime = performance.now()\n const animate = () => {\n const t = Math.min((performance.now() - startTime) / BOUNCE_MS, 1)\n const ease = 1 - Math.pow(1 - t, 3)\n const v = fromValue * (1 - ease)\n setPullDistanceRef.current(v)\n lastPullRef.current = v\n lastPull = v\n if (t < 1) rafRef.current = requestAnimationFrame(animate)\n else {\n setPullDistanceRef.current(0)\n rafRef.current = null\n lastPullRef.current = 0\n lastPull = 0\n configRef.current?.onRefresherAbort?.()\n // 状态变化:回到 Idle\n emitStatusChangeRef.current(RefreshStatus.Idle, 0)\n }\n }\n rafRef.current = requestAnimationFrame(animate)\n }\n\n /** 先动画到 refresherHeight(加载中保持高度),再执行刷新,完成后回弹;与 2.x release 时 setContentStyle(distanceToRefresh+1) 一致 */\n const runBounceToLoading = (fromValue: number, toValue: number, onReach: () => void) => {\n if (rafRef.current != null) cancelAnimationFrame(rafRef.current)\n const startTime = performance.now()\n const animate = () => {\n const t = Math.min((performance.now() - startTime) / BOUNCE_MS, 1)\n const ease = 1 - Math.pow(1 - t, 3)\n setPullDistanceRef.current(fromValue + (toValue - fromValue) * ease)\n if (t < 1) {\n rafRef.current = requestAnimationFrame(animate)\n } else {\n setPullDistanceRef.current(toValue)\n rafRef.current = null\n onReach()\n }\n }\n rafRef.current = requestAnimationFrame(animate)\n }\n\n const isEdge = () => (scrollEl.scrollTop ?? 0) <= topThresholdPxRef.current\n\n const onTouchStart = (e: TouchEvent) => {\n if (refreshingLockRef.current || isRefreshingRef.current) return\n if (rafRef.current != null) {\n cancelAnimationFrame(rafRef.current)\n rafRef.current = null\n }\n lastPull = lastPullRef.current\n touchStartedAtTop = isEdge()\n touchStartedInListArea = getIsTouchInListAreaRef.current?.(e) ?? true\n const t0 = e.touches[0]\n if (t0) {\n startY.current = t0.clientY\n startX.current = t0.clientX\n lastY.current = t0.clientY\n }\n }\n\n const onTouchMove = (ev: TouchEvent) => {\n if (refreshingLockRef.current || isRefreshingRef.current) return\n if (!touchStartedInListArea) return\n const touch = ev.touches[0]\n if (!touch) return\n const currentY = touch.clientY\n const currentX = touch.clientX\n if (!isEdge()) {\n setPull(0)\n dragOnEdge = false\n return\n }\n // 到顶后:若 touch 开始时不在顶部,在首次下拉(dy>0)时「采纳」该手势,使同一手势内滚到顶后继续下拉可触发刷新\n if (!touchStartedAtTop && !dragOnEdge) {\n const dyCheck = currentY - lastY.current\n if (dyCheck <= 0) return\n touchStartedAtTop = true\n // 重置起点,避免采纳时 dy 过大导致刷新层瞬间拉满\n startY.current = currentY\n startX.current = currentX\n lastY.current = currentY\n }\n\n const dy = currentY - lastY.current\n // 还没进入下拉拖拽阶段(dragOnEdge=false)时,先看第一下是往上还是往下:\n // - 第一笔就是往上滑(dy<=0):视为正常滚动,直接交给原生 Scroll,不拦截、不启动下拉逻辑\n // - 第一笔是往下滑(dy>0):才认为是一次「下拉刷新」手势,进入拖拽模式\n if (!dragOnEdge) {\n if (dy <= 0) {\n lastY.current = currentY\n startY.current = currentY\n startX.current = currentX\n return\n }\n // 真正开始下拉刷新\n dragOnEdge = true\n startY.current = currentY\n startX.current = currentX\n }\n\n if (ev.cancelable) ev.preventDefault()\n const totalMove = currentY - startY.current\n const dx = currentX - startX.current\n if (dy <= 0) {\n lastY.current = currentY\n const next = Math.max(0, lastPull + dy)\n setPull(next)\n return\n }\n const deg = Math.atan(Math.abs(dx) / dy) * (180 / Math.PI)\n if (deg > DEG_LIMIT) {\n startY.current = currentY\n startX.current = currentX\n lastY.current = currentY\n return\n }\n lastY.current = currentY\n const damped = dampIncrement(dy, totalMove, lastPull, screenHeight)\n const next = Math.min(lastPull + damped, DISTANCE_Y_MAX_LIMIT)\n setPull(next)\n configRef.current?.onRefresherPulling?.({ detail: { deltaY: next } })\n if (next >= thresholdRef.current) {\n configRef.current?.onRefresherWillRefresh?.()\n emitStatusChangeRef.current(RefreshStatus.CanRefresh, next)\n } else {\n emitStatusChangeRef.current(RefreshStatus.Idle, next)\n }\n }\n\n const runRefresh = () => {\n const cfg = configRef.current\n if (!cfg || refreshingLockRef.current || isRefreshingRef.current) return\n refreshingLockRef.current = true\n const pullValue = lastPull\n const height = DEFAULT_REFRESHER_HEIGHT\n pullAtReleaseRef.current = pullValue\n if (!isControlledRef.current) setInternalRefreshingRef.current(true)\n // 状态变化:Refreshing\n emitStatusChangeRef.current(RefreshStatus.Refreshing, pullValue)\n runBounceToLoading(pullValue, height, () => {\n const safeReset = () => {\n setPullDistanceRef.current(0)\n if (!isControlledRef.current) setInternalRefreshingRef.current(false)\n refreshingLockRef.current = false\n lastPullRef.current = 0\n lastPull = 0\n pullAtReleaseRef.current = 0\n configRef.current?.onRefresherRestore?.()\n // 状态变化:回到 Idle\n emitStatusChangeRef.current(RefreshStatus.Idle, 0)\n }\n const timeoutId = setTimeout(safeReset, BOUNCE_MS + 400)\n Promise.resolve(configRef.current?.onRefresherRefresh?.())\n .then(\n () => {\n // 若已经通过 safeReset 提前结束刷新(例如超时),则不再执行回弹动画,避免二次「吐舌头」闪现\n if (!refreshingLockRef.current) return\n // 状态变化:Completed\n emitStatusChangeRef.current(RefreshStatus.Completed, DEFAULT_REFRESHER_HEIGHT)\n requestAnimationFrame(() =>\n runBounceBack(DEFAULT_REFRESHER_HEIGHT, () => {\n clearTimeout(timeoutId)\n refreshingLockRef.current = false\n lastPullRef.current = 0\n lastPull = 0\n pullAtReleaseRef.current = 0\n configRef.current?.onRefresherRestore?.()\n // 状态变化:回到 Idle\n emitStatusChangeRef.current(RefreshStatus.Idle, 0)\n })\n )\n },\n () => {\n clearTimeout(timeoutId)\n safeReset()\n }\n )\n })\n }\n\n const onTouchEnd = () => {\n if (refreshingLockRef.current) return\n if (!touchStartedInListArea) return\n dragOnEdge = false\n const current = lastPullRef.current\n if (current >= thresholdRef.current) {\n runRefresh()\n } else {\n if (current > 0) {\n runBounceBackAbort(current)\n }\n }\n }\n\n const optsMove = { passive: false, capture: true }\n const optsEnd = { passive: true, capture: true }\n el.addEventListener('touchstart', onTouchStart, { passive: true })\n el.addEventListener('touchmove', onTouchMove, optsMove)\n el.addEventListener('touchend', onTouchEnd, optsEnd)\n el.addEventListener('touchcancel', onTouchEnd, optsEnd)\n return () => {\n if (rafRef.current != null) cancelAnimationFrame(rafRef.current)\n el.removeEventListener('touchstart', onTouchStart)\n el.removeEventListener('touchmove', onTouchMove, optsMove)\n el.removeEventListener('touchend', onTouchEnd, optsEnd)\n el.removeEventListener('touchcancel', onTouchEnd, optsEnd)\n }\n }, [h5RefresherEnabled])\n\n const renderRefresherContent = useCallback(() => {\n if (!config) return null\n const threshold = config.refresherThreshold ?? 45\n const defaultStyle = config.refresherDefaultStyle ?? 'black'\n const background = config.refresherBackground ?? '#fff'\n const hasCustomChildren = config.children != null\n\n // 小程序:自定义内容时返回 Slot(name=refresher),避免 View 的 slot 属性在模板层被过滤\n // 样式对齐 H5:由内层 View 统一承载容器样式\n if (supportsNativeRefresher) {\n // 小程序需要名为 refresher 的插槽来指定自定义刷新内容\n return hasCustomChildren && defaultStyle === 'none'\n ? (\n <Slot\n name=\"refresher\"\n style={{\n position: 'absolute',\n left: 0,\n right: 0,\n zIndex: 0,\n }}\n >\n <View\n style={{\n width: '100%',\n flexShrink: 0,\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n background,\n }}\n >\n {config.children}\n </View>\n </Slot>\n )\n : null\n }\n\n // H5:refresherDefaultStyle 控制默认指示器样式(对齐小程序 black/white/none)\n // black=深色文案 white=浅色文案 none=仅展示 children,不展示默认「下拉/释放/加载中」\n const textColor = defaultStyle === 'white' ? '#fff' : defaultStyle === 'black' ? '#333' : undefined\n // 有自定义 children 且 style=none 时隐藏默认文字\n const showDefaultText = !(defaultStyle === 'none' && hasCustomChildren)\n const defaultText = showDefaultText\n ? (isRefreshing ? '加载中...' : pullDistance >= threshold ? '释放刷新' : '下拉刷新')\n : null\n\n return (\n <View\n style={{\n width: '100%',\n minHeight: hasCustomChildren ? undefined : DEFAULT_REFRESHER_HEIGHT,\n height: hasCustomChildren ? 'auto' : DEFAULT_REFRESHER_HEIGHT,\n flexShrink: 0,\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n background,\n }}\n >\n {hasCustomChildren ? config.children : (\n defaultText ? <View style={textColor ? { color: textColor } : undefined}>{defaultText}</View> : null\n )}\n </View>\n )\n }, [config, pullDistance, isRefreshing])\n\n // 受控 refresherTriggered:设为 true 时立即展示顶部加载指示器(对齐小程序:无需下拉即显示、固定在顶部)\n React.useEffect(() => {\n if (!isControlled || !config || config.refresherTriggered !== true) return\n if (pullDistanceRef.current >= DEFAULT_REFRESHER_HEIGHT) return\n setPullDistanceRef.current(DEFAULT_REFRESHER_HEIGHT)\n pullDistanceRef.current = DEFAULT_REFRESHER_HEIGHT\n // 触发 Refreshing 状态变化\n emitStatusChangeRef.current(RefreshStatus.Refreshing, DEFAULT_REFRESHER_HEIGHT)\n }, [isControlled, config?.refresherTriggered])\n\n // 受控 refresherTriggered:父组件设为 false 时同步回弹并清零\n const prevTriggeredRef = useRef(config?.refresherTriggered)\n React.useEffect(() => {\n if (!isControlled || !config || config.refresherTriggered !== false) {\n prevTriggeredRef.current = config?.refresherTriggered\n return\n }\n const prev = prevTriggeredRef.current\n prevTriggeredRef.current = false\n if (prev === true && (pullDistanceRef.current > 0 || isRefreshingRef.current)) {\n if (rafRef.current != null) cancelAnimationFrame(rafRef.current)\n const from = pullDistanceRef.current > 0 ? pullDistanceRef.current : DEFAULT_REFRESHER_HEIGHT\n // 触发 Completed 状态变化\n emitStatusChangeRef.current(RefreshStatus.Completed, from)\n const startTime = performance.now()\n const animate = () => {\n const t = Math.min((performance.now() - startTime) / BOUNCE_MS, 1)\n const ease = 1 - Math.pow(1 - t, 3)\n const v = from * (1 - ease)\n setPullDistanceRef.current(v)\n pullDistanceRef.current = v\n if (t < 1) rafRef.current = requestAnimationFrame(animate)\n else {\n setPullDistanceRef.current(0)\n pullDistanceRef.current = 0\n // 修复闭包问题:使用 ref 获取最新值\n if (!isControlledRef.current) setInternalRefreshingRef.current(false)\n rafRef.current = null\n config.onRefresherRestore?.()\n // 触发 Idle 状态变化\n emitStatusChangeRef.current(RefreshStatus.Idle, 0)\n }\n }\n rafRef.current = requestAnimationFrame(animate)\n }\n }, [isControlled, config?.refresherTriggered])\n\n return {\n scrollViewRefresherProps,\n scrollViewRefresherHandlers,\n h5RefresherProps: {\n touchHandlers: {},\n pullDistance,\n isRefreshing,\n showRefresherLayer: !supportsNativeRefresher && !!config && h5RefresherEnabled,\n },\n addImperativeTouchListeners: !supportsNativeRefresher && config && h5RefresherEnabled ? addImperativeTouchListeners : undefined,\n renderRefresherContent,\n }\n}\n"],"names":["_jsx"],"mappings":"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"}
1
+ {"version":3,"file":"useRefresher.js","sources":["../../../../src/components/list/hooks/useRefresher.tsx"],"sourcesContent":["import { Slot, View } from '@tarojs/components'\nimport React, { useCallback, useRef, useState } from 'react'\n\nimport { supportsNativeRefresher } from '../utils'\n\n/**\n * List 组件内部的 refresher 配置类型(独立于 Refresher 组件)\n * 与 ScrollView refresher 相关属性语义对齐\n */\nexport interface ListRefresherConfig {\n refresherEnabled?: boolean\n refresherThreshold?: number\n refresherDefaultStyle?: 'black' | 'white' | 'none'\n refresherBackground?: string\n refresherTriggered?: boolean\n /** 自定义刷新内容(来自 Refresher 子组件的 children) */\n children?: React.ReactNode\n onRefresherPulling?: (e?: { detail?: { deltaY?: number } }) => void\n onRefresherRefresh?: () => void | Promise<void>\n onRefresherRestore?: () => void\n onRefresherAbort?: () => void\n onRefresherWillRefresh?: () => void\n onRefresherStatusChange?: (e?: { detail?: { status?: number, dy?: number } }) => void\n}\n\n/**\n * 下拉刷新(List 内部)\n *\n * - 小程序:ScrollView 原生 refresher-*;业务 Promise reject 时补发 Failed(4)(原生不派发)\n * - H5:触顶 + touch 拖拽;最大行程 / 阻尼停拉线为视口高的 0.9 / 0.8(innerHeight);收尾仅依赖 onRefresherRefresh 的 Promise\n * - 动画时间戳用 nowMs():小程序部分环境无 performance,避免抛错中断回弹\n * - rafRef 与受控 refresherTriggered→false 的 effect 共用:effect 内 cancel 可能打断 H5 成功回弹,须在 effect 动画结束处释放 refreshingLockRef\n * - H5 reject:onRefresherStatusChange 顺序 Failed(4) → Completed(3) → Idle(0)\n * - emitStatusChange:仅 status 变化时回调(同 status 不重复)\n */\n\nconst BOUNCE_MS = 300\nconst AT_TOP_THRESHOLD = 3\nconst H5_PULL_DISTANCE_MAX_VH = 0.9\nconst H5_DAMPING_LIMIT_VH = 0.8\nconst VIEWPORT_HEIGHT_FALLBACK = 800\nconst DEG_LIMIT = 40\nexport const DEFAULT_REFRESHER_HEIGHT = 50\n\nfunction nowMs (): number {\n if (typeof performance !== 'undefined' && typeof performance.now === 'function') {\n return performance.now()\n }\n return Date.now()\n}\n\n/** 下拉刷新状态枚举(对齐微信小程序 RefreshStatus) */\nexport const enum RefreshStatus {\n /** 空闲 */\n Idle = 0,\n /** 超过下拉刷新阈值 */\n CanRefresh = 1,\n /** 刷新中 */\n Refreshing = 2,\n /** 刷新完成 */\n Completed = 3,\n /** 刷新失败 */\n Failed = 4,\n}\n\nfunction getViewportHeightPx (): number {\n if (typeof window === 'undefined' || !Number.isFinite(window.innerHeight) || window.innerHeight <= 0) {\n return VIEWPORT_HEIGHT_FALLBACK\n }\n return window.innerHeight\n}\n\n/** 阻尼增量:ratio=总下拉位移/视口高;超过 dampingLimit 后不再累加 */\nfunction dampIncrement (\n diff: number,\n totalMove: number,\n currentPull: number,\n viewportHeight: number,\n dampingLimit: number\n): number {\n if (diff <= 0) return 0\n if (currentPull >= dampingLimit) return 0\n const ratio = Math.min(totalMove / viewportHeight, 1)\n return diff * (1 - ratio) * 0.6\n}\n\ninterface UseRefresherReturn {\n scrollViewRefresherProps: {\n refresherEnabled?: boolean\n refresherThreshold?: number\n refresherDefaultStyle?: string\n refresherBackground?: string\n refresherTriggered?: boolean\n }\n scrollViewRefresherHandlers: {\n onRefresherPulling?: (e: any) => void\n onRefresherRefresh?: (e: any) => void\n onRefresherRestore?: () => void\n onRefresherAbort?: () => void\n }\n h5RefresherProps: {\n touchHandlers: Record<string, unknown>\n pullDistance: number\n isRefreshing: boolean\n /** H5 单结构下恒为 true,仅兼容旧类型 */\n showRefresherLayer: boolean\n }\n addImperativeTouchListeners?: (el: HTMLElement) => () => void\n renderRefresherContent: () => React.ReactNode | null\n}\n\nexport function useRefresher(\n config: ListRefresherConfig | null,\n /** 列表逻辑顶部对应的 scrollTop,用于触顶判断;H5「顶栏悬浮+只滚列表」时传 0,imperative 内以 DOM scrollTop 为准 */\n scrollTopAtLogicalTop: number,\n /** scrollElement 模式下可选:下拉起始点须在 List 内才触发刷新;未传时默认 true(沿用原逻辑) */\n getIsTouchInListArea?: (ev: TouchEvent) => boolean\n): UseRefresherReturn {\n const [internalRefreshing, setInternalRefreshing] = useState(false)\n const [pullDistance, setPullDistance] = useState(0)\n const pullDistanceRef = useRef(0)\n const rafRef = useRef<number | null>(null)\n const setPullDistanceRef = useRef(setPullDistance)\n const setInternalRefreshingRef = useRef(setInternalRefreshing)\n setPullDistanceRef.current = setPullDistance\n setInternalRefreshingRef.current = setInternalRefreshing\n pullDistanceRef.current = pullDistance\n\n const isControlled = typeof config?.refresherTriggered === 'boolean'\n const isRefreshing = isControlled ? (config?.refresherTriggered ?? false) : internalRefreshing\n const isRefreshingRef = useRef(isRefreshing)\n isRefreshingRef.current = isRefreshing\n /** 刷新中锁:runRefresh 内同步置 true,避免 setState 未重渲染前再次触摸触发刷新 */\n const refreshingLockRef = useRef(false)\n /** H5 当前刷新状态,用于 onRefresherStatusChange 避免重复触发 */\n const refreshStatusRef = useRef<RefreshStatus>(RefreshStatus.Idle)\n /** H5 是否启用下拉刷新:refresherEnabled === false 时不挂 touch、不显示顶栏 */\n const h5RefresherEnabled = !!config && config.refresherEnabled !== false\n\n /** touch 只挂一次,回调里读 ref 才能拿到最新配置,避免改预设后仍用旧值 */\n const thresholdRef = useRef(config?.refresherThreshold ?? 45)\n thresholdRef.current = config?.refresherThreshold ?? 45\n const configRef = useRef(config)\n configRef.current = config\n\n const emitStatusChangeRef = useRef((status: RefreshStatus, dy: number) => {\n if (refreshStatusRef.current !== status) {\n refreshStatusRef.current = status\n configRef.current?.onRefresherStatusChange?.({ detail: { status, dy } })\n }\n })\n const isControlledRef = useRef(isControlled)\n isControlledRef.current = isControlled\n /** H5 顶栏悬浮时 List 传 0,触顶即 scrollTop<=0+阈值;否则由 List 传列表顶对应的 scrollTop */\n const scrollTopWhenAtTop = !supportsNativeRefresher && config ? scrollTopAtLogicalTop : 0\n const topThresholdPx = scrollTopWhenAtTop + AT_TOP_THRESHOLD\n const topThresholdPxRef = useRef(topThresholdPx)\n topThresholdPxRef.current = topThresholdPx\n\n const getIsTouchInListAreaRef = useRef(getIsTouchInListArea)\n getIsTouchInListAreaRef.current = getIsTouchInListArea\n\n const scrollViewRefresherProps = config && supportsNativeRefresher ? {\n refresherEnabled: config.refresherEnabled ?? true,\n refresherThreshold: config.refresherThreshold ?? 45,\n refresherDefaultStyle: config.refresherDefaultStyle ?? 'black',\n refresherBackground: config.refresherBackground ?? '#fff',\n refresherTriggered: isRefreshing,\n } : {}\n\n const scrollViewRefresherHandlers = config && supportsNativeRefresher ? {\n onRefresherPulling: (e: any) => {\n config.onRefresherPulling?.({ detail: { deltaY: e.detail?.deltaY ?? 0 } })\n },\n onRefresherRefresh: async () => {\n if (!isControlled) setInternalRefreshing(true)\n try {\n await config.onRefresherRefresh?.()\n } catch {\n // 原生不派发 Failed(4),补发便于与 H5 一致\n config.onRefresherStatusChange?.({ detail: { status: RefreshStatus.Failed, dy: 0 } })\n } finally {\n if (!isControlled) setInternalRefreshing(false)\n }\n },\n onRefresherRestore: () => config.onRefresherRestore?.(),\n onRefresherAbort: () => config.onRefresherAbort?.(),\n // 小程序特有事件:即将触发刷新(拖动超过 threshold 时)\n onRefresherWillRefresh: () => config.onRefresherWillRefresh?.(),\n // 小程序特有事件:下拉刷新状态变化\n onRefresherStatusChange: (e: any) => {\n config.onRefresherStatusChange?.({ detail: { status: e.detail?.status, dy: e.detail?.dy } })\n },\n } : {}\n\n const addImperativeTouchListeners = React.useCallback((el: HTMLElement) => {\n if (supportsNativeRefresher || !configRef.current || !h5RefresherEnabled) return () => {}\n const scrollEl = el as HTMLDivElement\n const startY = { current: 0 }\n const startX = { current: 0 }\n const lastY = { current: 0 }\n let touchStartedAtTop = false\n /** 下拉起始点是否在 List 内(scrollElement 模式);未传 getIsTouchInListArea 时恒为 true */\n let touchStartedInListArea = true\n let dragOnEdge = false\n let lastPull = 0\n /** 用于 onTouchEnd 判断是否触发刷新;刷新完成后必须置 0,否则下次点击(无 touchMove)会误用上次的 lastPull 再次触发 */\n const lastPullRef = { current: 0 }\n const pullAtReleaseRef = { current: 0 }\n\n const setPull = (v: number) => {\n lastPull = v\n lastPullRef.current = v\n setPullDistanceRef.current(v)\n }\n\n const runBounceBack = (fromValue: number, onComplete?: () => void) => {\n if (rafRef.current != null) cancelAnimationFrame(rafRef.current)\n const startTime = nowMs()\n const animate = () => {\n const t = Math.min((nowMs() - startTime) / BOUNCE_MS, 1)\n const ease = 1 - Math.pow(1 - t, 3)\n const v = fromValue * (1 - ease)\n setPullDistanceRef.current(v)\n lastPullRef.current = v\n lastPull = v\n if (t < 1) {\n rafRef.current = requestAnimationFrame(animate)\n } else {\n setPullDistanceRef.current(0)\n if (!isControlledRef.current) setInternalRefreshingRef.current(false)\n rafRef.current = null\n onComplete?.()\n }\n }\n rafRef.current = requestAnimationFrame(animate)\n }\n\n /** 未达阈值松手回弹结束:通知中止 */\n const runBounceBackAbort = (fromValue: number) => {\n if (rafRef.current != null) cancelAnimationFrame(rafRef.current)\n const startTime = nowMs()\n const animate = () => {\n const t = Math.min((nowMs() - startTime) / BOUNCE_MS, 1)\n const ease = 1 - Math.pow(1 - t, 3)\n const v = fromValue * (1 - ease)\n setPullDistanceRef.current(v)\n lastPullRef.current = v\n lastPull = v\n if (t < 1) rafRef.current = requestAnimationFrame(animate)\n else {\n setPullDistanceRef.current(0)\n rafRef.current = null\n lastPullRef.current = 0\n lastPull = 0\n configRef.current?.onRefresherAbort?.()\n emitStatusChangeRef.current(RefreshStatus.Idle, 0)\n }\n }\n rafRef.current = requestAnimationFrame(animate)\n }\n\n /** 收起到加载高度后再执行 onRefresherRefresh */\n const runBounceToLoading = (fromValue: number, toValue: number, onReach: () => void) => {\n if (rafRef.current != null) cancelAnimationFrame(rafRef.current)\n const startTime = nowMs()\n const animate = () => {\n const t = Math.min((nowMs() - startTime) / BOUNCE_MS, 1)\n const ease = 1 - Math.pow(1 - t, 3)\n setPullDistanceRef.current(fromValue + (toValue - fromValue) * ease)\n if (t < 1) {\n rafRef.current = requestAnimationFrame(animate)\n } else {\n setPullDistanceRef.current(toValue)\n rafRef.current = null\n onReach()\n }\n }\n rafRef.current = requestAnimationFrame(animate)\n }\n\n const isEdge = () => (scrollEl.scrollTop ?? 0) <= topThresholdPxRef.current\n\n const onTouchStart = (e: TouchEvent) => {\n if (refreshingLockRef.current || isRefreshingRef.current) return\n if (rafRef.current != null) {\n cancelAnimationFrame(rafRef.current)\n rafRef.current = null\n }\n lastPull = lastPullRef.current\n touchStartedAtTop = isEdge()\n touchStartedInListArea = getIsTouchInListAreaRef.current?.(e) ?? true\n const t0 = e.touches[0]\n if (t0) {\n startY.current = t0.clientY\n startX.current = t0.clientX\n lastY.current = t0.clientY\n }\n }\n\n const onTouchMove = (ev: TouchEvent) => {\n if (refreshingLockRef.current || isRefreshingRef.current) return\n if (!touchStartedInListArea) return\n const touch = ev.touches[0]\n if (!touch) return\n const currentY = touch.clientY\n const currentX = touch.clientX\n if (!isEdge()) {\n setPull(0)\n dragOnEdge = false\n return\n }\n // 到顶后:若 touch 开始时不在顶部,在首次下拉(dy>0)时「采纳」该手势,使同一手势内滚到顶后继续下拉可触发刷新\n if (!touchStartedAtTop && !dragOnEdge) {\n const dyCheck = currentY - lastY.current\n if (dyCheck <= 0) return\n touchStartedAtTop = true\n // 重置起点,避免采纳时 dy 过大导致刷新层瞬间拉满\n startY.current = currentY\n startX.current = currentX\n lastY.current = currentY\n }\n\n const dy = currentY - lastY.current\n // 还没进入下拉拖拽阶段(dragOnEdge=false)时,先看第一下是往上还是往下:\n // - 第一笔就是往上滑(dy<=0):视为正常滚动,直接交给原生 Scroll,不拦截、不启动下拉逻辑\n // - 第一笔是往下滑(dy>0):才认为是一次「下拉刷新」手势,进入拖拽模式\n if (!dragOnEdge) {\n if (dy <= 0) {\n lastY.current = currentY\n startY.current = currentY\n startX.current = currentX\n return\n }\n // 真正开始下拉刷新\n dragOnEdge = true\n startY.current = currentY\n startX.current = currentX\n }\n\n if (ev.cancelable) ev.preventDefault()\n const totalMove = currentY - startY.current\n const dx = currentX - startX.current\n if (dy <= 0) {\n lastY.current = currentY\n const next = Math.max(0, lastPull + dy)\n setPull(next)\n return\n }\n const deg = Math.atan(Math.abs(dx) / dy) * (180 / Math.PI)\n if (deg > DEG_LIMIT) {\n startY.current = currentY\n startX.current = currentX\n lastY.current = currentY\n return\n }\n lastY.current = currentY\n const vh = getViewportHeightPx()\n const maxPull = vh * H5_PULL_DISTANCE_MAX_VH\n const dampingLimit = vh * H5_DAMPING_LIMIT_VH\n const damped = dampIncrement(dy, totalMove, lastPull, vh, dampingLimit)\n const next = Math.min(lastPull + damped, maxPull)\n setPull(next)\n configRef.current?.onRefresherPulling?.({ detail: { deltaY: next } })\n if (next >= thresholdRef.current) {\n configRef.current?.onRefresherWillRefresh?.()\n emitStatusChangeRef.current(RefreshStatus.CanRefresh, next)\n } else {\n emitStatusChangeRef.current(RefreshStatus.Idle, next)\n }\n }\n\n const runRefresh = () => {\n const cfg = configRef.current\n if (!cfg || refreshingLockRef.current || isRefreshingRef.current) return\n refreshingLockRef.current = true\n const pullValue = lastPull\n const height = DEFAULT_REFRESHER_HEIGHT\n pullAtReleaseRef.current = pullValue\n if (!isControlledRef.current) setInternalRefreshingRef.current(true)\n emitStatusChangeRef.current(RefreshStatus.Refreshing, pullValue)\n runBounceToLoading(pullValue, height, () => {\n const safeReset = () => {\n setPullDistanceRef.current(0)\n if (!isControlledRef.current) setInternalRefreshingRef.current(false)\n refreshingLockRef.current = false\n lastPullRef.current = 0\n lastPull = 0\n pullAtReleaseRef.current = 0\n configRef.current?.onRefresherRestore?.()\n emitStatusChangeRef.current(RefreshStatus.Idle, 0)\n }\n Promise.resolve(configRef.current?.onRefresherRefresh?.())\n .then(\n () => {\n if (!refreshingLockRef.current) return\n emitStatusChangeRef.current(RefreshStatus.Completed, DEFAULT_REFRESHER_HEIGHT)\n requestAnimationFrame(() =>\n runBounceBack(DEFAULT_REFRESHER_HEIGHT, () => {\n refreshingLockRef.current = false\n lastPullRef.current = 0\n lastPull = 0\n pullAtReleaseRef.current = 0\n configRef.current?.onRefresherRestore?.()\n emitStatusChangeRef.current(RefreshStatus.Idle, 0)\n })\n )\n },\n () => {\n emitStatusChangeRef.current(RefreshStatus.Failed, pullValue)\n emitStatusChangeRef.current(RefreshStatus.Completed, DEFAULT_REFRESHER_HEIGHT)\n safeReset()\n }\n )\n })\n }\n\n const onTouchEnd = () => {\n if (refreshingLockRef.current) return\n if (!touchStartedInListArea) return\n dragOnEdge = false\n const current = lastPullRef.current\n if (current >= thresholdRef.current) {\n runRefresh()\n } else {\n if (current > 0) {\n runBounceBackAbort(current)\n }\n }\n }\n\n const optsMove = { passive: false, capture: true }\n const optsEnd = { passive: true, capture: true }\n el.addEventListener('touchstart', onTouchStart, { passive: true })\n el.addEventListener('touchmove', onTouchMove, optsMove)\n el.addEventListener('touchend', onTouchEnd, optsEnd)\n el.addEventListener('touchcancel', onTouchEnd, optsEnd)\n return () => {\n if (rafRef.current != null) cancelAnimationFrame(rafRef.current)\n el.removeEventListener('touchstart', onTouchStart)\n el.removeEventListener('touchmove', onTouchMove, optsMove)\n el.removeEventListener('touchend', onTouchEnd, optsEnd)\n el.removeEventListener('touchcancel', onTouchEnd, optsEnd)\n }\n }, [h5RefresherEnabled])\n\n const renderRefresherContent = useCallback(() => {\n if (!config) return null\n const threshold = config.refresherThreshold ?? 45\n const defaultStyle = config.refresherDefaultStyle ?? 'black'\n const background = config.refresherBackground ?? '#fff'\n const hasCustomChildren = config.children != null\n\n // 小程序:自定义内容时返回 Slot(name=refresher),避免 View 的 slot 属性在模板层被过滤\n // 样式对齐 H5:由内层 View 统一承载容器样式\n if (supportsNativeRefresher) {\n // 小程序需要名为 refresher 的插槽来指定自定义刷新内容\n return hasCustomChildren && defaultStyle === 'none'\n ? (\n <Slot\n name=\"refresher\"\n style={{\n position: 'absolute',\n left: 0,\n right: 0,\n zIndex: 0,\n }}\n >\n <View\n style={{\n width: '100%',\n flexShrink: 0,\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n background,\n }}\n >\n {config.children}\n </View>\n </Slot>\n )\n : null\n }\n\n // H5:refresherDefaultStyle 控制默认指示器样式(对齐小程序 black/white/none)\n // black=深色文案 white=浅色文案 none=仅展示 children,不展示默认「下拉/释放/加载中」\n const textColor = defaultStyle === 'white' ? '#fff' : defaultStyle === 'black' ? '#333' : undefined\n // 有自定义 children 且 style=none 时隐藏默认文字\n const showDefaultText = !(defaultStyle === 'none' && hasCustomChildren)\n const defaultText = showDefaultText\n ? (isRefreshing ? '加载中...' : pullDistance >= threshold ? '释放刷新' : '下拉刷新')\n : null\n\n return (\n <View\n style={{\n width: '100%',\n minHeight: hasCustomChildren ? undefined : DEFAULT_REFRESHER_HEIGHT,\n height: hasCustomChildren ? 'auto' : DEFAULT_REFRESHER_HEIGHT,\n flexShrink: 0,\n display: 'flex',\n justifyContent: 'center',\n alignItems: 'center',\n background,\n }}\n >\n {hasCustomChildren ? config.children : (\n defaultText ? <View style={textColor ? { color: textColor } : undefined}>{defaultText}</View> : null\n )}\n </View>\n )\n }, [config, pullDistance, isRefreshing])\n\n /** 受控 refresherTriggered=true:无下拉也显示加载条 */\n React.useEffect(() => {\n if (!isControlled || !config || config.refresherTriggered !== true) return\n if (pullDistanceRef.current >= DEFAULT_REFRESHER_HEIGHT) return\n setPullDistanceRef.current(DEFAULT_REFRESHER_HEIGHT)\n pullDistanceRef.current = DEFAULT_REFRESHER_HEIGHT\n emitStatusChangeRef.current(RefreshStatus.Refreshing, DEFAULT_REFRESHER_HEIGHT)\n }, [isControlled, config?.refresherTriggered])\n\n /** 受控 refresherTriggered=false:回弹清零;与 touch 共用 rafRef,cancel 时须在此释放 refreshingLockRef */\n const prevTriggeredRef = useRef(config?.refresherTriggered)\n React.useEffect(() => {\n if (!isControlled || !config || config.refresherTriggered !== false) {\n prevTriggeredRef.current = config?.refresherTriggered\n return\n }\n const prev = prevTriggeredRef.current\n prevTriggeredRef.current = false\n if (prev === true && (pullDistanceRef.current > 0 || isRefreshingRef.current)) {\n if (rafRef.current != null) cancelAnimationFrame(rafRef.current)\n const from = pullDistanceRef.current > 0 ? pullDistanceRef.current : DEFAULT_REFRESHER_HEIGHT\n emitStatusChangeRef.current(RefreshStatus.Completed, from)\n const startTime = nowMs()\n const animate = () => {\n const t = Math.min((nowMs() - startTime) / BOUNCE_MS, 1)\n const ease = 1 - Math.pow(1 - t, 3)\n const v = from * (1 - ease)\n setPullDistanceRef.current(v)\n pullDistanceRef.current = v\n if (t < 1) rafRef.current = requestAnimationFrame(animate)\n else {\n setPullDistanceRef.current(0)\n pullDistanceRef.current = 0\n if (!isControlledRef.current) setInternalRefreshingRef.current(false)\n rafRef.current = null\n refreshingLockRef.current = false\n config.onRefresherRestore?.()\n emitStatusChangeRef.current(RefreshStatus.Idle, 0)\n }\n }\n rafRef.current = requestAnimationFrame(animate)\n }\n }, [isControlled, config?.refresherTriggered])\n\n return {\n scrollViewRefresherProps,\n scrollViewRefresherHandlers,\n h5RefresherProps: {\n touchHandlers: {},\n pullDistance,\n isRefreshing,\n showRefresherLayer: !supportsNativeRefresher && !!config && h5RefresherEnabled,\n },\n addImperativeTouchListeners: !supportsNativeRefresher && config && h5RefresherEnabled ? addImperativeTouchListeners : undefined,\n renderRefresherContent,\n }\n}\n"],"names":["_jsx"],"mappings":"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"}
@@ -11,6 +11,7 @@ interface UseResizeObserverOptions {
11
11
  isHorizontal: boolean;
12
12
  /** List 容器 ID(小程序用于 SelectorQuery) */
13
13
  listId: string;
14
+ selectorQueryScope?: object;
14
15
  /** 尺寸变化回调 */
15
16
  onResize: (index: number, size: number) => void;
16
17
  }
@@ -1,9 +1,9 @@
1
1
  import Taro from '@tarojs/taro';
2
2
  import { useRef, useCallback, useEffect } from 'react';
3
- import { isH5, isMiniProgram } from '../utils.js';
3
+ import { getMiniProgramObserverScope, createSelectorQueryScoped, isH5, isMiniProgram } from '../utils.js';
4
4
 
5
5
  function useResizeObserver(options) {
6
- const { enabled, isHorizontal, listId, onResize } = options;
6
+ const { enabled, isHorizontal, listId, onResize, selectorQueryScope } = options;
7
7
  // H5: ResizeObserver 实例
8
8
  const observerRef = useRef(null);
9
9
  // 小程序: IntersectionObserver 实例 Map
@@ -55,8 +55,8 @@ function useResizeObserver(options) {
55
55
  : `#${listId}-list-header-inner-${-index - 1}`;
56
56
  const doObserve = () => {
57
57
  try {
58
- // 创建 IntersectionObserver
59
- const observer = Taro.createIntersectionObserver(Taro.getCurrentInstance().page, {
58
+ const observerScope = getMiniProgramObserverScope(selectorQueryScope);
59
+ const observer = Taro.createIntersectionObserver(observerScope, {
60
60
  observeAll: true
61
61
  });
62
62
  // 相对于 List 容器
@@ -64,7 +64,7 @@ function useResizeObserver(options) {
64
64
  // 观察元素进入可见区域(唯一 id 避免跨 List 误命中)
65
65
  observer.observe(selector, (res) => {
66
66
  if (res.intersectionRatio > 0) {
67
- Taro.createSelectorQuery()
67
+ createSelectorQueryScoped(selectorQueryScope)
68
68
  .select(selector)
69
69
  .boundingClientRect((rect) => {
70
70
  if (rect) {
@@ -82,7 +82,7 @@ function useResizeObserver(options) {
82
82
  }
83
83
  };
84
84
  Taro.nextTick(doObserve);
85
- }, [enabled, isHorizontal, listId, onResize]);
85
+ }, [enabled, isHorizontal, listId, onResize, selectorQueryScope]);
86
86
  /**
87
87
  * 观察元素(平台自动适配)
88
88
  */
@@ -1 +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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"}
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 { createSelectorQueryScoped, getMiniProgramObserverScope, 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 selectorQueryScope?: object\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, selectorQueryScope } = 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 const observerScope = getMiniProgramObserverScope(selectorQueryScope)\n const observer = Taro.createIntersectionObserver(observerScope, {\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 createSelectorQueryScoped(selectorQueryScope)\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, selectorQueryScope])\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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"}
@@ -27,8 +27,9 @@ function useScrollCorrection(options) {
27
27
  // 延迟执行修正(批量窗口 100ms)
28
28
  timerRef.current = setTimeout(() => {
29
29
  const now = Date.now();
30
+ const sinceLastScroll = now - lastUserScrollTimeRef.current;
30
31
  // 如果用户最近 300ms 内主动滚动,跳过修正
31
- if (now - lastUserScrollTimeRef.current < 300) {
32
+ if (sinceLastScroll < 300) {
32
33
  queueRef.current = [];
33
34
  return;
34
35
  }
@@ -1 +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;;;;"}
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 const sinceLastScroll = now - lastUserScrollTimeRef.current\n\n // 如果用户最近 300ms 内主动滚动,跳过修正\n if (sinceLastScroll < 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;AACtB,YAAA,MAAM,eAAe,GAAG,GAAG,GAAG,qBAAqB,CAAC,OAAO;;AAG3D,YAAA,IAAI,eAAe,GAAG,GAAG,EAAE;AACzB,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;;;;"}
@@ -71,12 +71,14 @@ export interface ListProps {
71
71
  dy?: number;
72
72
  };
73
73
  }) => void;
74
- /** 是否嵌套模式,与 plato 对齐;true=使用父级滚动,需配合 scrollElement 或 Context;不传或 false=default */
74
+ /** 嵌套滚动:父级滚动,需 scrollElement 或 Context */
75
75
  nestedScroll?: boolean;
76
- /** 自定义滚动容器 ref,nestedScroll 模式下从 props 或 Context 获取 */
76
+ /** 父级滚动容器 ref */
77
77
  scrollElement?: React.RefObject<HTMLElement | null>;
78
- /** 暴露滚动容器 ref,供内层 List/WaterFlow(nestedScroll)嵌套时传入 scrollElement */
78
+ /** 向外透出滚动容器,供子 List scrollElement */
79
79
  scrollRef?: React.MutableRefObject<HTMLElement | null>;
80
+ /** 仅小程序:SelectorQuery / IO 作用域(如自定义组件内传 `this`),未传则沿用 page */
81
+ selectorQueryScope?: object;
80
82
  }
81
83
  export interface ListHandle {
82
84
  scroll: (options?: {
@@ -15,7 +15,7 @@ import { ListItem } from './ListItem.js';
15
15
  import { NoMore } from './NoMore.js';
16
16
  import { StickyHeader } from './StickyHeader.js';
17
17
  import { StickySection } from './StickySection.js';
18
- import { isWeapp, isH5, supportsNativeRefresher } from './utils.js';
18
+ import { isWeapp, createSelectorQueryScoped, isH5, supportsNativeRefresher } from './utils.js';
19
19
  import { getScrollViewContextNode } from '../../utils/dom.js';
20
20
 
21
21
  function accumulate(arr) {
@@ -69,7 +69,7 @@ const InnerList = (props, ref) => {
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
- const { effectiveScrollElement, effectiveStartOffset, effectiveStartOffsetRef, useScrollElementMode, needAutoFind, autoFindStatus, contentWrapperRef, contentId, } = useListNestedScroll(listType, scrollElement, undefined, isHorizontal);
72
+ const { effectiveScrollElement, effectiveStartOffset, effectiveStartOffsetRef, useScrollElementMode, needAutoFind, autoFindStatus, contentWrapperRef, contentId, } = useListNestedScroll(listType, scrollElement, undefined, isHorizontal, props.selectorQueryScope);
73
73
  const DEFAULT_ITEM_WIDTH = 120;
74
74
  const DEFAULT_ITEM_HEIGHT = 40;
75
75
  const defaultItemSize = isHorizontal ? DEFAULT_ITEM_WIDTH : DEFAULT_ITEM_HEIGHT;
@@ -120,6 +120,22 @@ const InnerList = (props, ref) => {
120
120
  ro.observe(el);
121
121
  return () => ro.disconnect();
122
122
  }, [isHorizontal]);
123
+ // WeChat 小程序:没有原生 ResizeObserver,用 SelectorQuery 一次性测量容器高度
124
+ React.useEffect(() => {
125
+ if (!isWeapp)
126
+ return;
127
+ Taro.nextTick(() => {
128
+ createSelectorQueryScoped(props.selectorQueryScope)
129
+ .select(`#${listId}`)
130
+ .boundingClientRect((rect) => {
131
+ const measured = isHorizontal ? rect === null || rect === void 0 ? void 0 : rect.width : rect === null || rect === void 0 ? void 0 : rect.height;
132
+ if (typeof measured === 'number' && measured > 0) {
133
+ setContainerLength(measured);
134
+ }
135
+ })
136
+ .exec();
137
+ });
138
+ }, [isWeapp, isHorizontal, listId]);
123
139
  // 滚动追踪相关refs
124
140
  const isScrollingRef = React.useRef(false);
125
141
  const lastScrollTopRef = React.useRef(controlledScrollTop !== null && controlledScrollTop !== void 0 ? controlledScrollTop : 0);
@@ -131,6 +147,10 @@ const InnerList = (props, ref) => {
131
147
  const programmaticCooldownRef = React.useRef(false);
132
148
  const programmaticCooldownTimerRef = React.useRef(null);
133
149
  const scrollViewOffsetRef = React.useRef(0);
150
+ // 用户滚动期间挂起的 reflow 标记(用于滚动结束后补触发)
151
+ const pendingWeappReflowRef = React.useRef(false);
152
+ // ref 持有最新版 scheduleWeappDynamicReflow,供 updateRenderOffset 内的 setTimeout 闭包安全访问
153
+ const scheduleWeappDynamicReflowRef = React.useRef(null);
134
154
  // 处理渲染偏移量更新。
135
155
  // syncToScrollView=true:程序性滚动,立即同步 scrollViewOffset。
136
156
  // syncToScrollView=false:用户滑动,仅更新 renderOffset。weapp 采用 recycle-view 策略:不把用户滑动位置同步到 scrollViewOffset,避免「传滞后值拉回」和「从有到无归顶」。
@@ -151,7 +171,10 @@ const InnerList = (props, ref) => {
151
171
  if (needForce) {
152
172
  const intermediate = newOffset > 0 ? newOffset - 0.01 : 0.01;
153
173
  setScrollViewOffset(intermediate);
174
+ programmaticScrollRef.current = true;
154
175
  requestAnimationFrame(() => {
176
+ // 第二帧也需要标记为程序性滚动,否则 else 分支不会传 scrollTop
177
+ programmaticScrollRef.current = true;
155
178
  setScrollViewOffset(newOffset);
156
179
  });
157
180
  }
@@ -182,6 +205,10 @@ const InnerList = (props, ref) => {
182
205
  if (!isWeapp) {
183
206
  setScrollViewOffset(lastScrollTopRef.current);
184
207
  }
208
+ // 滚动结束后触发期间被延迟的 reflow(item 首次测量触发)
209
+ if (isWeapp && pendingWeappReflowRef.current) {
210
+ scheduleWeappDynamicReflowRef.current();
211
+ }
185
212
  }
186
213
  }, isWeapp ? 200 : 150);
187
214
  }, []);
@@ -358,8 +385,8 @@ const InnerList = (props, ref) => {
358
385
  // 动态尺寸缓存更新版本:setItemSize 后递增,用于驱动 sectionOffsets/totalLength 与 item 定位重算
359
386
  const [sizeCacheVersion, setSizeCacheVersion] = React.useState(0);
360
387
  const sizeCacheRafRef = React.useRef(null);
361
- // 小程序端:测量触发 re-render 时,reflow 帧传 eff 并同步 scrollViewOffset,避免下一帧传 0 导致跳变
362
- const measureScrollProtectRef = React.useRef(false);
388
+ // (measureScrollProtectRef 已移除:scrollTop + 内容变更同帧 setData 会与 scrollAnchoring
389
+ // 冲突导致归顶;改由 scrollAnchoring=true 独立处理内容重排,无需显式传 scrollTop 保护)
363
390
  // 动态尺寸缓存
364
391
  const sizeCache = useItemSizeCache({
365
392
  isHorizontal,
@@ -395,23 +422,33 @@ const InnerList = (props, ref) => {
395
422
  const listContentLengthRef = React.useRef(0);
396
423
  const inUpperZoneRef = React.useRef(true);
397
424
  const inLowerZoneRef = React.useRef(false);
398
- // 小程序 + 动高(virtual-list 风格):测量变化后同帧重排,不做程序性 scrollTop 回拉
425
+ // 小程序 + 动高(virtual-list 风格):测量变化后同帧重排,不做程序性 scrollTop 回拉。
426
+ // 若用户正在滚动(惯性未结束),推迟到滚动停止后再触发,防止内容重排 + setData 同帧
427
+ // 导致 WeChat scrollAnchoring 失效或传滞后位置造成归顶。
399
428
  const scheduleWeappDynamicReflow = React.useCallback(() => {
400
429
  if (!isWeapp || props.useResizeObserver !== true)
401
430
  return;
431
+ // 滚动中:仅标记为待处理,等 onScrollEnd / 200ms 超时触发
432
+ if (isUserScrollingRef.current) {
433
+ pendingWeappReflowRef.current = true;
434
+ return;
435
+ }
402
436
  if (sizeCacheRafRef.current != null)
403
437
  return;
404
438
  sizeCacheRafRef.current = requestAnimationFrame(() => {
405
439
  sizeCacheRafRef.current = null;
406
- measureScrollProtectRef.current = true;
440
+ pendingWeappReflowRef.current = false;
407
441
  setSizeCacheVersion((v) => v + 1);
408
442
  });
409
443
  }, [isWeapp, props.useResizeObserver]);
444
+ // 每次渲染时更新 ref,保证 setTimeout 闭包内拿到最新版本
445
+ scheduleWeappDynamicReflowRef.current = scheduleWeappDynamicReflow;
410
446
  // ResizeObserver(当启用动态测量时)
411
447
  const resizeObserver = useResizeObserver({
412
448
  enabled: props.useResizeObserver === true,
413
449
  isHorizontal,
414
450
  listId,
451
+ selectorQueryScope: props.selectorQueryScope,
415
452
  onResize: (index, size) => {
416
453
  var _a;
417
454
  const oldSize = sizeCache.getItemSize(index);
@@ -566,8 +603,12 @@ const InnerList = (props, ref) => {
566
603
  const effectiveOffset = newOffset;
567
604
  const currentThreshold = thresholdRef.current;
568
605
  const { upper, lower } = currentThreshold;
569
- const currentContainerLength = containerRef.current
606
+ // WeChat 小程序节点不具备 clientHeight/clientWidth,需显式回退到 containerLength state
607
+ const rawContainerSize = containerRef.current
570
608
  ? (isHorizontal ? containerRef.current.clientWidth : containerRef.current.clientHeight)
609
+ : null;
610
+ const currentContainerLength = (typeof rawContainerSize === 'number' && rawContainerSize > 0)
611
+ ? rawContainerSize
571
612
  : containerLength;
572
613
  const nowInUpper = effectiveOffset <= upper;
573
614
  const currentContentLength = listContentLengthRef.current;
@@ -576,8 +617,9 @@ const InnerList = (props, ref) => {
576
617
  scrollDiffListRef.current.shift();
577
618
  scrollDiffListRef.current.push(diff);
578
619
  const shaking = isScrollingRef.current && isShaking(scrollDiffListRef.current);
579
- if (shaking)
620
+ if (shaking) {
580
621
  return;
622
+ }
581
623
  if (programmaticCooldownRef.current) {
582
624
  lastScrollTopRef.current = effectiveOffset;
583
625
  setRenderOffset(effectiveOffset);
@@ -615,6 +657,10 @@ const InnerList = (props, ref) => {
615
657
  isScrollingRef.current = false;
616
658
  isUserScrollingRef.current = false;
617
659
  setIsUserScrolling(false);
660
+ // 滚动结束后触发期间被延迟的 reflow(item 首次测量触发)
661
+ if (pendingWeappReflowRef.current) {
662
+ scheduleWeappDynamicReflowRef.current();
663
+ }
618
664
  }
619
665
  }
620
666
  onScrollEnd === null || onScrollEnd === void 0 ? void 0 : onScrollEnd();
@@ -779,30 +825,23 @@ const InnerList = (props, ref) => {
779
825
  };
780
826
  }, [useScrollElementMode, effectiveScrollElement]);
781
827
  scrollViewOffsetRef.current = scrollViewOffset;
782
- // scrollTop:weapp scrollViewOffset(reflow 帧传 eff 防跳变);H5 仅非用户滑动时传
828
+ // scrollTop 传递策略(对齐 virtual-list enhanced=true 的做法):
829
+ // - 程序性滚动帧(programmaticScrollRef=true):传 scrollViewOffset(目标位置)
830
+ // - 其余所有帧(用户滚动 / 测量重排 / 空闲):完全不传,依赖微信原生 + scrollAnchoring
831
+ // scrollAnchoring=true 负责在内容重排时自动维持视口位置,避免与显式 scrollTop
832
+ // 同帧冲突(冲突会导致 scrollAnchoring 失去锚点后归顶)
783
833
  if (isWeapp) {
784
- if (measureScrollProtectRef.current) {
785
- measureScrollProtectRef.current = false;
786
- const eff = lastScrollTopRef.current;
787
- setScrollViewOffset(eff);
788
- if (isHorizontal) {
789
- scrollViewProps.scrollLeft = eff;
790
- }
791
- else {
792
- scrollViewProps.scrollTop = eff;
793
- }
794
- programmaticScrollRef.current = false;
795
- }
796
- else {
797
- const sv = scrollViewOffset;
834
+ if (programmaticScrollRef.current) {
835
+ // 程序性滚动(imperative / scrollCorrection / scrollIntoView 等):传目标位置
798
836
  if (isHorizontal) {
799
- scrollViewProps.scrollLeft = sv;
837
+ scrollViewProps.scrollLeft = scrollViewOffset;
800
838
  }
801
839
  else {
802
- scrollViewProps.scrollTop = sv;
840
+ scrollViewProps.scrollTop = scrollViewOffset;
803
841
  }
804
842
  programmaticScrollRef.current = false;
805
843
  }
844
+ // else:用户滚动 / 空闲帧不传 scrollTop,让微信原生 + scrollAnchoring 完全接管
806
845
  }
807
846
  else {
808
847
  // H5:非用户滑动时传
@@ -848,8 +887,7 @@ const InnerList = (props, ref) => {
848
887
  listContentLength: listContentLengthRef.current,
849
888
  };
850
889
  useListScrollElementAttach(useScrollElementMode && isH5, effectiveScrollElement, effectiveStartOffset, isHorizontal, setContainerLength, updateRenderOffset, scrollRefProp, scrollAttachRefsRef);
851
- useListScrollElementAttachWeapp(useScrollElementMode && isWeapp, effectiveScrollElement, effectiveStartOffsetRef, effectiveStartOffset, isHorizontal, setContainerLength, updateRenderOffset, scrollRefProp, scrollAttachRefsRef, initialContainerLength // 兜底:measure 未完成或失败时供 onScrollToUpper/Lower 及 containerLengthRef 使用
852
- );
890
+ useListScrollElementAttachWeapp(useScrollElementMode && isWeapp, effectiveScrollElement, effectiveStartOffsetRef, effectiveStartOffset, isHorizontal, setContainerLength, updateRenderOffset, scrollRefProp, scrollAttachRefsRef, initialContainerLength, props.selectorQueryScope);
853
891
  // 吸顶/吸左 header
854
892
  const stickyHeaderNode = React.useMemo(() => {
855
893
  if (!stickyHeader)
@@ -931,7 +969,7 @@ const InnerList = (props, ref) => {
931
969
  Taro.nextTick(() => {
932
970
  if (!headerRefsRef.current.has(sectionIndex))
933
971
  return;
934
- Taro.createSelectorQuery()
972
+ createSelectorQueryScoped(props.selectorQueryScope)
935
973
  .select(`#${listId}-list-header-inner-${sectionIndex}`)
936
974
  .boundingClientRect((rect) => {
937
975
  if (rect) {
@@ -1077,7 +1115,7 @@ const InnerList = (props, ref) => {
1077
1115
  Taro.nextTick(() => {
1078
1116
  if (!itemRefsRef.current.has(capturedIndex))
1079
1117
  return;
1080
- Taro.createSelectorQuery()
1118
+ createSelectorQueryScoped(props.selectorQueryScope)
1081
1119
  // 页面上可能同时存在多个 List,inner id 必须带 listId 前缀避免跨列表误命中
1082
1120
  .select(`#${listId}-list-item-inner-${capturedIndex}`)
1083
1121
  .boundingClientRect((rect) => {