@tarojs/components-advanced 4.2.0 → 4.2.1-beta.1
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.
- package/dist/components/index.js +2 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/list/NoMore.d.ts +30 -0
- package/dist/components/list/NoMore.js +10 -0
- package/dist/components/list/NoMore.js.map +1 -0
- package/dist/components/list/hooks/useItemSizeCache.d.ts +13 -0
- package/dist/components/list/hooks/useItemSizeCache.js +40 -0
- package/dist/components/list/hooks/useItemSizeCache.js.map +1 -0
- package/dist/components/list/hooks/useListNestedScroll.d.ts +18 -0
- package/dist/components/list/hooks/useListNestedScroll.js +61 -0
- package/dist/components/list/hooks/useListNestedScroll.js.map +1 -0
- package/dist/components/list/hooks/useListScrollElementAttach.d.ts +25 -0
- package/dist/components/list/hooks/useListScrollElementAttach.js +88 -0
- package/dist/components/list/hooks/useListScrollElementAttach.js.map +1 -0
- package/dist/components/list/hooks/useListScrollElementAttachWeapp.d.ts +15 -0
- package/dist/components/list/hooks/useListScrollElementAttachWeapp.js +135 -0
- package/dist/components/list/hooks/useListScrollElementAttachWeapp.js.map +1 -0
- package/dist/components/list/hooks/useMeasureStartOffset.d.ts +12 -0
- package/dist/components/list/hooks/useMeasureStartOffset.js +84 -0
- package/dist/components/list/hooks/useMeasureStartOffset.js.map +1 -0
- package/dist/components/list/hooks/useMeasureStartOffsetWeapp.d.ts +14 -0
- package/dist/components/list/hooks/useMeasureStartOffsetWeapp.js +87 -0
- package/dist/components/list/hooks/useMeasureStartOffsetWeapp.js.map +1 -0
- package/dist/components/list/hooks/useRefresher.d.ts +80 -0
- package/dist/components/list/hooks/useRefresher.js +561 -0
- package/dist/components/list/hooks/useRefresher.js.map +1 -0
- package/dist/components/list/hooks/useResizeObserver.d.ts +29 -0
- package/dist/components/list/hooks/useResizeObserver.js +153 -0
- package/dist/components/list/hooks/useResizeObserver.js.map +1 -0
- package/dist/components/list/hooks/useScrollCorrection.d.ts +19 -0
- package/dist/components/list/hooks/useScrollCorrection.js +74 -0
- package/dist/components/list/hooks/useScrollCorrection.js.map +1 -0
- package/dist/components/list/hooks/useScrollParentAutoFind.d.ts +20 -0
- package/dist/components/list/hooks/useScrollParentAutoFind.js +81 -0
- package/dist/components/list/hooks/useScrollParentAutoFind.js.map +1 -0
- package/dist/components/list/index.d.ts +64 -7
- package/dist/components/list/index.js +1081 -162
- package/dist/components/list/index.js.map +1 -1
- package/dist/components/list/utils.d.ts +28 -0
- package/dist/components/list/utils.js +41 -0
- package/dist/components/list/utils.js.map +1 -0
- package/dist/components/virtual-list/vue/list.d.ts +12 -12
- package/dist/components/virtual-waterfall/vue/waterfall.d.ts +11 -11
- package/dist/components/water-flow/flow-item.js +18 -11
- package/dist/components/water-flow/flow-item.js.map +1 -1
- package/dist/components/water-flow/flow-section.js +1 -1
- package/dist/components/water-flow/flow-section.js.map +1 -1
- package/dist/components/water-flow/index.d.ts +1 -1
- package/dist/components/water-flow/interface.d.ts +32 -2
- package/dist/components/water-flow/node.d.ts +3 -0
- package/dist/components/water-flow/node.js +34 -1
- package/dist/components/water-flow/node.js.map +1 -1
- package/dist/components/water-flow/root.d.ts +39 -4
- package/dist/components/water-flow/root.js +144 -44
- package/dist/components/water-flow/root.js.map +1 -1
- package/dist/components/water-flow/section.d.ts +11 -1
- package/dist/components/water-flow/section.js +81 -19
- package/dist/components/water-flow/section.js.map +1 -1
- package/dist/components/water-flow/utils.d.ts +4 -0
- package/dist/components/water-flow/utils.js +5 -1
- package/dist/components/water-flow/utils.js.map +1 -1
- package/dist/components/water-flow/water-flow-node-cache.d.ts +24 -0
- package/dist/components/water-flow/water-flow-node-cache.js +161 -0
- package/dist/components/water-flow/water-flow-node-cache.js.map +1 -0
- package/dist/components/water-flow/water-flow.d.ts +2 -3
- package/dist/components/water-flow/water-flow.js +316 -36
- package/dist/components/water-flow/water-flow.js.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/dom.d.ts +2 -2
- package/dist/utils/dom.js +7 -6
- package/dist/utils/dom.js.map +1 -1
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/scrollElementContext.d.ts +15 -0
- package/dist/utils/scrollElementContext.js +14 -0
- package/dist/utils/scrollElementContext.js.map +1 -0
- package/dist/utils/scrollParent.d.ts +33 -0
- package/dist/utils/scrollParent.js +88 -0
- package/dist/utils/scrollParent.js.map +1 -0
- package/dist/utils/weapp-scope.d.ts +7 -0
- package/dist/utils/weapp-scope.js +20 -0
- package/dist/utils/weapp-scope.js.map +1 -0
- package/package.json +9 -8
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { useState, useRef, useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
const WARNED_NESTED = new WeakSet();
|
|
4
|
+
const MAX_RETRY = 20;
|
|
5
|
+
const RETRY_DELAY = 50;
|
|
6
|
+
/**
|
|
7
|
+
* 测量 scrollElement 内 content 节点之前所有兄弟的高度/宽度之和,作为 startOffset。
|
|
8
|
+
* 用于 scrollElement 模式下无 Context/props 时自动计算上方内容高度。
|
|
9
|
+
* - 直接子节点:累加前兄弟尺寸(更稳定)
|
|
10
|
+
* - 非直接子节点:getBoundingClientRect 回退,并 warning 建议传 startOffset
|
|
11
|
+
* - ref 未就绪时自动重试,确保绑定到最外层滚动容器后能正确测量
|
|
12
|
+
*/
|
|
13
|
+
function useMeasureStartOffset(scrollElRef, contentRef, options) {
|
|
14
|
+
const { enabled, isHorizontal = false } = options;
|
|
15
|
+
const [measuredStartOffset, setMeasuredStartOffset] = useState(0);
|
|
16
|
+
const [retryTrigger, setRetryTrigger] = useState(0);
|
|
17
|
+
const retryCountRef = useRef(0);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (!enabled) {
|
|
20
|
+
retryCountRef.current = 0;
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const scrollEl = scrollElRef.current;
|
|
24
|
+
const contentEl = contentRef.current;
|
|
25
|
+
// ref 未就绪时重试(如 ScrollView 与 WaterFlow 异步挂载)
|
|
26
|
+
if (!scrollEl || !contentEl) {
|
|
27
|
+
if (retryCountRef.current < MAX_RETRY) {
|
|
28
|
+
retryCountRef.current += 1;
|
|
29
|
+
const id = setTimeout(() => setRetryTrigger((t) => t + 1), RETRY_DELAY);
|
|
30
|
+
return () => clearTimeout(id);
|
|
31
|
+
}
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
retryCountRef.current = 0;
|
|
35
|
+
const measure = () => {
|
|
36
|
+
const el = contentRef.current;
|
|
37
|
+
const scroll = scrollElRef.current;
|
|
38
|
+
if (!el || !scroll)
|
|
39
|
+
return;
|
|
40
|
+
if (el.parentElement === scroll) {
|
|
41
|
+
// 直接子节点:累加前兄弟尺寸
|
|
42
|
+
let offset = 0;
|
|
43
|
+
let prev = el.previousElementSibling;
|
|
44
|
+
while (prev) {
|
|
45
|
+
offset += isHorizontal ? prev.offsetWidth : prev.offsetHeight;
|
|
46
|
+
prev = prev.previousElementSibling;
|
|
47
|
+
}
|
|
48
|
+
setMeasuredStartOffset((prevVal) => (Math.abs(prevVal - offset) < 1 ? prevVal : offset));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// 非直接子节点:getBoundingClientRect 回退
|
|
52
|
+
const scrollRect = scroll.getBoundingClientRect();
|
|
53
|
+
const contentRect = el.getBoundingClientRect();
|
|
54
|
+
const offset = isHorizontal
|
|
55
|
+
? contentRect.left - scrollRect.left + scroll.scrollLeft
|
|
56
|
+
: contentRect.top - scrollRect.top + scroll.scrollTop;
|
|
57
|
+
const value = Math.max(0, offset);
|
|
58
|
+
setMeasuredStartOffset((prevVal) => (Math.abs(prevVal - value) < 1 ? prevVal : value));
|
|
59
|
+
if (!WARNED_NESTED.has(el)) {
|
|
60
|
+
WARNED_NESTED.add(el);
|
|
61
|
+
// eslint-disable-next-line no-console
|
|
62
|
+
console.warn('[useMeasureStartOffset] content 不是 scrollElement 的直接子节点,使用 getBoundingClientRect 测量。' +
|
|
63
|
+
'建议通过 props 或 Context 传入 startOffset 以获得更稳定的布局。');
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
measure();
|
|
67
|
+
scrollEl.addEventListener('scroll', measure, { passive: true });
|
|
68
|
+
const ro = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(measure) : null;
|
|
69
|
+
if (ro) {
|
|
70
|
+
ro.observe(scrollEl);
|
|
71
|
+
Array.from(scrollEl.children).forEach((child) => ro.observe(child));
|
|
72
|
+
// 非直接子节点:content 自身或其祖先变化时也需重测
|
|
73
|
+
ro.observe(contentEl);
|
|
74
|
+
}
|
|
75
|
+
return () => {
|
|
76
|
+
scrollEl.removeEventListener('scroll', measure);
|
|
77
|
+
ro === null || ro === void 0 ? void 0 : ro.disconnect();
|
|
78
|
+
};
|
|
79
|
+
}, [enabled, scrollElRef, contentRef, isHorizontal, retryTrigger]);
|
|
80
|
+
return measuredStartOffset;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export { useMeasureStartOffset };
|
|
84
|
+
//# sourceMappingURL=useMeasureStartOffset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useMeasureStartOffset.js","sources":["../../../../src/components/list/hooks/useMeasureStartOffset.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\n\nimport type { RefObject } from 'react'\n\nconst WARNED_NESTED = new WeakSet<Element>()\nconst MAX_RETRY = 20\nconst RETRY_DELAY = 50\n\n/**\n * 测量 scrollElement 内 content 节点之前所有兄弟的高度/宽度之和,作为 startOffset。\n * 用于 scrollElement 模式下无 Context/props 时自动计算上方内容高度。\n * - 直接子节点:累加前兄弟尺寸(更稳定)\n * - 非直接子节点:getBoundingClientRect 回退,并 warning 建议传 startOffset\n * - ref 未就绪时自动重试,确保绑定到最外层滚动容器后能正确测量\n */\nexport function useMeasureStartOffset(\n scrollElRef: RefObject<HTMLElement | null>,\n contentRef: RefObject<HTMLElement | null>,\n options: { enabled: boolean, isHorizontal?: boolean }\n): number {\n const { enabled, isHorizontal = false } = options\n const [measuredStartOffset, setMeasuredStartOffset] = useState(0)\n const [retryTrigger, setRetryTrigger] = useState(0)\n const retryCountRef = useRef(0)\n\n useEffect(() => {\n if (!enabled) {\n retryCountRef.current = 0\n return\n }\n const scrollEl = scrollElRef.current\n const contentEl = contentRef.current\n\n // ref 未就绪时重试(如 ScrollView 与 WaterFlow 异步挂载)\n if (!scrollEl || !contentEl) {\n if (retryCountRef.current < MAX_RETRY) {\n retryCountRef.current += 1\n const id = setTimeout(() => setRetryTrigger((t) => t + 1), RETRY_DELAY)\n return () => clearTimeout(id)\n }\n return\n }\n retryCountRef.current = 0\n\n const measure = () => {\n const el = contentRef.current\n const scroll = scrollElRef.current\n if (!el || !scroll) return\n\n if (el.parentElement === scroll) {\n // 直接子节点:累加前兄弟尺寸\n let offset = 0\n let prev: Element | null = el.previousElementSibling\n while (prev) {\n offset += isHorizontal ? (prev as HTMLElement).offsetWidth : (prev as HTMLElement).offsetHeight\n prev = prev.previousElementSibling\n }\n setMeasuredStartOffset((prevVal) => (Math.abs(prevVal - offset) < 1 ? prevVal : offset))\n return\n }\n\n // 非直接子节点:getBoundingClientRect 回退\n const scrollRect = scroll.getBoundingClientRect()\n const contentRect = el.getBoundingClientRect()\n const offset = isHorizontal\n ? contentRect.left - scrollRect.left + scroll.scrollLeft\n : contentRect.top - scrollRect.top + scroll.scrollTop\n const value = Math.max(0, offset)\n setMeasuredStartOffset((prevVal) => (Math.abs(prevVal - value) < 1 ? prevVal : value))\n\n if (!WARNED_NESTED.has(el)) {\n WARNED_NESTED.add(el)\n // eslint-disable-next-line no-console\n console.warn(\n '[useMeasureStartOffset] content 不是 scrollElement 的直接子节点,使用 getBoundingClientRect 测量。' +\n '建议通过 props 或 Context 传入 startOffset 以获得更稳定的布局。'\n )\n }\n }\n\n measure()\n scrollEl.addEventListener('scroll', measure, { passive: true })\n const ro = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(measure) : null\n if (ro) {\n ro.observe(scrollEl)\n Array.from(scrollEl.children).forEach((child) => ro.observe(child))\n // 非直接子节点:content 自身或其祖先变化时也需重测\n ro.observe(contentEl)\n }\n return () => {\n scrollEl.removeEventListener('scroll', measure)\n ro?.disconnect()\n }\n }, [enabled, scrollElRef, contentRef, isHorizontal, retryTrigger])\n\n return measuredStartOffset\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { MutableRefObject, RefObject } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* 小程序版 startOffset:对外层 scroll-view 与带 `contentId` 的外包各执行一次 SelectorQuery(各自 `weappScope(ref)`),
|
|
4
|
+
* 再合并结果;避免二者不在同一自定义组件时,单次 `in` 链式 `select` 查不全。
|
|
5
|
+
*
|
|
6
|
+
* 公式:startOffset = contentRect.top - scrollRect.top + scrollTop
|
|
7
|
+
*/
|
|
8
|
+
export declare function useMeasureStartOffsetWeapp(scrollElRef: RefObject<HTMLElement | null>, contentId: string, options: {
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
isHorizontal?: boolean;
|
|
11
|
+
startOffsetRef?: MutableRefObject<number>;
|
|
12
|
+
/** 挂载 `id={contentId}` 的嵌套内容外包 View;第二次 query 用其 ref 取 content 侧 `_scope` */
|
|
13
|
+
contentWrapperRef: RefObject<HTMLElement | null>;
|
|
14
|
+
}): number;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { useState, useRef, useEffect } from 'react';
|
|
2
|
+
import { createSelectorQueryForRef } from '../utils.js';
|
|
3
|
+
|
|
4
|
+
const MAX_RETRY = 20;
|
|
5
|
+
const RETRY_DELAY = 50;
|
|
6
|
+
/** 与 useListScrollElementAttachWeapp 容器测量间隔一致(H5 无 interval,用 ResizeObserver+scroll 事件驱动) */
|
|
7
|
+
const MEASURE_INTERVAL = 150;
|
|
8
|
+
/**
|
|
9
|
+
* 小程序版 startOffset:对外层 scroll-view 与带 `contentId` 的外包各执行一次 SelectorQuery(各自 `weappScope(ref)`),
|
|
10
|
+
* 再合并结果;避免二者不在同一自定义组件时,单次 `in` 链式 `select` 查不全。
|
|
11
|
+
*
|
|
12
|
+
* 公式:startOffset = contentRect.top - scrollRect.top + scrollTop
|
|
13
|
+
*/
|
|
14
|
+
function useMeasureStartOffsetWeapp(scrollElRef, contentId, options) {
|
|
15
|
+
const { enabled, isHorizontal = false, startOffsetRef, contentWrapperRef } = options;
|
|
16
|
+
const [measuredStartOffset, setMeasuredStartOffset] = useState(0);
|
|
17
|
+
const [retryTrigger, setRetryTrigger] = useState(0);
|
|
18
|
+
const retryCountRef = useRef(0);
|
|
19
|
+
const autoIdRef = useRef(`_ls_so_${Math.random().toString(36).slice(2, 9)}`);
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (!enabled || !contentId) {
|
|
22
|
+
retryCountRef.current = 0;
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const applyRects = (scrollRect, scrollInfo, contentRect) => {
|
|
26
|
+
var _a, _b;
|
|
27
|
+
if (!scrollRect || !scrollInfo || !contentRect)
|
|
28
|
+
return;
|
|
29
|
+
const scrollTop = (_a = scrollInfo.scrollTop) !== null && _a !== void 0 ? _a : 0;
|
|
30
|
+
const scrollLeft = (_b = scrollInfo.scrollLeft) !== null && _b !== void 0 ? _b : 0;
|
|
31
|
+
const value = isHorizontal
|
|
32
|
+
? Math.max(0, contentRect.left - scrollRect.left + scrollLeft)
|
|
33
|
+
: Math.max(0, contentRect.top - scrollRect.top + scrollTop);
|
|
34
|
+
if (startOffsetRef)
|
|
35
|
+
startOffsetRef.current = value;
|
|
36
|
+
setMeasuredStartOffset((prevVal) => (Math.abs(prevVal - value) < 1 ? prevVal : value));
|
|
37
|
+
};
|
|
38
|
+
const measure = () => {
|
|
39
|
+
const scrollEl = scrollElRef.current;
|
|
40
|
+
if (!scrollEl)
|
|
41
|
+
return;
|
|
42
|
+
if (!scrollEl.id) {
|
|
43
|
+
scrollEl.id = autoIdRef.current;
|
|
44
|
+
}
|
|
45
|
+
const scrollViewId = scrollEl.id;
|
|
46
|
+
createSelectorQueryForRef(scrollElRef)
|
|
47
|
+
.select(`#${scrollViewId}`)
|
|
48
|
+
.boundingClientRect()
|
|
49
|
+
.select(`#${scrollViewId}`)
|
|
50
|
+
.scrollOffset()
|
|
51
|
+
.exec((scrollRes) => {
|
|
52
|
+
const scrollRect = scrollRes === null || scrollRes === void 0 ? void 0 : scrollRes[0];
|
|
53
|
+
const scrollInfo = scrollRes === null || scrollRes === void 0 ? void 0 : scrollRes[1];
|
|
54
|
+
if (!scrollRect || !scrollInfo)
|
|
55
|
+
return;
|
|
56
|
+
createSelectorQueryForRef(contentWrapperRef)
|
|
57
|
+
.select(`#${contentId}`)
|
|
58
|
+
.boundingClientRect()
|
|
59
|
+
.exec((contentRes) => {
|
|
60
|
+
const contentRect = contentRes === null || contentRes === void 0 ? void 0 : contentRes[0];
|
|
61
|
+
applyRects(scrollRect, scrollInfo, contentRect);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
const scrollEl = scrollElRef.current;
|
|
66
|
+
if (!scrollEl) {
|
|
67
|
+
if (retryCountRef.current < MAX_RETRY) {
|
|
68
|
+
retryCountRef.current += 1;
|
|
69
|
+
const id = setTimeout(() => setRetryTrigger((t) => t + 1), RETRY_DELAY);
|
|
70
|
+
return () => clearTimeout(id);
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
retryCountRef.current = 0;
|
|
75
|
+
measure();
|
|
76
|
+
scrollEl.addEventListener('scroll', measure);
|
|
77
|
+
const interval = setInterval(measure, MEASURE_INTERVAL);
|
|
78
|
+
return () => {
|
|
79
|
+
scrollEl.removeEventListener('scroll', measure);
|
|
80
|
+
clearInterval(interval);
|
|
81
|
+
};
|
|
82
|
+
}, [enabled, scrollElRef, contentId, contentWrapperRef, isHorizontal, retryTrigger]);
|
|
83
|
+
return measuredStartOffset;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export { useMeasureStartOffsetWeapp };
|
|
87
|
+
//# sourceMappingURL=useMeasureStartOffsetWeapp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useMeasureStartOffsetWeapp.js","sources":["../../../../src/components/list/hooks/useMeasureStartOffsetWeapp.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\n\nimport { createSelectorQueryForRef } from '../utils'\n\nimport type { MutableRefObject, RefObject } from 'react'\n\nconst MAX_RETRY = 20\nconst RETRY_DELAY = 50\n/** 与 useListScrollElementAttachWeapp 容器测量间隔一致(H5 无 interval,用 ResizeObserver+scroll 事件驱动) */\nconst MEASURE_INTERVAL = 150\n\n/**\n * 小程序版 startOffset:对外层 scroll-view 与带 `contentId` 的外包各执行一次 SelectorQuery(各自 `weappScope(ref)`),\n * 再合并结果;避免二者不在同一自定义组件时,单次 `in` 链式 `select` 查不全。\n *\n * 公式:startOffset = contentRect.top - scrollRect.top + scrollTop\n */\nexport function useMeasureStartOffsetWeapp(\n scrollElRef: RefObject<HTMLElement | null>,\n contentId: string,\n options: {\n enabled: boolean\n isHorizontal?: boolean\n startOffsetRef?: MutableRefObject<number>\n /** 挂载 `id={contentId}` 的嵌套内容外包 View;第二次 query 用其 ref 取 content 侧 `_scope` */\n contentWrapperRef: RefObject<HTMLElement | null>\n }\n): number {\n const { enabled, isHorizontal = false, startOffsetRef, contentWrapperRef } = options\n const [measuredStartOffset, setMeasuredStartOffset] = useState(0)\n const [retryTrigger, setRetryTrigger] = useState(0)\n const retryCountRef = useRef(0)\n const autoIdRef = useRef(`_ls_so_${Math.random().toString(36).slice(2, 9)}`)\n\n useEffect(() => {\n if (!enabled || !contentId) {\n retryCountRef.current = 0\n return\n }\n\n const applyRects = (scrollRect: any, scrollInfo: any, contentRect: any) => {\n if (!scrollRect || !scrollInfo || !contentRect) return\n const scrollTop = scrollInfo.scrollTop ?? 0\n const scrollLeft = scrollInfo.scrollLeft ?? 0\n const value = isHorizontal\n ? Math.max(0, contentRect.left - scrollRect.left + scrollLeft)\n : Math.max(0, contentRect.top - scrollRect.top + scrollTop)\n if (startOffsetRef) startOffsetRef.current = value\n setMeasuredStartOffset((prevVal) => (Math.abs(prevVal - value) < 1 ? prevVal : value))\n }\n\n const measure = () => {\n const scrollEl = scrollElRef.current as any\n if (!scrollEl) return\n\n if (!scrollEl.id) {\n scrollEl.id = autoIdRef.current\n }\n const scrollViewId = scrollEl.id\n\n createSelectorQueryForRef(scrollElRef)\n .select(`#${scrollViewId}`)\n .boundingClientRect()\n .select(`#${scrollViewId}`)\n .scrollOffset()\n .exec((scrollRes) => {\n const scrollRect = scrollRes?.[0]\n const scrollInfo = scrollRes?.[1]\n if (!scrollRect || !scrollInfo) return\n createSelectorQueryForRef(contentWrapperRef)\n .select(`#${contentId}`)\n .boundingClientRect()\n .exec((contentRes) => {\n const contentRect = contentRes?.[0]\n applyRects(scrollRect, scrollInfo, contentRect)\n })\n })\n }\n\n const scrollEl = scrollElRef.current\n if (!scrollEl) {\n if (retryCountRef.current < MAX_RETRY) {\n retryCountRef.current += 1\n const id = setTimeout(() => setRetryTrigger((t) => t + 1), RETRY_DELAY)\n return () => clearTimeout(id)\n }\n return\n }\n retryCountRef.current = 0\n measure()\n scrollEl.addEventListener('scroll', measure)\n const interval = setInterval(measure, MEASURE_INTERVAL)\n return () => {\n scrollEl.removeEventListener('scroll', measure)\n clearInterval(interval)\n }\n }, [enabled, scrollElRef, contentId, contentWrapperRef, isHorizontal, retryTrigger])\n\n return measuredStartOffset\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* List 组件内部的 refresher 配置类型(独立于 Refresher 组件)
|
|
4
|
+
* 与 ScrollView refresher 相关属性语义对齐
|
|
5
|
+
*/
|
|
6
|
+
export interface ListRefresherConfig {
|
|
7
|
+
refresherEnabled?: boolean;
|
|
8
|
+
refresherThreshold?: number;
|
|
9
|
+
refresherDefaultStyle?: 'black' | 'white' | 'none';
|
|
10
|
+
refresherBackground?: string;
|
|
11
|
+
refresherTriggered?: boolean;
|
|
12
|
+
/** 自定义刷新内容(来自 Refresher 子组件的 children) */
|
|
13
|
+
children?: React.ReactNode;
|
|
14
|
+
onRefresherPulling?: (e?: {
|
|
15
|
+
detail?: {
|
|
16
|
+
deltaY?: number;
|
|
17
|
+
};
|
|
18
|
+
}) => void;
|
|
19
|
+
onRefresherRefresh?: () => void | Promise<void>;
|
|
20
|
+
onRefresherRestore?: () => void;
|
|
21
|
+
onRefresherAbort?: () => void;
|
|
22
|
+
onRefresherWillRefresh?: () => void;
|
|
23
|
+
onRefresherStatusChange?: (e?: {
|
|
24
|
+
detail?: {
|
|
25
|
+
status?: number;
|
|
26
|
+
dy?: number;
|
|
27
|
+
};
|
|
28
|
+
}) => void;
|
|
29
|
+
}
|
|
30
|
+
export declare const DEFAULT_REFRESHER_HEIGHT = 50;
|
|
31
|
+
/** 下拉刷新状态枚举(对齐微信小程序 RefreshStatus) */
|
|
32
|
+
export declare const enum RefreshStatus {
|
|
33
|
+
/** 空闲 */
|
|
34
|
+
Idle = 0,
|
|
35
|
+
/** 超过下拉刷新阈值 */
|
|
36
|
+
CanRefresh = 1,
|
|
37
|
+
/** 刷新中 */
|
|
38
|
+
Refreshing = 2,
|
|
39
|
+
/** 刷新完成 */
|
|
40
|
+
Completed = 3,
|
|
41
|
+
/** 刷新失败 */
|
|
42
|
+
Failed = 4
|
|
43
|
+
}
|
|
44
|
+
interface UseRefresherReturn {
|
|
45
|
+
scrollViewRefresherProps: {
|
|
46
|
+
refresherEnabled?: boolean;
|
|
47
|
+
refresherThreshold?: number;
|
|
48
|
+
refresherDefaultStyle?: string;
|
|
49
|
+
refresherBackground?: string;
|
|
50
|
+
refresherTriggered?: boolean;
|
|
51
|
+
};
|
|
52
|
+
scrollViewRefresherHandlers: {
|
|
53
|
+
onRefresherPulling?: (e: any) => void;
|
|
54
|
+
onRefresherRefresh?: (e: any) => void;
|
|
55
|
+
onRefresherRestore?: () => void;
|
|
56
|
+
onRefresherAbort?: () => void;
|
|
57
|
+
};
|
|
58
|
+
h5RefresherProps: {
|
|
59
|
+
touchHandlers: Record<string, unknown>;
|
|
60
|
+
pullDistance: number;
|
|
61
|
+
isRefreshing: boolean;
|
|
62
|
+
/** H5 单结构下恒为 true,仅兼容旧类型 */
|
|
63
|
+
showRefresherLayer: boolean;
|
|
64
|
+
};
|
|
65
|
+
addImperativeTouchListeners?: (el: HTMLElement) => () => void;
|
|
66
|
+
renderRefresherContent: () => React.ReactNode | null;
|
|
67
|
+
/**
|
|
68
|
+
* 刷新区几何高度:H5 等非小程序原生路径下与 List 绝对层 height / translateY 及本 hook 内下拉收尾动画一致。
|
|
69
|
+
* 小程序原生 refresher 由 ScrollView 负责展示与布局,List 侧槽位样式不依赖此字段。
|
|
70
|
+
*/
|
|
71
|
+
slotHeight: number;
|
|
72
|
+
}
|
|
73
|
+
export declare function useRefresher(config: ListRefresherConfig | null,
|
|
74
|
+
/** 列表逻辑顶部对应的 scrollTop,用于触顶判断;H5「顶栏悬浮+只滚列表」时传 0,imperative 内以 DOM scrollTop 为准 */
|
|
75
|
+
scrollTopAtLogicalTop: number,
|
|
76
|
+
/** scrollElement 模式下可选:下拉起始点须在 List 内才触发刷新;未传时默认 true(沿用原逻辑) */
|
|
77
|
+
getIsTouchInListArea?: (ev: TouchEvent) => boolean,
|
|
78
|
+
/** H5 等:开启刷新区时是否测量自定义内容高度(与 List 侧 isH5 && refresher 一致) */
|
|
79
|
+
enableH5SlotMeasure?: boolean): UseRefresherReturn;
|
|
80
|
+
export {};
|