@tarojs/components-advanced 4.1.12-beta.7 → 4.1.12-beta.9
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 -1
- package/dist/components/index.js.map +1 -1
- package/dist/components/list/hooks/useListNestedScroll.d.ts +13 -0
- package/dist/components/list/hooks/useListNestedScroll.js +46 -0
- package/dist/components/list/hooks/useListNestedScroll.js.map +1 -0
- package/dist/components/list/hooks/useListScrollElementAttach.d.ts +21 -0
- package/dist/components/list/hooks/useListScrollElementAttach.js +86 -0
- package/dist/components/list/hooks/useListScrollElementAttach.js.map +1 -0
- package/dist/components/list/hooks/useMeasureStartOffset.d.ts +4 -2
- package/dist/components/list/hooks/useMeasureStartOffset.js +56 -15
- package/dist/components/list/hooks/useMeasureStartOffset.js.map +1 -1
- package/dist/components/list/hooks/useScrollParentAutoFind.d.ts +17 -0
- package/dist/components/list/hooks/useScrollParentAutoFind.js +54 -0
- package/dist/components/list/hooks/useScrollParentAutoFind.js.map +1 -0
- package/dist/components/list/index.d.ts +7 -12
- package/dist/components/list/index.js +53 -119
- package/dist/components/list/index.js.map +1 -1
- package/dist/components/water-flow/interface.d.ts +3 -3
- package/dist/components/water-flow/root.d.ts +8 -0
- package/dist/components/water-flow/root.js +33 -17
- package/dist/components/water-flow/root.js.map +1 -1
- package/dist/components/water-flow/section.d.ts +1 -1
- package/dist/components/water-flow/section.js +2 -2
- package/dist/components/water-flow/section.js.map +1 -1
- package/dist/components/water-flow/water-flow.d.ts +1 -0
- package/dist/components/water-flow/water-flow.js +79 -43
- package/dist/components/water-flow/water-flow.js.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/scrollParent.d.ts +22 -0
- package/dist/utils/scrollParent.js +55 -0
- package/dist/utils/scrollParent.js.map +1 -0
- package/package.json +9 -9
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { View, ScrollView } from '@tarojs/components';
|
|
3
|
+
import { ScrollElementContext } from '@tarojs/components-react';
|
|
4
|
+
export { ScrollElementContext as ListScrollElementContext } from '@tarojs/components-react';
|
|
3
5
|
import Taro from '@tarojs/taro';
|
|
4
|
-
import React
|
|
6
|
+
import React from 'react';
|
|
5
7
|
import { useItemSizeCache } from './hooks/useItemSizeCache.js';
|
|
6
|
-
import {
|
|
8
|
+
import { useListNestedScroll } from './hooks/useListNestedScroll.js';
|
|
9
|
+
import { useListScrollElementAttach } from './hooks/useListScrollElementAttach.js';
|
|
7
10
|
import { useRefresher, DEFAULT_REFRESHER_HEIGHT } from './hooks/useRefresher.js';
|
|
8
11
|
import { useResizeObserver } from './hooks/useResizeObserver.js';
|
|
9
12
|
import { useScrollCorrection } from './hooks/useScrollCorrection.js';
|
|
@@ -11,7 +14,7 @@ import { ListItem } from './ListItem.js';
|
|
|
11
14
|
import { NoMore } from './NoMore.js';
|
|
12
15
|
import { StickyHeader } from './StickyHeader.js';
|
|
13
16
|
import { StickySection } from './StickySection.js';
|
|
14
|
-
import {
|
|
17
|
+
import { isWeapp, isH5, supportsNativeRefresher } from './utils.js';
|
|
15
18
|
|
|
16
19
|
// 工具:累加数组
|
|
17
20
|
function accumulate(arr) {
|
|
@@ -43,35 +46,33 @@ function shouldMeasureWeappItem(index, measuredSet) {
|
|
|
43
46
|
}
|
|
44
47
|
// 小程序端暂不外抛 onItemSizeChange,避免父层重渲染导致 List remount 引发回顶或空白
|
|
45
48
|
function weappDeferItemSizeChange(_index, _size, _onItemSizeChange) { }
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const useScrollElementMode = listType === 'nested' && !!(effectiveScrollElement && isH5);
|
|
58
|
-
if (listType === 'nested' && !effectiveScrollElement && isH5) {
|
|
59
|
-
// eslint-disable-next-line no-console
|
|
60
|
-
console.warn('[List] type=nested 但无 scrollElement(props 或 Context),回退为 default');
|
|
49
|
+
/** 从 scroll 选项解析目标偏移量 */
|
|
50
|
+
function resolveScrollTargetOffset(options, isHorizontal) {
|
|
51
|
+
const opts = options !== null && options !== void 0 ? options : {};
|
|
52
|
+
const top = typeof opts.top === 'number' ? opts.top : undefined;
|
|
53
|
+
const left = typeof opts.left === 'number' ? opts.left : undefined;
|
|
54
|
+
let result = 0;
|
|
55
|
+
if (isHorizontal) {
|
|
56
|
+
if (typeof left === 'number')
|
|
57
|
+
result = left;
|
|
58
|
+
else if (typeof top === 'number')
|
|
59
|
+
result = top;
|
|
61
60
|
}
|
|
62
|
-
|
|
61
|
+
else {
|
|
62
|
+
if (typeof top === 'number')
|
|
63
|
+
result = top;
|
|
64
|
+
else if (typeof left === 'number')
|
|
65
|
+
result = left;
|
|
66
|
+
}
|
|
67
|
+
return Number.isFinite(result) ? result : 0;
|
|
63
68
|
}
|
|
69
|
+
// eslint-disable-next-line complexity -- List 多端/多模式逻辑集中,已抽离 useListNestedScroll、useListScrollElementAttach、resolveScrollTargetOffset 等
|
|
64
70
|
const InnerList = (props, ref) => {
|
|
65
|
-
var _a, _b, _c
|
|
66
|
-
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,
|
|
71
|
+
var _a, _b, _c;
|
|
72
|
+
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;
|
|
67
73
|
const isHorizontal = scrollX === true;
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
const measuredStartOffset = useMeasureStartOffset((_a = result1.effectiveScrollElement) !== null && _a !== void 0 ? _a : EMPTY_SCROLL_REF, contentWrapperRef, {
|
|
71
|
-
enabled: result1.useScrollElementMode && !result1.hasListScrollCtx && !!result1.effectiveScrollElement && isH5,
|
|
72
|
-
isHorizontal,
|
|
73
|
-
});
|
|
74
|
-
const { effectiveScrollElement, effectiveStartOffset, useScrollElementMode } = useListScrollElement(listType, scrollElement, measuredStartOffset);
|
|
74
|
+
const listType = nestedScroll === true ? 'nested' : 'default';
|
|
75
|
+
const { effectiveScrollElement, effectiveStartOffset, useScrollElementMode, needAutoFind, autoFindStatus, contentWrapperRef, } = useListNestedScroll(listType, scrollElement, undefined, isHorizontal);
|
|
75
76
|
const DEFAULT_ITEM_WIDTH = 120;
|
|
76
77
|
const DEFAULT_ITEM_HEIGHT = 40;
|
|
77
78
|
// 滚动状态管理
|
|
@@ -172,31 +173,7 @@ const InnerList = (props, ref) => {
|
|
|
172
173
|
// 暴露给外部的实例方法:通过 ref.scroll({ top / left }) 进行程序性滚动
|
|
173
174
|
React.useImperativeHandle(ref, () => ({
|
|
174
175
|
scroll(options) {
|
|
175
|
-
const
|
|
176
|
-
const isHorizontal = scrollX === true;
|
|
177
|
-
const top = typeof opts.top === 'number' ? opts.top : undefined;
|
|
178
|
-
const left = typeof opts.left === 'number' ? opts.left : undefined;
|
|
179
|
-
let targetOffset = 0;
|
|
180
|
-
if (isHorizontal) {
|
|
181
|
-
if (typeof left === 'number') {
|
|
182
|
-
targetOffset = left;
|
|
183
|
-
}
|
|
184
|
-
else if (typeof top === 'number') {
|
|
185
|
-
targetOffset = top;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
else {
|
|
189
|
-
if (typeof top === 'number') {
|
|
190
|
-
targetOffset = top;
|
|
191
|
-
}
|
|
192
|
-
else if (typeof left === 'number') {
|
|
193
|
-
targetOffset = left;
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
if (!Number.isFinite(targetOffset)) {
|
|
197
|
-
targetOffset = 0;
|
|
198
|
-
}
|
|
199
|
-
// 任务 2.2:scrollElement 模式下直接操作外部容器(内嵌时需加上 startOffset)
|
|
176
|
+
const targetOffset = resolveScrollTargetOffset(options, isHorizontal);
|
|
200
177
|
const el = effectiveScrollElement === null || effectiveScrollElement === void 0 ? void 0 : effectiveScrollElement.current;
|
|
201
178
|
if (el && isH5) {
|
|
202
179
|
const scrollTarget = targetOffset + effectiveStartOffset;
|
|
@@ -338,7 +315,7 @@ const InnerList = (props, ref) => {
|
|
|
338
315
|
}, [children]);
|
|
339
316
|
// 动态尺寸管理
|
|
340
317
|
const defaultEstimatedSize = isHorizontal ? DEFAULT_ITEM_WIDTH : DEFAULT_ITEM_HEIGHT;
|
|
341
|
-
const estimatedSize = (
|
|
318
|
+
const estimatedSize = (_a = props.estimatedItemSize) !== null && _a !== void 0 ? _a : defaultEstimatedSize;
|
|
342
319
|
// 计算总 item 数量(跨所有 section)
|
|
343
320
|
const totalItemCount = React.useMemo(() => {
|
|
344
321
|
return sections.reduce((sum, section) => sum + section.items.length, 0);
|
|
@@ -616,73 +593,15 @@ const InnerList = (props, ref) => {
|
|
|
616
593
|
}
|
|
617
594
|
onScrollEnd === null || onScrollEnd === void 0 ? void 0 : onScrollEnd();
|
|
618
595
|
}, [isWeapp, onScrollEnd]);
|
|
619
|
-
// scrollElement 模式:containerLength 从 scrollElement 获取(任务 1.6)
|
|
620
|
-
React.useEffect(() => {
|
|
621
|
-
if (!effectiveScrollElement || !isH5)
|
|
622
|
-
return;
|
|
623
|
-
const el = effectiveScrollElement.current;
|
|
624
|
-
if (!el || typeof ResizeObserver === 'undefined')
|
|
625
|
-
return;
|
|
626
|
-
const update = () => {
|
|
627
|
-
const measured = isHorizontal ? el.clientWidth : el.clientHeight;
|
|
628
|
-
if (measured > 0) {
|
|
629
|
-
setContainerLength(measured);
|
|
630
|
-
}
|
|
631
|
-
// scrollElement 模式下 useLayoutEffect 可能早于 ref 挂载,ResizeObserver 作为兜底确保 scrollRef 正确
|
|
632
|
-
if (scrollRefProp)
|
|
633
|
-
scrollRefProp.current = el;
|
|
634
|
-
};
|
|
635
|
-
update();
|
|
636
|
-
const ro = new ResizeObserver(update);
|
|
637
|
-
ro.observe(el);
|
|
638
|
-
return () => ro.disconnect();
|
|
639
|
-
}, [effectiveScrollElement, isH5, isHorizontal]);
|
|
640
|
-
// scrollElement 模式:监听外部滚动,驱动 renderOffset
|
|
641
|
-
// 使用 ref 保存 scrollCorrection/onScroll,避免每次渲染 deps 变化导致 effect 反复执行形成循环
|
|
642
|
-
const effectiveStartOffsetRef = React.useRef(effectiveStartOffset);
|
|
643
|
-
effectiveStartOffsetRef.current = effectiveStartOffset;
|
|
644
|
-
React.useEffect(() => {
|
|
645
|
-
if (!effectiveScrollElement || !isH5)
|
|
646
|
-
return;
|
|
647
|
-
const el = effectiveScrollElement.current;
|
|
648
|
-
if (!el)
|
|
649
|
-
return;
|
|
650
|
-
const handler = () => {
|
|
651
|
-
var _a, _b, _c;
|
|
652
|
-
const scrollPos = isHorizontal ? el.scrollLeft : el.scrollTop;
|
|
653
|
-
const adjustedPos = scrollPos - effectiveStartOffsetRef.current;
|
|
654
|
-
const clientSize = isHorizontal ? el.clientWidth : el.clientHeight;
|
|
655
|
-
const scrollSize = isHorizontal ? el.scrollWidth : el.scrollHeight;
|
|
656
|
-
scrollCorrectionRef.current.markUserScrolling();
|
|
657
|
-
updateRenderOffset(adjustedPos, false, 'scrollElement');
|
|
658
|
-
(_a = onScrollRef.current) === null || _a === void 0 ? void 0 : _a.call(onScrollRef, {
|
|
659
|
-
scrollTop: isHorizontal ? 0 : scrollPos,
|
|
660
|
-
scrollLeft: isHorizontal ? scrollPos : 0
|
|
661
|
-
});
|
|
662
|
-
// 任务 2.1:onScrollToUpper / onScrollToLower(scrollElement 模式用 adjustedPos,使有上方混排时以 List 顶为基准)
|
|
663
|
-
const { upper, lower } = thresholdRef.current;
|
|
664
|
-
const effectiveAdjusted = Math.max(0, adjustedPos);
|
|
665
|
-
if (effectiveAdjusted <= upper) {
|
|
666
|
-
(_b = onScrollToUpperRef.current) === null || _b === void 0 ? void 0 : _b.call(onScrollToUpperRef);
|
|
667
|
-
}
|
|
668
|
-
if (scrollPos + clientSize >= scrollSize - lower) {
|
|
669
|
-
(_c = onScrollToLowerRef.current) === null || _c === void 0 ? void 0 : _c.call(onScrollToLowerRef);
|
|
670
|
-
}
|
|
671
|
-
};
|
|
672
|
-
// 同步初始 scroll 位置(内嵌时需减去 startOffset)
|
|
673
|
-
const initialScroll = isHorizontal ? el.scrollLeft : el.scrollTop;
|
|
674
|
-
updateRenderOffset(initialScroll - effectiveStartOffsetRef.current, false, 'scrollElement');
|
|
675
|
-
el.addEventListener('scroll', handler, { passive: true });
|
|
676
|
-
return () => el.removeEventListener('scroll', handler);
|
|
677
|
-
}, [effectiveScrollElement, isH5, isHorizontal, updateRenderOffset]);
|
|
678
596
|
// 任务 2.3:暴露 scrollRef 给父组件(供内层 List/WaterFlow 传入 scrollElement)
|
|
679
597
|
// 收敛到此处统一赋值,不再在 ResizeObserver 中重复
|
|
680
598
|
React.useLayoutEffect(() => {
|
|
681
599
|
if (!scrollRefProp)
|
|
682
600
|
return;
|
|
683
601
|
const el = useScrollElementMode ? effectiveScrollElement === null || effectiveScrollElement === void 0 ? void 0 : effectiveScrollElement.current : containerRef.current;
|
|
684
|
-
if (el)
|
|
602
|
+
if (el) {
|
|
685
603
|
scrollRefProp.current = el;
|
|
604
|
+
}
|
|
686
605
|
}, [scrollRefProp, useScrollElementMode, effectiveScrollElement]);
|
|
687
606
|
// controlledScrollTop 变化时同步到 ScrollView
|
|
688
607
|
React.useEffect(() => {
|
|
@@ -872,6 +791,19 @@ const InnerList = (props, ref) => {
|
|
|
872
791
|
const noMoreHeight = (noMoreConfig === null || noMoreConfig === void 0 ? void 0 : noMoreConfig.visible) ? (noMoreConfig.height || 60) : 0;
|
|
873
792
|
const listContentLength = sectionOffsets[sectionOffsets.length - 1] + noMoreHeight;
|
|
874
793
|
const totalLength = listContentLength;
|
|
794
|
+
// scrollElement 模式下 onScrollToLower 需用内层内容高度判断,供 scroll handler 读取
|
|
795
|
+
const listContentLengthRef = React.useRef(0);
|
|
796
|
+
listContentLengthRef.current = listContentLength;
|
|
797
|
+
const scrollAttachRefsRef = React.useRef(null);
|
|
798
|
+
scrollAttachRefsRef.current = {
|
|
799
|
+
scrollCorrection: scrollCorrectionRef.current,
|
|
800
|
+
onScroll: onScrollRef.current,
|
|
801
|
+
onScrollToUpper: onScrollToUpperRef.current,
|
|
802
|
+
onScrollToLower: onScrollToLowerRef.current,
|
|
803
|
+
threshold: thresholdRef.current,
|
|
804
|
+
listContentLength: listContentLengthRef.current,
|
|
805
|
+
};
|
|
806
|
+
useListScrollElementAttach(useScrollElementMode && isH5, effectiveScrollElement, effectiveStartOffset, isHorizontal, setContainerLength, updateRenderOffset, scrollRefProp, scrollAttachRefsRef);
|
|
875
807
|
// 吸顶/吸左 header
|
|
876
808
|
const stickyHeaderNode = React.useMemo(() => {
|
|
877
809
|
if (!stickyHeader)
|
|
@@ -1152,7 +1084,7 @@ const InnerList = (props, ref) => {
|
|
|
1152
1084
|
const itemNode = React.createElement(View, outerItemProps, React.createElement(View, innerProps, section.items[i]));
|
|
1153
1085
|
// 任务 4.1:当 List 暴露 scrollRef 时,为每个 item 提供 Context,供内层 WaterFlow 使用
|
|
1154
1086
|
const itemWithContext = scrollRefProp && !useScrollElementMode
|
|
1155
|
-
? React.createElement(
|
|
1087
|
+
? React.createElement(ScrollElementContext.Provider, {
|
|
1156
1088
|
key: outerItemProps.key,
|
|
1157
1089
|
value: {
|
|
1158
1090
|
scrollRef: scrollRefProp,
|
|
@@ -1189,7 +1121,7 @@ const InnerList = (props, ref) => {
|
|
|
1189
1121
|
else {
|
|
1190
1122
|
const itemNode = React.createElement(View, outerItemProps, section.items[i]);
|
|
1191
1123
|
const itemWithContext = scrollRefProp && !useScrollElementMode
|
|
1192
|
-
? React.createElement(
|
|
1124
|
+
? React.createElement(ScrollElementContext.Provider, {
|
|
1193
1125
|
key: outerItemProps.key,
|
|
1194
1126
|
value: {
|
|
1195
1127
|
scrollRef: scrollRefProp,
|
|
@@ -1269,7 +1201,9 @@ const InnerList = (props, ref) => {
|
|
|
1269
1201
|
transform: `translateY(${h5RefresherTranslateY}px)`,
|
|
1270
1202
|
}, children: renderRefresherContent() }), jsxs(View, { style: Object.assign(Object.assign(Object.assign({}, listWrapperStyle), pullTranslate), { zIndex: 1, background: (_b = (_a = style === null || style === void 0 ? void 0 : style.background) !== null && _a !== void 0 ? _a : style === null || style === void 0 ? void 0 : style.backgroundColor) !== null && _b !== void 0 ? _b : '#fff' }), children: [stickyHeaderNode, renderSections(), renderNoMoreContent()] })] })) : (jsxs(Fragment, { children: [!supportsNativeRefresher && renderRefresherContent(), stickyHeaderNode, renderSections(), renderNoMoreContent()] })) }));
|
|
1271
1203
|
};
|
|
1272
|
-
|
|
1204
|
+
// useScrollElementMode 或 needAutoFind&&pending:渲染 View 以便监听外部滚动或 probe 阶段查找滚动父节点
|
|
1205
|
+
const renderView = useScrollElementMode || (!!needAutoFind && autoFindStatus === 'pending');
|
|
1206
|
+
if (renderView) {
|
|
1273
1207
|
// 任务 2.4:恢复 refresher DOM 结构(refresher 层 + listWrapperStyle)
|
|
1274
1208
|
return (jsx(View, { ref: contentWrapperRef, style: contentWrapperStyle, children: refresherHeightForH5 > 0 ? (jsxs(Fragment, { children: [jsx(View, { style: {
|
|
1275
1209
|
position: 'absolute',
|
|
@@ -1279,11 +1213,11 @@ const InnerList = (props, ref) => {
|
|
|
1279
1213
|
height: refresherHeightForH5,
|
|
1280
1214
|
zIndex: 0,
|
|
1281
1215
|
transform: `translateY(${h5RefresherTranslateY}px)`,
|
|
1282
|
-
}, children: renderRefresherContent() }), jsxs(View, { style: Object.assign(Object.assign(Object.assign({}, listWrapperStyle), pullTranslate), { zIndex: 1, background: (
|
|
1216
|
+
}, children: renderRefresherContent() }), jsxs(View, { style: Object.assign(Object.assign(Object.assign({}, listWrapperStyle), pullTranslate), { zIndex: 1, background: (_c = (_b = style === null || style === void 0 ? void 0 : style.background) !== null && _b !== void 0 ? _b : style === null || style === void 0 ? void 0 : style.backgroundColor) !== null && _c !== void 0 ? _c : '#fff' }), children: [stickyHeaderNode, renderSections(), renderNoMoreContent()] })] })) : (jsxs(Fragment, { children: [stickyHeaderNode, renderSections(), renderNoMoreContent()] })) }));
|
|
1283
1217
|
}
|
|
1284
1218
|
return (jsxs(ScrollView, Object.assign({ ref: containerRef }, scrollViewProps, { id: listId, children: [supportsNativeRefresher && renderRefresherContent(), renderContentArea()] })));
|
|
1285
1219
|
};
|
|
1286
1220
|
const List = React.forwardRef(InnerList);
|
|
1287
1221
|
|
|
1288
|
-
export { List, ListItem,
|
|
1222
|
+
export { List, ListItem, NoMore, StickyHeader, StickySection, accumulate, List as default, isShaking };
|
|
1289
1223
|
//# sourceMappingURL=index.js.map
|