@tarojs/components-advanced 4.1.12-beta.6 → 4.1.12-beta.7
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 +1 -1
- package/dist/components/list/hooks/useMeasureStartOffset.d.ts +10 -0
- package/dist/components/list/hooks/useMeasureStartOffset.js +43 -0
- package/dist/components/list/hooks/useMeasureStartOffset.js.map +1 -0
- package/dist/components/list/hooks/useRefresher.d.ts +3 -1
- package/dist/components/list/hooks/useRefresher.js +26 -3
- package/dist/components/list/hooks/useRefresher.js.map +1 -1
- package/dist/components/list/index.d.ts +14 -0
- package/dist/components/list/index.js +232 -19
- package/dist/components/list/index.js.map +1 -1
- package/dist/components/water-flow/interface.d.ts +14 -2
- package/dist/components/water-flow/root.d.ts +3 -1
- package/dist/components/water-flow/root.js +10 -9
- package/dist/components/water-flow/root.js.map +1 -1
- package/dist/components/water-flow/utils.d.ts +2 -0
- package/dist/components/water-flow/utils.js +3 -1
- package/dist/components/water-flow/utils.js.map +1 -1
- package/dist/components/water-flow/water-flow.d.ts +1 -1
- package/dist/components/water-flow/water-flow.js +151 -24
- package/dist/components/water-flow/water-flow.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +9 -9
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { View, ScrollView } from '@tarojs/components';
|
|
3
3
|
import Taro from '@tarojs/taro';
|
|
4
|
-
import React from 'react';
|
|
4
|
+
import React, { useContext } from 'react';
|
|
5
5
|
import { useItemSizeCache } from './hooks/useItemSizeCache.js';
|
|
6
|
+
import { useMeasureStartOffset } from './hooks/useMeasureStartOffset.js';
|
|
6
7
|
import { useRefresher, DEFAULT_REFRESHER_HEIGHT } from './hooks/useRefresher.js';
|
|
7
8
|
import { useResizeObserver } from './hooks/useResizeObserver.js';
|
|
8
9
|
import { useScrollCorrection } from './hooks/useScrollCorrection.js';
|
|
@@ -10,7 +11,7 @@ import { ListItem } from './ListItem.js';
|
|
|
10
11
|
import { NoMore } from './NoMore.js';
|
|
11
12
|
import { StickyHeader } from './StickyHeader.js';
|
|
12
13
|
import { StickySection } from './StickySection.js';
|
|
13
|
-
import {
|
|
14
|
+
import { isH5, isWeapp, supportsNativeRefresher } from './utils.js';
|
|
14
15
|
|
|
15
16
|
// 工具:累加数组
|
|
16
17
|
function accumulate(arr) {
|
|
@@ -42,10 +43,35 @@ function shouldMeasureWeappItem(index, measuredSet) {
|
|
|
42
43
|
}
|
|
43
44
|
// 小程序端暂不外抛 onItemSizeChange,避免父层重渲染导致 List remount 引发回顶或空白
|
|
44
45
|
function weappDeferItemSizeChange(_index, _size, _onItemSizeChange) { }
|
|
46
|
+
const EMPTY_SCROLL_REF = { current: null };
|
|
47
|
+
/** 任务 4.1/4.2:List 内嵌 WaterFlow/List 时,向子组件提供 scrollRef、containerHeight、startOffset、reportNestedHeightChange */
|
|
48
|
+
const ListScrollElementContext = React.createContext(null);
|
|
49
|
+
/** 抽离 scrollElement 模式逻辑,降低 InnerList 圈复杂度 */
|
|
50
|
+
function useListScrollElement(listType, scrollElement,
|
|
51
|
+
/** 无 Context 时自动测量的 startOffset(上方内容高度),与下方 DOM stacking 对称 */
|
|
52
|
+
measuredStartOffset) {
|
|
53
|
+
var _a, _b;
|
|
54
|
+
const listScrollCtx = useContext(ListScrollElementContext);
|
|
55
|
+
const effectiveScrollElement = scrollElement !== null && scrollElement !== void 0 ? scrollElement : listScrollCtx === null || listScrollCtx === void 0 ? void 0 : listScrollCtx.scrollRef;
|
|
56
|
+
const effectiveStartOffset = (_b = (_a = listScrollCtx === null || listScrollCtx === void 0 ? void 0 : listScrollCtx.startOffset) !== null && _a !== void 0 ? _a : measuredStartOffset) !== null && _b !== void 0 ? _b : 0;
|
|
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');
|
|
61
|
+
}
|
|
62
|
+
return { effectiveScrollElement, effectiveStartOffset, useScrollElementMode, hasListScrollCtx: !!listScrollCtx };
|
|
63
|
+
}
|
|
45
64
|
const InnerList = (props, ref) => {
|
|
46
|
-
var _a;
|
|
47
|
-
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, } = props;
|
|
65
|
+
var _a, _b, _c, _d;
|
|
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, type: listType = 'default', scrollElement, scrollRef: scrollRefProp, } = props;
|
|
48
67
|
const isHorizontal = scrollX === true;
|
|
68
|
+
const contentWrapperRef = React.useRef(null);
|
|
69
|
+
const result1 = useListScrollElement(listType, scrollElement, 0);
|
|
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);
|
|
49
75
|
const DEFAULT_ITEM_WIDTH = 120;
|
|
50
76
|
const DEFAULT_ITEM_HEIGHT = 40;
|
|
51
77
|
// 滚动状态管理
|
|
@@ -170,9 +196,23 @@ const InnerList = (props, ref) => {
|
|
|
170
196
|
if (!Number.isFinite(targetOffset)) {
|
|
171
197
|
targetOffset = 0;
|
|
172
198
|
}
|
|
173
|
-
|
|
199
|
+
// 任务 2.2:scrollElement 模式下直接操作外部容器(内嵌时需加上 startOffset)
|
|
200
|
+
const el = effectiveScrollElement === null || effectiveScrollElement === void 0 ? void 0 : effectiveScrollElement.current;
|
|
201
|
+
if (el && isH5) {
|
|
202
|
+
const scrollTarget = targetOffset + effectiveStartOffset;
|
|
203
|
+
if (isHorizontal) {
|
|
204
|
+
el.scrollTo({ left: scrollTarget });
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
el.scrollTo({ top: scrollTarget });
|
|
208
|
+
}
|
|
209
|
+
updateRenderOffset(targetOffset, false, 'scrollElement');
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
updateRenderOffset(targetOffset, true, 'imperative');
|
|
213
|
+
}
|
|
174
214
|
},
|
|
175
|
-
}), [scrollX, updateRenderOffset]);
|
|
215
|
+
}), [scrollX, effectiveScrollElement, effectiveStartOffset, isH5, isHorizontal, updateRenderOffset]);
|
|
176
216
|
// 提取 Refresher 配置(List 属性为 base,Refresher 子组件覆盖)
|
|
177
217
|
const refresherConfig = React.useMemo(() => {
|
|
178
218
|
const listRefresherEnabled = props.refresherEnabled !== false && (props.refresherEnabled === true || props.onRefresherRefresh != null);
|
|
@@ -254,7 +294,9 @@ const InnerList = (props, ref) => {
|
|
|
254
294
|
return config;
|
|
255
295
|
}, [children, props.showNoMore, props.noMoreText, props.noMoreStyle, props.renderNoMore]);
|
|
256
296
|
// Refresher 平台适配:H5 用 addImperativeTouchListeners
|
|
257
|
-
const { scrollViewRefresherProps, scrollViewRefresherHandlers, h5RefresherProps, addImperativeTouchListeners, renderRefresherContent, } = useRefresher(refresherConfig, isH5 && refresherConfig && !supportsNativeRefresher ? 0 : renderOffset
|
|
297
|
+
const { scrollViewRefresherProps, scrollViewRefresherHandlers, h5RefresherProps, addImperativeTouchListeners, renderRefresherContent, } = useRefresher(refresherConfig, isH5 && refresherConfig && !supportsNativeRefresher ? 0 : renderOffset, useScrollElementMode
|
|
298
|
+
? (ev) => { var _a, _b; return (_b = (ev.target != null && ((_a = contentWrapperRef.current) === null || _a === void 0 ? void 0 : _a.contains(ev.target)))) !== null && _b !== void 0 ? _b : false; }
|
|
299
|
+
: undefined);
|
|
258
300
|
const refresherTeardownRef = React.useRef(null);
|
|
259
301
|
const addImperativeTouchListenersRef = React.useRef(addImperativeTouchListeners);
|
|
260
302
|
addImperativeTouchListenersRef.current = addImperativeTouchListeners;
|
|
@@ -296,7 +338,7 @@ const InnerList = (props, ref) => {
|
|
|
296
338
|
}, [children]);
|
|
297
339
|
// 动态尺寸管理
|
|
298
340
|
const defaultEstimatedSize = isHorizontal ? DEFAULT_ITEM_WIDTH : DEFAULT_ITEM_HEIGHT;
|
|
299
|
-
const estimatedSize = (
|
|
341
|
+
const estimatedSize = (_b = props.estimatedItemSize) !== null && _b !== void 0 ? _b : defaultEstimatedSize;
|
|
300
342
|
// 计算总 item 数量(跨所有 section)
|
|
301
343
|
const totalItemCount = React.useMemo(() => {
|
|
302
344
|
return sections.reduce((sum, section) => sum + section.items.length, 0);
|
|
@@ -334,6 +376,16 @@ const InnerList = (props, ref) => {
|
|
|
334
376
|
updateRenderOffset(newOffset, true, 'scrollCorrection'); // 程序性修正需同步到 ScrollView
|
|
335
377
|
}
|
|
336
378
|
});
|
|
379
|
+
const scrollCorrectionRef = React.useRef(scrollCorrection);
|
|
380
|
+
scrollCorrectionRef.current = scrollCorrection;
|
|
381
|
+
const onScrollRef = React.useRef(onScroll);
|
|
382
|
+
onScrollRef.current = onScroll;
|
|
383
|
+
const onScrollToUpperRef = React.useRef(onScrollToUpper);
|
|
384
|
+
onScrollToUpperRef.current = onScrollToUpper;
|
|
385
|
+
const onScrollToLowerRef = React.useRef(onScrollToLower);
|
|
386
|
+
onScrollToLowerRef.current = onScrollToLower;
|
|
387
|
+
const thresholdRef = React.useRef({ upper: upperThreshold, lower: lowerThreshold });
|
|
388
|
+
thresholdRef.current = { upper: upperThreshold, lower: lowerThreshold };
|
|
337
389
|
// 小程序 + 动高(virtual-list 风格):测量变化后同帧重排,不做程序性 scrollTop 回拉
|
|
338
390
|
const scheduleWeappDynamicReflow = React.useCallback(() => {
|
|
339
391
|
if (!isWeapp || props.useResizeObserver !== true)
|
|
@@ -564,6 +616,74 @@ const InnerList = (props, ref) => {
|
|
|
564
616
|
}
|
|
565
617
|
onScrollEnd === null || onScrollEnd === void 0 ? void 0 : onScrollEnd();
|
|
566
618
|
}, [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
|
+
// 任务 2.3:暴露 scrollRef 给父组件(供内层 List/WaterFlow 传入 scrollElement)
|
|
679
|
+
// 收敛到此处统一赋值,不再在 ResizeObserver 中重复
|
|
680
|
+
React.useLayoutEffect(() => {
|
|
681
|
+
if (!scrollRefProp)
|
|
682
|
+
return;
|
|
683
|
+
const el = useScrollElementMode ? effectiveScrollElement === null || effectiveScrollElement === void 0 ? void 0 : effectiveScrollElement.current : containerRef.current;
|
|
684
|
+
if (el)
|
|
685
|
+
scrollRefProp.current = el;
|
|
686
|
+
}, [scrollRefProp, useScrollElementMode, effectiveScrollElement]);
|
|
567
687
|
// controlledScrollTop 变化时同步到 ScrollView
|
|
568
688
|
React.useEffect(() => {
|
|
569
689
|
if (typeof controlledScrollTop === 'number') {
|
|
@@ -641,19 +761,30 @@ const InnerList = (props, ref) => {
|
|
|
641
761
|
}
|
|
642
762
|
}
|
|
643
763
|
updateRenderOffset(targetOffset, true, 'scrollIntoView');
|
|
764
|
+
// scrollElement 模式下需显式滚动外部容器,否则仅 updateRenderOffset 不会滚动 div
|
|
765
|
+
if (useScrollElementMode && (effectiveScrollElement === null || effectiveScrollElement === void 0 ? void 0 : effectiveScrollElement.current) && isH5) {
|
|
766
|
+
const el = effectiveScrollElement.current;
|
|
767
|
+
const scrollTarget = targetOffset + effectiveStartOffset;
|
|
768
|
+
if (isHorizontal) {
|
|
769
|
+
el.scrollTo({ left: scrollTarget });
|
|
770
|
+
}
|
|
771
|
+
else {
|
|
772
|
+
el.scrollTo({ top: scrollTarget });
|
|
773
|
+
}
|
|
774
|
+
}
|
|
644
775
|
}
|
|
645
|
-
}, [props.scrollIntoView, totalItemCount, sections, getHeaderSize, getItemSize, space, updateRenderOffset]);
|
|
776
|
+
}, [props.scrollIntoView, totalItemCount, sections, getHeaderSize, getItemSize, space, updateRenderOffset, useScrollElementMode, effectiveScrollElement, effectiveStartOffset, isH5, isHorizontal]);
|
|
646
777
|
// 容器样式;H5 刷新中禁止滚动
|
|
647
778
|
const containerStyle = Object.assign(Object.assign({ position: 'relative', boxSizing: 'border-box', height,
|
|
648
779
|
width }, style), (isH5 && refresherConfig && !supportsNativeRefresher && h5RefresherProps.isRefreshing
|
|
649
780
|
? { overflow: 'hidden' }
|
|
650
781
|
: {}));
|
|
651
782
|
// ScrollView 属性
|
|
652
|
-
const scrollViewProps = Object.assign(Object.assign(Object.assign(Object.assign(
|
|
783
|
+
const scrollViewProps = Object.assign(Object.assign(Object.assign(Object.assign({ scrollY: !scrollX && scrollY, scrollX, style: containerStyle, className, enhanced: true, showScrollbar,
|
|
653
784
|
upperThreshold,
|
|
654
785
|
lowerThreshold, scrollWithAnimation: false, onScroll: handleScroll, onScrollToUpper,
|
|
655
786
|
onScrollToLower,
|
|
656
|
-
onScrollStart, onScrollEnd: handleNativeScrollEnd, enableBackToTop }, (isWeapp ? { scrollAnchoring: true } : {})), (typeof cacheExtent === 'number' ? { cacheExtent } : {})),
|
|
787
|
+
onScrollStart, onScrollEnd: handleNativeScrollEnd, enableBackToTop }, (isWeapp ? { scrollAnchoring: true } : {})), (typeof cacheExtent === 'number' ? { cacheExtent } : {})), scrollViewRefresherProps), scrollViewRefresherHandlers);
|
|
657
788
|
// H5 对齐小程序:refresherTriggered=true 时顶部立即显示加载指示器,滚到顶部并锁定滚动直至设为 false
|
|
658
789
|
React.useEffect(() => {
|
|
659
790
|
if (!isH5 || !refresherConfig || supportsNativeRefresher || !h5RefresherProps.isRefreshing)
|
|
@@ -667,7 +798,7 @@ const InnerList = (props, ref) => {
|
|
|
667
798
|
return;
|
|
668
799
|
let teardown = null;
|
|
669
800
|
const tryAttach = () => {
|
|
670
|
-
const el = containerRef.current;
|
|
801
|
+
const el = useScrollElementMode ? effectiveScrollElement === null || effectiveScrollElement === void 0 ? void 0 : effectiveScrollElement.current : containerRef.current;
|
|
671
802
|
if (el && !refresherTeardownRef.current) {
|
|
672
803
|
teardown = attach(el);
|
|
673
804
|
refresherTeardownRef.current = teardown;
|
|
@@ -682,7 +813,7 @@ const InnerList = (props, ref) => {
|
|
|
682
813
|
}
|
|
683
814
|
refresherTeardownRef.current = null;
|
|
684
815
|
};
|
|
685
|
-
}, []);
|
|
816
|
+
}, [useScrollElementMode, effectiveScrollElement]);
|
|
686
817
|
scrollViewOffsetRef.current = scrollViewOffset;
|
|
687
818
|
// scrollTop:weapp 传 scrollViewOffset(reflow 帧传 eff 防跳变);H5 仅非用户滑动时传
|
|
688
819
|
if (isWeapp) {
|
|
@@ -1018,10 +1149,79 @@ const InnerList = (props, ref) => {
|
|
|
1018
1149
|
innerProps.id = `${listId}-list-item-inner-${currentGlobalIndex}`;
|
|
1019
1150
|
}
|
|
1020
1151
|
innerProps['data-index'] = String(currentGlobalIndex);
|
|
1021
|
-
|
|
1152
|
+
const itemNode = React.createElement(View, outerItemProps, React.createElement(View, innerProps, section.items[i]));
|
|
1153
|
+
// 任务 4.1:当 List 暴露 scrollRef 时,为每个 item 提供 Context,供内层 WaterFlow 使用
|
|
1154
|
+
const itemWithContext = scrollRefProp && !useScrollElementMode
|
|
1155
|
+
? React.createElement(ListScrollElementContext.Provider, {
|
|
1156
|
+
key: outerItemProps.key,
|
|
1157
|
+
value: {
|
|
1158
|
+
scrollRef: scrollRefProp,
|
|
1159
|
+
containerHeight: containerLength,
|
|
1160
|
+
startOffset: offset + itemOffsets[i],
|
|
1161
|
+
reportNestedHeightChange: props.useResizeObserver
|
|
1162
|
+
? (height) => {
|
|
1163
|
+
if (height <= 0)
|
|
1164
|
+
return;
|
|
1165
|
+
const idx = currentGlobalIndex;
|
|
1166
|
+
const estimatedHeader = estimatedSize * 0.5;
|
|
1167
|
+
const fullHeight = height + estimatedHeader;
|
|
1168
|
+
const oldSize = sizeCache.getItemSize(idx);
|
|
1169
|
+
if (Math.abs(oldSize - fullHeight) < 1)
|
|
1170
|
+
return;
|
|
1171
|
+
sizeCache.setItemSize(idx, fullHeight);
|
|
1172
|
+
scrollCorrection.recordSizeChange(idx, oldSize, fullHeight);
|
|
1173
|
+
if (isWeapp && props.useResizeObserver === true) {
|
|
1174
|
+
scheduleWeappDynamicReflow();
|
|
1175
|
+
}
|
|
1176
|
+
else if (sizeCacheRafRef.current == null) {
|
|
1177
|
+
sizeCacheRafRef.current = requestAnimationFrame(() => {
|
|
1178
|
+
sizeCacheRafRef.current = null;
|
|
1179
|
+
setSizeCacheVersion((v) => v + 1);
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
: undefined,
|
|
1184
|
+
},
|
|
1185
|
+
}, itemNode)
|
|
1186
|
+
: itemNode;
|
|
1187
|
+
nodes.push(itemWithContext);
|
|
1022
1188
|
}
|
|
1023
1189
|
else {
|
|
1024
|
-
|
|
1190
|
+
const itemNode = React.createElement(View, outerItemProps, section.items[i]);
|
|
1191
|
+
const itemWithContext = scrollRefProp && !useScrollElementMode
|
|
1192
|
+
? React.createElement(ListScrollElementContext.Provider, {
|
|
1193
|
+
key: outerItemProps.key,
|
|
1194
|
+
value: {
|
|
1195
|
+
scrollRef: scrollRefProp,
|
|
1196
|
+
containerHeight: containerLength,
|
|
1197
|
+
startOffset: offset + itemOffsets[i],
|
|
1198
|
+
reportNestedHeightChange: props.useResizeObserver
|
|
1199
|
+
? (height) => {
|
|
1200
|
+
if (height <= 0)
|
|
1201
|
+
return;
|
|
1202
|
+
const idx = currentGlobalIndex;
|
|
1203
|
+
const estimatedHeader = estimatedSize * 0.5;
|
|
1204
|
+
const fullHeight = height + estimatedHeader;
|
|
1205
|
+
const oldSize = sizeCache.getItemSize(idx);
|
|
1206
|
+
if (Math.abs(oldSize - fullHeight) < 1)
|
|
1207
|
+
return;
|
|
1208
|
+
sizeCache.setItemSize(idx, fullHeight);
|
|
1209
|
+
scrollCorrection.recordSizeChange(idx, oldSize, fullHeight);
|
|
1210
|
+
if (isWeapp && props.useResizeObserver === true) {
|
|
1211
|
+
scheduleWeappDynamicReflow();
|
|
1212
|
+
}
|
|
1213
|
+
else if (sizeCacheRafRef.current == null) {
|
|
1214
|
+
sizeCacheRafRef.current = requestAnimationFrame(() => {
|
|
1215
|
+
sizeCacheRafRef.current = null;
|
|
1216
|
+
setSizeCacheVersion((v) => v + 1);
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
: undefined,
|
|
1221
|
+
},
|
|
1222
|
+
}, itemNode)
|
|
1223
|
+
: itemNode;
|
|
1224
|
+
nodes.push(itemWithContext);
|
|
1025
1225
|
}
|
|
1026
1226
|
}
|
|
1027
1227
|
globalItemIndex += section.items.length;
|
|
@@ -1038,16 +1238,17 @@ const InnerList = (props, ref) => {
|
|
|
1038
1238
|
const defaultStyle = Object.assign(Object.assign(Object.assign({ position: 'absolute' }, (isHorizontal
|
|
1039
1239
|
? { left: listContentEnd, top: 0, width: noMoreHeightValue, height: '100%' }
|
|
1040
1240
|
: { top: listContentEnd, left: 0, width: '100%', height: noMoreHeightValue })), { display: 'flex', alignItems: 'center', justifyContent: 'center', textAlign: 'center', color: '#999', fontSize: '14px', boxSizing: 'border-box' }), noMoreConfig.style);
|
|
1041
|
-
return (jsx(View, { style: defaultStyle,
|
|
1241
|
+
return (jsx(View, { style: defaultStyle, children: noMoreConfig.children || noMoreConfig.text || '没有更多了' }));
|
|
1042
1242
|
};
|
|
1043
1243
|
// 空列表场景:仅显示 NoMore
|
|
1044
1244
|
if (sections.length === 0 && (noMoreConfig === null || noMoreConfig === void 0 ? void 0 : noMoreConfig.visible)) {
|
|
1045
1245
|
return (jsx(ScrollView, Object.assign({ ref: containerRef }, scrollViewProps, { children: jsx(View, { style: Object.assign({ minHeight: containerLength, display: 'flex', alignItems: 'center', justifyContent: 'center' }, containerStyle), children: renderNoMoreContent() }) })));
|
|
1046
1246
|
}
|
|
1047
1247
|
// 可滚区域总尺寸
|
|
1248
|
+
// H5 refresher 用负 translateY 隐藏,有上方混排时可能延伸到 sibling 区域;overflow:hidden 裁剪避免重叠
|
|
1249
|
+
const needsRefresherClip = refresherHeightForH5 > 0;
|
|
1048
1250
|
const contentWrapperStyle = isHorizontal
|
|
1049
|
-
? { width: totalLength, position: 'relative', height: '100%' }
|
|
1050
|
-
: { height: totalLength, position: 'relative', width: '100%' };
|
|
1251
|
+
? Object.assign({ width: totalLength, position: 'relative', height: '100%' }, (needsRefresherClip && { overflow: 'hidden' })) : Object.assign({ height: totalLength, position: 'relative', width: '100%' }, (needsRefresherClip && { overflow: 'hidden' }));
|
|
1051
1252
|
const listWrapperStyle = isHorizontal
|
|
1052
1253
|
? { width: listContentLength, position: 'relative', height: '100%' }
|
|
1053
1254
|
: { height: listContentLength, position: 'relative', width: '100%' };
|
|
@@ -1068,9 +1269,21 @@ const InnerList = (props, ref) => {
|
|
|
1068
1269
|
transform: `translateY(${h5RefresherTranslateY}px)`,
|
|
1069
1270
|
}, 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()] })) }));
|
|
1070
1271
|
};
|
|
1272
|
+
if (useScrollElementMode) {
|
|
1273
|
+
// 任务 2.4:恢复 refresher DOM 结构(refresher 层 + listWrapperStyle)
|
|
1274
|
+
return (jsx(View, { ref: contentWrapperRef, style: contentWrapperStyle, children: refresherHeightForH5 > 0 ? (jsxs(Fragment, { children: [jsx(View, { style: {
|
|
1275
|
+
position: 'absolute',
|
|
1276
|
+
top: 0,
|
|
1277
|
+
left: 0,
|
|
1278
|
+
right: 0,
|
|
1279
|
+
height: refresherHeightForH5,
|
|
1280
|
+
zIndex: 0,
|
|
1281
|
+
transform: `translateY(${h5RefresherTranslateY}px)`,
|
|
1282
|
+
}, children: renderRefresherContent() }), jsxs(View, { style: Object.assign(Object.assign(Object.assign({}, listWrapperStyle), pullTranslate), { zIndex: 1, background: (_d = (_c = style === null || style === void 0 ? void 0 : style.background) !== null && _c !== void 0 ? _c : style === null || style === void 0 ? void 0 : style.backgroundColor) !== null && _d !== void 0 ? _d : '#fff' }), children: [stickyHeaderNode, renderSections(), renderNoMoreContent()] })] })) : (jsxs(Fragment, { children: [stickyHeaderNode, renderSections(), renderNoMoreContent()] })) }));
|
|
1283
|
+
}
|
|
1071
1284
|
return (jsxs(ScrollView, Object.assign({ ref: containerRef }, scrollViewProps, { id: listId, children: [supportsNativeRefresher && renderRefresherContent(), renderContentArea()] })));
|
|
1072
1285
|
};
|
|
1073
1286
|
const List = React.forwardRef(InnerList);
|
|
1074
1287
|
|
|
1075
|
-
export { List, ListItem, NoMore, StickyHeader, StickySection, accumulate, List as default, isShaking };
|
|
1288
|
+
export { List, ListItem, ListScrollElementContext, NoMore, StickyHeader, StickySection, accumulate, List as default, isShaking };
|
|
1076
1289
|
//# sourceMappingURL=index.js.map
|