@tarojs/components-advanced 4.1.12-beta.4 → 4.1.12-beta.40
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 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/list/hooks/useItemSizeCache.d.ts +1 -13
- package/dist/components/list/hooks/useItemSizeCache.js +6 -50
- package/dist/components/list/hooks/useItemSizeCache.js.map +1 -1
- 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 +14 -0
- package/dist/components/list/hooks/useListScrollElementAttachWeapp.js +134 -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 +82 -0
- package/dist/components/list/hooks/useMeasureStartOffsetWeapp.js.map +1 -0
- package/dist/components/list/hooks/useRefresher.d.ts +10 -2
- package/dist/components/list/hooks/useRefresher.js +150 -69
- package/dist/components/list/hooks/useRefresher.js.map +1 -1
- package/dist/components/list/hooks/useResizeObserver.d.ts +1 -0
- package/dist/components/list/hooks/useResizeObserver.js +37 -31
- package/dist/components/list/hooks/useResizeObserver.js.map +1 -1
- package/dist/components/list/hooks/useScrollCorrection.d.ts +3 -2
- package/dist/components/list/hooks/useScrollCorrection.js +7 -5
- package/dist/components/list/hooks/useScrollCorrection.js.map +1 -1
- 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 +16 -6
- package/dist/components/list/index.js +435 -498
- package/dist/components/list/index.js.map +1 -1
- package/dist/components/list/utils.d.ts +5 -0
- package/dist/components/list/utils.js +17 -1
- package/dist/components/list/utils.js.map +1 -1
- package/dist/components/virtual-list/vue/list.d.ts +10 -10
- package/dist/components/virtual-waterfall/vue/waterfall.d.ts +10 -10
- package/dist/components/water-flow/flow-item.js +6 -4
- 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 +18 -2
- package/dist/components/water-flow/root.d.ts +35 -4
- package/dist/components/water-flow/root.js +114 -42
- package/dist/components/water-flow/root.js.map +1 -1
- package/dist/components/water-flow/section.d.ts +7 -1
- package/dist/components/water-flow/section.js +54 -9
- 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 +286 -31
- package/dist/components/water-flow/water-flow.js.map +1 -1
- package/dist/index.js +2 -0
- 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/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/package.json +9 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../../src/components/list/utils.ts"],"sourcesContent":["/**\n * List 组件工具函数\n */\n\n/** 判断是否为微信小程序 */\nexport const isWeapp = process.env.TARO_ENV === 'weapp'\n\n/** 判断是否为支付宝小程序 */\nexport const isAlipay = process.env.TARO_ENV === 'alipay'\n\n/** 判断是否为 H5 */\nexport const isH5 = process.env.TARO_ENV === 'h5'\n\n/** 判断是否为小程序环境(微信/支付宝/百度/京东/头条等) */\nexport const isMiniProgram = isWeapp || isAlipay || process.env.TARO_ENV === 'swan' || process.env.TARO_ENV === 'tt' || process.env.TARO_ENV === 'jd'\n\n/**\n * 是否支持原生 refresher(ScrollView refresher-*)\n * 以各平台 components 为准:weapp/jd/tt 的 ScrollView 有 refresher-enabled 等;harmony-hybrid 的 harmony-definition 中 refresher-* 为 false,走自定义下拉\n */\nexport const supportsNativeRefresher = isMiniProgram\n"],"names":[],"mappings":"AAAA;;AAEG;
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../src/components/list/utils.ts"],"sourcesContent":["/**\n * List 组件工具函数\n */\n\nimport Taro from '@tarojs/taro'\n\n/** 有 scope 则 `query.in(scope)`,否则与原先一致(page / 根) */\nexport function createSelectorQueryScoped (selectorQueryScope?: object) {\n if (selectorQueryScope != null) {\n return Taro.createSelectorQuery().in(selectorQueryScope as any)\n }\n const instance = Taro.getCurrentInstance()\n return instance?.page\n ? Taro.createSelectorQuery().in(instance.page as any)\n : Taro.createSelectorQuery()\n}\n\n/** IO 作用域,缺省为 page */\nexport function getMiniProgramObserverScope (selectorQueryScope?: object) {\n return (selectorQueryScope ?? Taro.getCurrentInstance().page) as any\n}\n\n/** 判断是否为微信小程序 */\nexport const isWeapp = process.env.TARO_ENV === 'weapp'\n\n/** 判断是否为支付宝小程序 */\nexport const isAlipay = process.env.TARO_ENV === 'alipay'\n\n/** 判断是否为 H5 */\nexport const isH5 = process.env.TARO_ENV === 'h5'\n\n/** 判断是否为小程序环境(微信/支付宝/百度/京东/头条等) */\nexport const isMiniProgram = isWeapp || isAlipay || process.env.TARO_ENV === 'swan' || process.env.TARO_ENV === 'tt' || process.env.TARO_ENV === 'jd'\n\n/**\n * 是否支持原生 refresher(ScrollView refresher-*)\n * 以各平台 components 为准:weapp/jd/tt 的 ScrollView 有 refresher-enabled 等;harmony-hybrid 的 harmony-definition 中 refresher-* 为 false,走自定义下拉\n */\nexport const supportsNativeRefresher = isMiniProgram\n"],"names":[],"mappings":";;AAAA;;AAEG;AAIH;AACM,SAAU,yBAAyB,CAAE,kBAA2B,EAAA;AACpE,IAAA,IAAI,kBAAkB,IAAI,IAAI,EAAE;QAC9B,OAAO,IAAI,CAAC,mBAAmB,EAAE,CAAC,EAAE,CAAC,kBAAyB,CAAC;;AAEjE,IAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,kBAAkB,EAAE;AAC1C,IAAA,OAAO,CAAA,QAAQ,KAAA,IAAA,IAAR,QAAQ,KAAR,KAAA,CAAA,GAAA,KAAA,CAAA,GAAA,QAAQ,CAAE,IAAI;UACjB,IAAI,CAAC,mBAAmB,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAW;AACpD,UAAE,IAAI,CAAC,mBAAmB,EAAE;AAChC;AAEA;AACM,SAAU,2BAA2B,CAAE,kBAA2B,EAAA;AACtE,IAAA,QAAQ,kBAAkB,KAAlB,IAAA,IAAA,kBAAkB,cAAlB,kBAAkB,GAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC,IAAI;AAC9D;AAEA;AACa,MAAA,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK;AAEhD;AACa,MAAA,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK;AAEjD;AACa,MAAA,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK;AAE7C;AACO,MAAM,aAAa,GAAG,OAAO,IAAI,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK;AAEjJ;;;AAGG;AACI,MAAM,uBAAuB,GAAG;;;;"}
|
|
@@ -2,11 +2,11 @@ import Preset from '../preset';
|
|
|
2
2
|
declare const _default: import("vue").DefineComponent<{
|
|
3
3
|
id: StringConstructor;
|
|
4
4
|
height: {
|
|
5
|
-
type: (
|
|
5
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
6
6
|
required: true;
|
|
7
7
|
};
|
|
8
8
|
width: {
|
|
9
|
-
type: (
|
|
9
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
10
10
|
required: true;
|
|
11
11
|
};
|
|
12
12
|
item: {
|
|
@@ -93,11 +93,11 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
93
93
|
instance: import("vue").CreateComponentPublicInstance<Readonly<import("vue").ExtractPropTypes<{
|
|
94
94
|
id: StringConstructor;
|
|
95
95
|
height: {
|
|
96
|
-
type: (
|
|
96
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
97
97
|
required: true;
|
|
98
98
|
};
|
|
99
99
|
width: {
|
|
100
|
-
type: (
|
|
100
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
101
101
|
required: true;
|
|
102
102
|
};
|
|
103
103
|
item: {
|
|
@@ -181,11 +181,11 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
181
181
|
}>> & {}, {}, {}, {}, import("vue").MethodOptions, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, Readonly<import("vue").ExtractPropTypes<{
|
|
182
182
|
id: StringConstructor;
|
|
183
183
|
height: {
|
|
184
|
-
type: (
|
|
184
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
185
185
|
required: true;
|
|
186
186
|
};
|
|
187
187
|
width: {
|
|
188
|
-
type: (
|
|
188
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
189
189
|
required: true;
|
|
190
190
|
};
|
|
191
191
|
item: {
|
|
@@ -276,11 +276,11 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
276
276
|
}, Readonly<import("vue").ExtractPropTypes<{
|
|
277
277
|
id: StringConstructor;
|
|
278
278
|
height: {
|
|
279
|
-
type: (
|
|
279
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
280
280
|
required: true;
|
|
281
281
|
};
|
|
282
282
|
width: {
|
|
283
|
-
type: (
|
|
283
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
284
284
|
required: true;
|
|
285
285
|
};
|
|
286
286
|
item: {
|
|
@@ -394,11 +394,11 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
394
394
|
}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
|
395
395
|
id: StringConstructor;
|
|
396
396
|
height: {
|
|
397
|
-
type: (
|
|
397
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
398
398
|
required: true;
|
|
399
399
|
};
|
|
400
400
|
width: {
|
|
401
|
-
type: (
|
|
401
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
402
402
|
required: true;
|
|
403
403
|
};
|
|
404
404
|
item: {
|
|
@@ -2,11 +2,11 @@ import Preset from '../preset';
|
|
|
2
2
|
declare const _default: import("vue").DefineComponent<{
|
|
3
3
|
id: StringConstructor;
|
|
4
4
|
height: {
|
|
5
|
-
type: (
|
|
5
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
6
6
|
required: true;
|
|
7
7
|
};
|
|
8
8
|
width: {
|
|
9
|
-
type: (
|
|
9
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
10
10
|
required: true;
|
|
11
11
|
};
|
|
12
12
|
column: NumberConstructor;
|
|
@@ -87,11 +87,11 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
87
87
|
instance: import("vue").CreateComponentPublicInstance<Readonly<import("vue").ExtractPropTypes<{
|
|
88
88
|
id: StringConstructor;
|
|
89
89
|
height: {
|
|
90
|
-
type: (
|
|
90
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
91
91
|
required: true;
|
|
92
92
|
};
|
|
93
93
|
width: {
|
|
94
|
-
type: (
|
|
94
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
95
95
|
required: true;
|
|
96
96
|
};
|
|
97
97
|
column: NumberConstructor;
|
|
@@ -169,11 +169,11 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
169
169
|
}>> & {}, {}, {}, {}, import("vue").MethodOptions, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, Readonly<import("vue").ExtractPropTypes<{
|
|
170
170
|
id: StringConstructor;
|
|
171
171
|
height: {
|
|
172
|
-
type: (
|
|
172
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
173
173
|
required: true;
|
|
174
174
|
};
|
|
175
175
|
width: {
|
|
176
|
-
type: (
|
|
176
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
177
177
|
required: true;
|
|
178
178
|
};
|
|
179
179
|
column: NumberConstructor;
|
|
@@ -258,11 +258,11 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
258
258
|
}, Readonly<import("vue").ExtractPropTypes<{
|
|
259
259
|
id: StringConstructor;
|
|
260
260
|
height: {
|
|
261
|
-
type: (
|
|
261
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
262
262
|
required: true;
|
|
263
263
|
};
|
|
264
264
|
width: {
|
|
265
|
-
type: (
|
|
265
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
266
266
|
required: true;
|
|
267
267
|
};
|
|
268
268
|
column: NumberConstructor;
|
|
@@ -368,11 +368,11 @@ declare const _default: import("vue").DefineComponent<{
|
|
|
368
368
|
}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
|
369
369
|
id: StringConstructor;
|
|
370
370
|
height: {
|
|
371
|
-
type: (
|
|
371
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
372
372
|
required: true;
|
|
373
373
|
};
|
|
374
374
|
width: {
|
|
375
|
-
type: (
|
|
375
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
376
376
|
required: true;
|
|
377
377
|
};
|
|
378
378
|
column: NumberConstructor;
|
|
@@ -35,13 +35,15 @@ function FlowItemContainer(_a) {
|
|
|
35
35
|
const itemStyle = useMemo(() => {
|
|
36
36
|
const baseStyle = {
|
|
37
37
|
width: '100%',
|
|
38
|
-
|
|
38
|
+
position: 'absolute',
|
|
39
|
+
top: 0,
|
|
40
|
+
left: 0,
|
|
41
|
+
transform: `translate3d(0px, ${top$}px, 0px)`,
|
|
39
42
|
};
|
|
40
43
|
if (!layouted$) {
|
|
41
|
-
return baseStyle;
|
|
44
|
+
return Object.assign(Object.assign({}, baseStyle), { minHeight: node.section.defaultSize });
|
|
42
45
|
}
|
|
43
|
-
|
|
44
|
-
return Object.assign(Object.assign({}, baseStyle), { height: height$, transition: 'transform 20ms cubic-bezier(0.075, 0.82, 0.165, 1)', willChange: 'transform', position: 'absolute', top: 0, left: 0, transform: `translate3d(0px, ${top$}px, 0px)` });
|
|
46
|
+
return Object.assign(Object.assign({}, baseStyle), { height: height$ });
|
|
45
47
|
}, [top$, layouted$, height$]);
|
|
46
48
|
useEffect(() => {
|
|
47
49
|
let observer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow-item.js","sources":["../../../src/components/water-flow/flow-item.ts"],"sourcesContent":["import { View } from '@tarojs/components'\nimport {\n type CSSProperties,\n type PropsWithChildren,\n createContext,\n createElement,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n} from 'react'\n\nimport { Node, NodeEvents } from './node'\nimport { useMemoizedFn } from './use-memoized-fn'\nimport { useObservedAttr } from './use-observed-attr'\nimport { isWeb } from './utils'\n\nimport type { FlowItemContainerProps } from './interface'\n\nconst FlowItemContext = createContext<{ node: Node }>(Object.create(null))\nexport const useFlowItemPositioner = () => {\n const nodeModel = useContext(FlowItemContext).node\n const width$ = useObservedAttr(nodeModel, 'width')\n const height$ = useObservedAttr(nodeModel, 'height')\n const top$ = useObservedAttr(nodeModel, 'top')\n const scrollTop$ = useObservedAttr(nodeModel, 'scrollTop')\n\n return {\n resize: useMemoizedFn(() => {\n if (!isWeb()) {\n nodeModel.pub(NodeEvents.Resize)\n }\n }),\n top: top$,\n scrollTop: scrollTop$,\n width: width$,\n height: height$,\n }\n}\n\nexport function FlowItemContainer({\n children,\n ...props\n}: PropsWithChildren<FlowItemContainerProps>) {\n const { node } = props\n const layouted$ = useObservedAttr(node, 'layouted')\n const top$ = useObservedAttr(node, 'top')\n const height$ = useObservedAttr(node, 'height')\n const refFlowItem = useRef<HTMLElement>()\n\n const itemStyle: CSSProperties = useMemo(() => {\n const baseStyle: CSSProperties = {\n width: '100%',\n
|
|
1
|
+
{"version":3,"file":"flow-item.js","sources":["../../../src/components/water-flow/flow-item.ts"],"sourcesContent":["import { View } from '@tarojs/components'\nimport {\n type CSSProperties,\n type PropsWithChildren,\n createContext,\n createElement,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n} from 'react'\n\nimport { Node, NodeEvents } from './node'\nimport { useMemoizedFn } from './use-memoized-fn'\nimport { useObservedAttr } from './use-observed-attr'\nimport { isWeb } from './utils'\n\nimport type { FlowItemContainerProps } from './interface'\n\nconst FlowItemContext = createContext<{ node: Node }>(Object.create(null))\nexport const useFlowItemPositioner = () => {\n const nodeModel = useContext(FlowItemContext).node\n const width$ = useObservedAttr(nodeModel, 'width')\n const height$ = useObservedAttr(nodeModel, 'height')\n const top$ = useObservedAttr(nodeModel, 'top')\n const scrollTop$ = useObservedAttr(nodeModel, 'scrollTop')\n\n return {\n resize: useMemoizedFn(() => {\n if (!isWeb()) {\n nodeModel.pub(NodeEvents.Resize)\n }\n }),\n top: top$,\n scrollTop: scrollTop$,\n width: width$,\n height: height$,\n }\n}\n\nexport function FlowItemContainer({\n children,\n ...props\n}: PropsWithChildren<FlowItemContainerProps>) {\n const { node } = props\n const layouted$ = useObservedAttr(node, 'layouted')\n const top$ = useObservedAttr(node, 'top')\n const height$ = useObservedAttr(node, 'height')\n const refFlowItem = useRef<HTMLElement>()\n\n const itemStyle: CSSProperties = useMemo(() => {\n const baseStyle: CSSProperties = {\n width: '100%',\n position: 'absolute',\n top: 0,\n left: 0,\n transform: `translate3d(0px, ${top$}px, 0px)`,\n }\n if (!layouted$) {\n return {\n ...baseStyle,\n minHeight: node.section.defaultSize,\n }\n }\n return {\n ...baseStyle,\n height: height$,\n }\n }, [top$, layouted$, height$])\n\n useEffect(() => {\n let observer: ResizeObserver\n if (isWeb() && typeof ResizeObserver !== 'undefined') {\n observer = new ResizeObserver(() => {\n node.pub(NodeEvents.Resize)\n })\n observer.observe(refFlowItem.current!)\n }\n return () => {\n if (observer) {\n observer.disconnect()\n }\n }\n }, [node])\n\n useLayoutEffect(() => {\n node.measure()\n }, [node])\n\n return createElement(\n View,\n { style: itemStyle, key: node.id },\n createElement(\n View,\n { id: node.id, ref: refFlowItem },\n createElement(FlowItemContext.Provider, { value: { node } }, children)\n )\n )\n}\n\nexport function FlowItem(props: PropsWithChildren) {\n return props.children\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -58,7 +58,7 @@ function FlowSection(_a) {
|
|
|
58
58
|
return createElement(FlowItemContainer, columnProps, childNode);
|
|
59
59
|
}));
|
|
60
60
|
});
|
|
61
|
-
}, [children, layouted$, section.columnMap, renderRange
|
|
61
|
+
}, [children, layouted$, section.columnMap, renderRange$]);
|
|
62
62
|
return createElement(View, { style: sectionStyle, className, id: id !== null && id !== void 0 ? id : section.id }, columns);
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow-section.js","sources":["../../../src/components/water-flow/flow-section.ts"],"sourcesContent":["import { View } from '@tarojs/components'\nimport {\n type CSSProperties,\n type PropsWithChildren,\n Children,\n createElement,\n useMemo,\n} from 'react'\n\nimport { FlowItemContainer } from './flow-item'\nimport { Section } from './section'\nimport { useObservedAttr } from './use-observed-attr'\n\nimport type { FlowSectionProps } from './interface'\n\nexport interface _FlowSectionProps extends FlowSectionProps {\n section: Section\n}\n\nexport function FlowSection({\n children,\n ...props\n}: PropsWithChildren<FlowSectionProps>) {\n const {\n id,\n className,\n style,\n section,\n rowGap = 0,\n columnGap = 0,\n } = props as _FlowSectionProps\n const layouted$ = useObservedAttr(section, 'layouted')\n const height$ = useObservedAttr(section, 'height')\n const renderRange$ = useObservedAttr(section, 'renderRange')\n const scrollTop$ = useObservedAttr(section, 'scrollTop')\n\n const sectionStyle: CSSProperties = useMemo(() => {\n const baseStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'row',\n width: '100%',\n height: height$,\n gap: columnGap,\n visibility: layouted$ ? 'visible' : 'hidden',\n ...style,\n }\n\n if (!layouted$) {\n return baseStyle\n }\n\n return {\n ...baseStyle,\n position: 'absolute',\n top: 0,\n transform: `translate3d(0px, ${scrollTop$}px, 0px)`,\n left: 0,\n }\n }, [height$, style, layouted$, scrollTop$, columnGap])\n\n const columns = useMemo(() => {\n const childNodes = Children.toArray(children)\n const columnStyle: CSSProperties = {\n position: 'relative',\n display: 'flex',\n flexDirection: 'column',\n gap: rowGap,\n flex: 1,\n }\n /** 已经完成布局计算,使用虚拟滚动 */\n if (layouted$) {\n return renderRange$.map(([startIndex, endIndex], colIndex) => {\n const columnId = `col-${colIndex}`\n return createElement(\n View,\n {\n style: columnStyle,\n id: columnId,\n key: columnId,\n },\n section.columnMap[colIndex]\n .slice(startIndex, endIndex + 1)\n .map((node) => {\n const childNode = childNodes[node.childIndex]\n const columnProps: any = {\n node,\n key: node.id,\n }\n return createElement(FlowItemContainer, columnProps, childNode)\n })\n )\n })\n }\n\n return section.columnMap.map((column, colIndex) => {\n const columnId = `col-${colIndex}`\n return createElement(\n View,\n { style: columnStyle, id: columnId, key: columnId },\n column.map((node) => {\n const childNode = childNodes[node.childIndex]\n const columnProps: any = {\n node,\n key: node.id,\n }\n return createElement(FlowItemContainer, columnProps, childNode)\n })\n )\n })\n }, [children, layouted$, section.columnMap, renderRange
|
|
1
|
+
{"version":3,"file":"flow-section.js","sources":["../../../src/components/water-flow/flow-section.ts"],"sourcesContent":["import { View } from '@tarojs/components'\nimport {\n type CSSProperties,\n type PropsWithChildren,\n Children,\n createElement,\n useMemo,\n} from 'react'\n\nimport { FlowItemContainer } from './flow-item'\nimport { Section } from './section'\nimport { useObservedAttr } from './use-observed-attr'\n\nimport type { FlowSectionProps } from './interface'\n\nexport interface _FlowSectionProps extends FlowSectionProps {\n section: Section\n}\n\nexport function FlowSection({\n children,\n ...props\n}: PropsWithChildren<FlowSectionProps>) {\n const {\n id,\n className,\n style,\n section,\n rowGap = 0,\n columnGap = 0,\n } = props as _FlowSectionProps\n const layouted$ = useObservedAttr(section, 'layouted')\n const height$ = useObservedAttr(section, 'height')\n const renderRange$ = useObservedAttr(section, 'renderRange')\n const scrollTop$ = useObservedAttr(section, 'scrollTop')\n\n const sectionStyle: CSSProperties = useMemo(() => {\n const baseStyle: CSSProperties = {\n display: 'flex',\n flexDirection: 'row',\n width: '100%',\n height: height$,\n gap: columnGap,\n visibility: layouted$ ? 'visible' : 'hidden',\n ...style,\n }\n\n if (!layouted$) {\n return baseStyle\n }\n\n return {\n ...baseStyle,\n position: 'absolute',\n top: 0,\n transform: `translate3d(0px, ${scrollTop$}px, 0px)`,\n left: 0,\n }\n }, [height$, style, layouted$, scrollTop$, columnGap])\n\n const columns = useMemo(() => {\n const childNodes = Children.toArray(children)\n const columnStyle: CSSProperties = {\n position: 'relative',\n display: 'flex',\n flexDirection: 'column',\n gap: rowGap,\n flex: 1,\n }\n /** 已经完成布局计算,使用虚拟滚动 */\n if (layouted$) {\n return renderRange$.map(([startIndex, endIndex], colIndex) => {\n const columnId = `col-${colIndex}`\n return createElement(\n View,\n {\n style: columnStyle,\n id: columnId,\n key: columnId,\n },\n section.columnMap[colIndex]\n .slice(startIndex, endIndex + 1)\n .map((node) => {\n const childNode = childNodes[node.childIndex]\n const columnProps: any = {\n node,\n key: node.id,\n }\n return createElement(FlowItemContainer, columnProps, childNode)\n })\n )\n })\n }\n\n return section.columnMap.map((column, colIndex) => {\n const columnId = `col-${colIndex}`\n return createElement(\n View,\n { style: columnStyle, id: columnId, key: columnId },\n column.map((node) => {\n const childNode = childNodes[node.childIndex]\n const columnProps: any = {\n node,\n key: node.id,\n }\n return createElement(FlowItemContainer, columnProps, childNode)\n })\n )\n })\n }, [children, layouted$, section.columnMap, renderRange$])\n\n return createElement(\n View,\n { style: sectionStyle, className, id: id ?? section.id },\n columns\n )\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { FlowItem, useFlowItemPositioner } from './flow-item';
|
|
2
2
|
export { FlowSection } from './flow-section';
|
|
3
|
-
export type { FlowSectionProps, WaterFlowProps } from './interface';
|
|
3
|
+
export type { FlowSectionProps, WaterFlowProps, WaterFlowRef } from './interface';
|
|
4
4
|
export { WaterFlow } from './water-flow';
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { ScrollViewProps } from '@tarojs/components';
|
|
2
2
|
import { Node } from './node';
|
|
3
|
-
import type { CSSProperties } from 'react';
|
|
3
|
+
import type { CSSProperties, RefObject } from 'react';
|
|
4
4
|
export interface BaseProps {
|
|
5
5
|
id?: string;
|
|
6
6
|
className?: string;
|
|
7
7
|
style?: CSSProperties;
|
|
8
8
|
}
|
|
9
|
-
export interface WaterFlowProps extends Omit<ScrollViewProps, 'cacheExtent' | 'upperThreshold' | 'lowerThreshold' | 'style'>, Pick<BaseProps, 'style'> {
|
|
9
|
+
export interface WaterFlowProps extends Omit<ScrollViewProps, 'cacheExtent' | 'upperThreshold' | 'lowerThreshold' | 'style' | 'type'>, Pick<BaseProps, 'style'> {
|
|
10
10
|
/**
|
|
11
11
|
* 距顶部多少个FlowItem时,触发 scrolltoupper 事件
|
|
12
12
|
* @default 0
|
|
@@ -22,6 +22,22 @@ export interface WaterFlowProps extends Omit<ScrollViewProps, 'cacheExtent' | 'u
|
|
|
22
22
|
* @default 50
|
|
23
23
|
*/
|
|
24
24
|
cacheCount?: number;
|
|
25
|
+
/** 是否嵌套模式,与 plato 对齐;true=使用父级滚动,需配合 scrollElement 或 Context;不传或 false=default */
|
|
26
|
+
nestedScroll?: boolean;
|
|
27
|
+
/** 自定义滚动容器 ref,nestedScroll 模式下从 props 或 Context 获取 */
|
|
28
|
+
scrollElement?: RefObject<HTMLElement | null>;
|
|
29
|
+
/** WaterFlow 内容在滚动容器中的起始偏移(上方有其他内容时使用) */
|
|
30
|
+
startOffset?: number;
|
|
31
|
+
/** 可视区高度,scrollElement 模式下可选,不传则从 scrollElement.clientHeight 获取 */
|
|
32
|
+
containerHeight?: number;
|
|
33
|
+
/** 瀑布流内容高度变化时回调,便于 List 动高联动(避免底部空白) */
|
|
34
|
+
onScrollHeightChange?: (height: number) => void;
|
|
35
|
+
/** scrollIntoView 滚动完成后回调,便于父组件清空 scrollIntoView 以支持重复点击同一目标 */
|
|
36
|
+
onScrollIntoViewComplete?: () => void;
|
|
37
|
+
}
|
|
38
|
+
/** WaterFlow ref 类型,current 指向内容容器,用于 IntersectionObserver root、SelectorQuery.in 等 */
|
|
39
|
+
export interface WaterFlowRef {
|
|
40
|
+
current: HTMLElement | null;
|
|
25
41
|
}
|
|
26
42
|
export interface FlowSectionProps extends BaseProps {
|
|
27
43
|
/**
|
|
@@ -2,7 +2,10 @@ import { Node } from './node';
|
|
|
2
2
|
import { Section } from './section';
|
|
3
3
|
import { StatefulEventBus } from './stateful-event-bus';
|
|
4
4
|
import type { BaseProps, ScrollDirection, Size, WaterFlowProps } from './interface';
|
|
5
|
-
export type RootProps = Pick<WaterFlowProps, 'cacheCount' | 'lowerThresholdCount' | 'upperThresholdCount'> & Required<Pick<BaseProps, 'id'
|
|
5
|
+
export type RootProps = Pick<WaterFlowProps, 'cacheCount' | 'lowerThresholdCount' | 'upperThresholdCount'> & Required<Pick<BaseProps, 'id'>> & {
|
|
6
|
+
/** scrollElement 模式下为 true,不测量自有容器;此时需布局全部 section 以展开完整高度 */
|
|
7
|
+
skipContainerMeasure?: boolean;
|
|
8
|
+
};
|
|
6
9
|
type RootState = {
|
|
7
10
|
/** 是否在滚动中 */
|
|
8
11
|
isScrolling: boolean;
|
|
@@ -52,9 +55,17 @@ export declare class Root extends StatefulEventBus<RootState, Events> {
|
|
|
52
55
|
*/
|
|
53
56
|
sections: Section[];
|
|
54
57
|
/**
|
|
55
|
-
* 设置预加载的 Item
|
|
58
|
+
* 设置预加载的 Item 条数(与 props.cacheCount 一致,收敛目标)。
|
|
56
59
|
*/
|
|
57
60
|
cacheCount: number;
|
|
61
|
+
/**
|
|
62
|
+
* Node 层向上(列索引减小方向)预缓存条数,可与 cacheCount 不同(快速滑动单边放大)。
|
|
63
|
+
*/
|
|
64
|
+
nodeCacheBackward: number;
|
|
65
|
+
/**
|
|
66
|
+
* Node 层向下(列索引增大方向)预缓存条数。
|
|
67
|
+
*/
|
|
68
|
+
nodeCacheForward: number;
|
|
58
69
|
upperThresholdCount: number;
|
|
59
70
|
lowerThresholdCount: number;
|
|
60
71
|
/**
|
|
@@ -65,6 +76,14 @@ export declare class Root extends StatefulEventBus<RootState, Events> {
|
|
|
65
76
|
* 触发滚动阈值对应的 scrollTop 值
|
|
66
77
|
*/
|
|
67
78
|
lowerThresholdScrollTop: number;
|
|
79
|
+
/** scrollElement 模式下为 true,需布局全部 section 以展开完整高度供父容器滚动 */
|
|
80
|
+
skipContainerMeasure: boolean;
|
|
81
|
+
/** 当前是否处于触顶区域;初始为 true(起始在顶部),只有从 false→true 时才触发事件 */
|
|
82
|
+
private _inUpperZone;
|
|
83
|
+
/** 当前是否处于触底区域;初始为 false */
|
|
84
|
+
private _inLowerZone;
|
|
85
|
+
/** scrollHeight 更新防抖(raf),减轻 pushNodes 后测量前后的高度跳变 */
|
|
86
|
+
private _scrollHeightRafId;
|
|
68
87
|
constructor(props: RootProps);
|
|
69
88
|
/**
|
|
70
89
|
* 设置订阅事件
|
|
@@ -94,8 +113,15 @@ export declare class Root extends StatefulEventBus<RootState, Events> {
|
|
|
94
113
|
/**
|
|
95
114
|
* 处理滚动到阈值的情况
|
|
96
115
|
* 检测当前滚动位置是否达到了上下阈值,并触发相应的事件
|
|
116
|
+
* scrollElement 模式:scrollOffset 为内容内偏移(scrollTop - startOffset),upper/lowerThresholdScrollTop 基于本组件内容计算,触顶/触底以本 WaterFlow 内容为基准
|
|
97
117
|
*/
|
|
98
118
|
private handleReachThreshold;
|
|
119
|
+
/**
|
|
120
|
+
* 列表追加并完成 finalize 后调用:重置触底边沿状态(_inLowerZone),
|
|
121
|
+
* 使用户仍在底部时下一次滚动能再次触发 onScrollToLower,而不必先上滑再下滑。
|
|
122
|
+
* 不在此处同步调用 handleReachThreshold,避免仍在底部时立刻连发触底(与误触区分)。
|
|
123
|
+
*/
|
|
124
|
+
resetLowerReachEdgeAfterContentChange(): void;
|
|
99
125
|
/**
|
|
100
126
|
* 容器的滚动上边界
|
|
101
127
|
*/
|
|
@@ -113,9 +139,10 @@ export declare class Root extends StatefulEventBus<RootState, Events> {
|
|
|
113
139
|
*/
|
|
114
140
|
get sectionRange(): number[][];
|
|
115
141
|
/**
|
|
116
|
-
*
|
|
142
|
+
* 更新总滚动高度(各 Section 累计)。
|
|
143
|
+
* @param immediate true 时跳过 raf 防抖(如 finalizePushNodesStateIfNeeded),避免高度滞后引起跳动
|
|
117
144
|
*/
|
|
118
|
-
updateScrollHeight(): void;
|
|
145
|
+
updateScrollHeight(immediate?: boolean): void;
|
|
119
146
|
/**
|
|
120
147
|
* 注册分组
|
|
121
148
|
*/
|
|
@@ -132,6 +159,10 @@ export declare class Root extends StatefulEventBus<RootState, Events> {
|
|
|
132
159
|
* 查找节点
|
|
133
160
|
*/
|
|
134
161
|
findNode(id: string): Node;
|
|
162
|
+
/**
|
|
163
|
+
* 设置 Node 层上下方向预缓存条数,并刷新可见分组内的列渲染区间。
|
|
164
|
+
*/
|
|
165
|
+
setNodeCacheRange(backward: number, forward: number): void;
|
|
135
166
|
/**
|
|
136
167
|
* 获取分组渲染区间
|
|
137
168
|
*/
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { cancelAnimationFrame, requestAnimationFrame } from '@tarojs/runtime';
|
|
1
2
|
import { nextTick } from '@tarojs/taro';
|
|
2
3
|
import '../../utils/index.js';
|
|
3
4
|
import { StatefulEventBus } from './stateful-event-bus.js';
|
|
@@ -18,7 +19,7 @@ const RootEvents = {
|
|
|
18
19
|
*/
|
|
19
20
|
class Root extends StatefulEventBus {
|
|
20
21
|
constructor(props) {
|
|
21
|
-
const { id, cacheCount, lowerThresholdCount, upperThresholdCount } = props;
|
|
22
|
+
const { id, cacheCount, lowerThresholdCount, upperThresholdCount, skipContainerMeasure } = props;
|
|
22
23
|
super({
|
|
23
24
|
isScrolling: false,
|
|
24
25
|
scrollOffset: 0,
|
|
@@ -43,9 +44,17 @@ class Root extends StatefulEventBus {
|
|
|
43
44
|
*/
|
|
44
45
|
this.sections = [];
|
|
45
46
|
/**
|
|
46
|
-
* 设置预加载的 Item
|
|
47
|
+
* 设置预加载的 Item 条数(与 props.cacheCount 一致,收敛目标)。
|
|
47
48
|
*/
|
|
48
49
|
this.cacheCount = 1;
|
|
50
|
+
/**
|
|
51
|
+
* Node 层向上(列索引减小方向)预缓存条数,可与 cacheCount 不同(快速滑动单边放大)。
|
|
52
|
+
*/
|
|
53
|
+
this.nodeCacheBackward = 1;
|
|
54
|
+
/**
|
|
55
|
+
* Node 层向下(列索引增大方向)预缓存条数。
|
|
56
|
+
*/
|
|
57
|
+
this.nodeCacheForward = 1;
|
|
49
58
|
this.upperThresholdCount = 0;
|
|
50
59
|
this.lowerThresholdCount = 0;
|
|
51
60
|
/**
|
|
@@ -56,48 +65,56 @@ class Root extends StatefulEventBus {
|
|
|
56
65
|
* 触发滚动阈值对应的 scrollTop 值
|
|
57
66
|
*/
|
|
58
67
|
this.lowerThresholdScrollTop = Infinity;
|
|
68
|
+
/** scrollElement 模式下为 true,需布局全部 section 以展开完整高度供父容器滚动 */
|
|
69
|
+
this.skipContainerMeasure = false;
|
|
70
|
+
/** 当前是否处于触顶区域;初始为 true(起始在顶部),只有从 false→true 时才触发事件 */
|
|
71
|
+
this._inUpperZone = true;
|
|
72
|
+
/** 当前是否处于触底区域;初始为 false */
|
|
73
|
+
this._inLowerZone = false;
|
|
74
|
+
/** scrollHeight 更新防抖(raf),减轻 pushNodes 后测量前后的高度跳变 */
|
|
75
|
+
this._scrollHeightRafId = null;
|
|
59
76
|
Object.assign(this, {
|
|
60
77
|
id,
|
|
61
78
|
cacheCount,
|
|
62
79
|
lowerThresholdCount,
|
|
63
80
|
upperThresholdCount,
|
|
81
|
+
skipContainerMeasure: !!skipContainerMeasure,
|
|
64
82
|
});
|
|
83
|
+
this.nodeCacheBackward = cacheCount;
|
|
84
|
+
this.nodeCacheForward = cacheCount;
|
|
65
85
|
this.setupSubscriptions();
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
86
|
+
if (!skipContainerMeasure) {
|
|
87
|
+
getRectSizeSync(`#${id}`, 100).then(({ width = windowWidth, height = windowHeight }) => {
|
|
88
|
+
this.setStateIn('containerSize', {
|
|
89
|
+
width,
|
|
90
|
+
height,
|
|
91
|
+
});
|
|
70
92
|
});
|
|
71
|
-
}
|
|
93
|
+
}
|
|
72
94
|
this.renderInitialLayout();
|
|
73
95
|
}
|
|
74
96
|
/**
|
|
75
97
|
* 设置订阅事件
|
|
76
98
|
*/
|
|
77
99
|
setupSubscriptions() {
|
|
78
|
-
/**
|
|
79
|
-
* 滚动过程中计算渲染的分组区间
|
|
80
|
-
* 滚动过程中分组的最大高度会发生更新,可以在这时计算滚动高度
|
|
81
|
-
*/
|
|
82
|
-
this.sub('scrollOffset', () => {
|
|
83
|
-
this.setStateIn('renderRange', this.getSectionRenderRange());
|
|
84
|
-
this.handleReachThreshold();
|
|
85
|
-
if (this.getState().scrollDirection === 'forward') {
|
|
86
|
-
this.updateScrollHeight();
|
|
87
|
-
}
|
|
88
|
-
});
|
|
100
|
+
/** 滚动:先更新触底阈值,再判触顶/触底并更新分组与总高度,避免同一帧内沿用无效阈值。 */
|
|
89
101
|
this.sub('scrollOffset', () => {
|
|
90
102
|
const sectionSize = this.sections.length;
|
|
91
103
|
const lastSection = this.sections[sectionSize - 1];
|
|
92
|
-
|
|
93
|
-
if (lastSection.columnMap.every((column) => column[column.length - 1].getState().layouted)) {
|
|
104
|
+
if (lastSection === null || lastSection === void 0 ? void 0 : lastSection.columnMap.every((column) => { var _a; return (_a = column[column.length - 1]) === null || _a === void 0 ? void 0 : _a.getState().layouted; })) {
|
|
94
105
|
this.setLowerThresholdScrollTop();
|
|
95
106
|
}
|
|
107
|
+
this.setStateIn('renderRange', this.getSectionRenderRange());
|
|
108
|
+
this.handleReachThreshold();
|
|
109
|
+
this.updateScrollHeight();
|
|
96
110
|
});
|
|
97
111
|
this.sub(RootEvents.AllSectionsLayouted, () => {
|
|
112
|
+
this.updateScrollHeight();
|
|
98
113
|
this.setUpperThresholdScrollTop();
|
|
114
|
+
this.setLowerThresholdScrollTop();
|
|
99
115
|
});
|
|
100
116
|
this.sub(RootEvents.Resize, () => {
|
|
117
|
+
this.updateScrollHeight();
|
|
101
118
|
this.setUpperThresholdScrollTop();
|
|
102
119
|
this.setLowerThresholdScrollTop();
|
|
103
120
|
});
|
|
@@ -122,8 +139,10 @@ class Root extends StatefulEventBus {
|
|
|
122
139
|
const section = this.sections[i];
|
|
123
140
|
section.layoutedSignal.promise.then(() => {
|
|
124
141
|
this.setStateIn('renderRange', [0, i + 1 > sectionSize ? sectionSize - 1 : i + 1]);
|
|
125
|
-
//
|
|
126
|
-
|
|
142
|
+
// skipContainerMeasure(nestedScroll 模式):需布局全部 section,使 scrollHeight 展开供父容器滚动
|
|
143
|
+
// default 模式:容器可视区域已填满则提前终止,减少首屏渲染
|
|
144
|
+
if (!this.skipContainerMeasure &&
|
|
145
|
+
section.getState().scrollTop > this.getState().containerSize.height) {
|
|
127
146
|
this.pub(RootEvents.InitialRenderCompleted, section);
|
|
128
147
|
return;
|
|
129
148
|
}
|
|
@@ -189,8 +208,14 @@ class Root extends StatefulEventBus {
|
|
|
189
208
|
* 当距底部还有 lowerThresholdCount 个 FlowItem 时的 scrollTop 值
|
|
190
209
|
*/
|
|
191
210
|
setLowerThresholdScrollTop() {
|
|
192
|
-
|
|
193
|
-
|
|
211
|
+
// 与 setUpperThresholdScrollTop 一致:0 或 undefined 时用「内容底 - 容器高」作为触底阈值
|
|
212
|
+
if (!this.lowerThresholdCount) {
|
|
213
|
+
// 必须用 sectionRange 实时计算,避免依赖可能未更新的 scrollHeight 状态
|
|
214
|
+
const range = this.sectionRange;
|
|
215
|
+
const totalHeight = range.length > 0 ? range[range.length - 1][1] : 0;
|
|
216
|
+
// 触底判定:scrollOffset + containerSize.height >= lowerThresholdScrollTop
|
|
217
|
+
// 须存内容底边 totalHeight(H)。若误存 H-h,则顶部时 h 与 H-h 比较,当 2h>=H 会恒判为在触底区,误触 onScrollToLower。
|
|
218
|
+
this.lowerThresholdScrollTop = totalHeight;
|
|
194
219
|
return 0;
|
|
195
220
|
}
|
|
196
221
|
const sectionSize = this.sections.length;
|
|
@@ -238,20 +263,26 @@ class Root extends StatefulEventBus {
|
|
|
238
263
|
/**
|
|
239
264
|
* 处理滚动到阈值的情况
|
|
240
265
|
* 检测当前滚动位置是否达到了上下阈值,并触发相应的事件
|
|
266
|
+
* scrollElement 模式:scrollOffset 为内容内偏移(scrollTop - startOffset),upper/lowerThresholdScrollTop 基于本组件内容计算,触顶/触底以本 WaterFlow 内容为基准
|
|
241
267
|
*/
|
|
242
268
|
handleReachThreshold() {
|
|
243
|
-
const {
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
scrollOffset <= upperThresholdScrollTop) {
|
|
269
|
+
const { scrollOffset, containerSize } = this.getState();
|
|
270
|
+
const inUpper = this.upperThresholdScrollTop !== -Infinity && scrollOffset <= this.upperThresholdScrollTop;
|
|
271
|
+
const inLower = this.lowerThresholdScrollTop !== Infinity && scrollOffset + containerSize.height >= this.lowerThresholdScrollTop;
|
|
272
|
+
if (inUpper && !this._inUpperZone)
|
|
248
273
|
this.pub(RootEvents.ReachUpperThreshold);
|
|
249
|
-
|
|
250
|
-
if (scrollDirection === 'forward' &&
|
|
251
|
-
this.lowerThresholdCount !== Infinity &&
|
|
252
|
-
scrollOffset + containerSize.height >= this.lowerThresholdScrollTop) {
|
|
274
|
+
if (inLower && !this._inLowerZone)
|
|
253
275
|
this.pub(RootEvents.ReachLowerThreshold);
|
|
254
|
-
|
|
276
|
+
this._inUpperZone = inUpper;
|
|
277
|
+
this._inLowerZone = inLower;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* 列表追加并完成 finalize 后调用:重置触底边沿状态(_inLowerZone),
|
|
281
|
+
* 使用户仍在底部时下一次滚动能再次触发 onScrollToLower,而不必先上滑再下滑。
|
|
282
|
+
* 不在此处同步调用 handleReachThreshold,避免仍在底部时立刻连发触底(与误触区分)。
|
|
283
|
+
*/
|
|
284
|
+
resetLowerReachEdgeAfterContentChange() {
|
|
285
|
+
this._inLowerZone = false;
|
|
255
286
|
}
|
|
256
287
|
/**
|
|
257
288
|
* 容器的滚动上边界
|
|
@@ -273,21 +304,44 @@ class Root extends StatefulEventBus {
|
|
|
273
304
|
* @returns [number,number][]
|
|
274
305
|
*/
|
|
275
306
|
get sectionRange() {
|
|
307
|
+
var _a;
|
|
276
308
|
const length = this.sections.length;
|
|
277
309
|
if (length === 0)
|
|
278
310
|
return [];
|
|
279
311
|
const range = Array.from({ length }, () => [0, this.sections[0].maxColumnHeight]);
|
|
280
312
|
for (let i = 1; i < length; i++) {
|
|
281
313
|
const previous = range[i - 1];
|
|
282
|
-
|
|
314
|
+
const prevSection = this.sections[i - 1];
|
|
315
|
+
const gap = (_a = prevSection.rowGap) !== null && _a !== void 0 ? _a : 0;
|
|
316
|
+
range[i] = [previous[1] + gap, previous[1] + gap + this.sections[i].maxColumnHeight];
|
|
283
317
|
}
|
|
284
318
|
return range;
|
|
285
319
|
}
|
|
286
320
|
/**
|
|
287
|
-
*
|
|
321
|
+
* 更新总滚动高度(各 Section 累计)。
|
|
322
|
+
* @param immediate true 时跳过 raf 防抖(如 finalizePushNodesStateIfNeeded),避免高度滞后引起跳动
|
|
288
323
|
*/
|
|
289
|
-
updateScrollHeight() {
|
|
290
|
-
|
|
324
|
+
updateScrollHeight(immediate = false) {
|
|
325
|
+
const flush = () => {
|
|
326
|
+
var _a, _b;
|
|
327
|
+
const next = (_b = (_a = this.sectionRange[this.sectionRange.length - 1]) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : 0;
|
|
328
|
+
this.setStateIn('scrollHeight', next);
|
|
329
|
+
};
|
|
330
|
+
if (immediate) {
|
|
331
|
+
if (this._scrollHeightRafId != null) {
|
|
332
|
+
cancelAnimationFrame(this._scrollHeightRafId);
|
|
333
|
+
this._scrollHeightRafId = null;
|
|
334
|
+
}
|
|
335
|
+
flush();
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (this._scrollHeightRafId != null) {
|
|
339
|
+
cancelAnimationFrame(this._scrollHeightRafId);
|
|
340
|
+
}
|
|
341
|
+
this._scrollHeightRafId = requestAnimationFrame(() => {
|
|
342
|
+
this._scrollHeightRafId = null;
|
|
343
|
+
flush();
|
|
344
|
+
});
|
|
291
345
|
}
|
|
292
346
|
/**
|
|
293
347
|
* 注册分组
|
|
@@ -315,6 +369,23 @@ class Root extends StatefulEventBus {
|
|
|
315
369
|
findNode(id) {
|
|
316
370
|
return this.nodeMap.get(id);
|
|
317
371
|
}
|
|
372
|
+
/**
|
|
373
|
+
* 设置 Node 层上下方向预缓存条数,并刷新可见分组内的列渲染区间。
|
|
374
|
+
*/
|
|
375
|
+
setNodeCacheRange(backward, forward) {
|
|
376
|
+
const b = Math.max(0, Math.floor(backward));
|
|
377
|
+
const f = Math.max(0, Math.floor(forward));
|
|
378
|
+
if (this.nodeCacheBackward === b && this.nodeCacheForward === f) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
this.nodeCacheBackward = b;
|
|
382
|
+
this.nodeCacheForward = f;
|
|
383
|
+
for (const section of this.sections) {
|
|
384
|
+
if (section.isInRange) {
|
|
385
|
+
section.setStateIn('renderRange', section.getNodeRenderRange());
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
318
389
|
/**
|
|
319
390
|
* 获取分组渲染区间
|
|
320
391
|
*/
|
|
@@ -333,15 +404,16 @@ class Root extends StatefulEventBus {
|
|
|
333
404
|
if (result[1] === -Infinity) {
|
|
334
405
|
result[1] = this.sections.length - 1;
|
|
335
406
|
}
|
|
336
|
-
const scrollDirection = this.getState().scrollDirection;
|
|
337
407
|
const [backwardCache, forwardCache] = this.calcCacheSection(result);
|
|
338
|
-
|
|
339
|
-
const
|
|
408
|
+
// 双向预缓存,避免反向滚动时出现空白(原逻辑仅在滚动方向缓存,反向时未预渲染)
|
|
409
|
+
const backwardDistance = backwardCache;
|
|
410
|
+
const forwardDistance = forwardCache;
|
|
340
411
|
const overscanBackward = result[0] - backwardDistance;
|
|
341
412
|
const overscanForward = result[1] + forwardDistance;
|
|
342
413
|
result[0] = overscanBackward < 0 ? 0 : overscanBackward;
|
|
343
414
|
result[1] = overscanForward > this.sections.length ? this.sections.length - 1 : overscanForward;
|
|
344
|
-
|
|
415
|
+
const prevRange = this.getState().renderRange;
|
|
416
|
+
return isSameRenderRange(result, prevRange) ? prevRange : result;
|
|
345
417
|
}
|
|
346
418
|
/**
|
|
347
419
|
* 计算预渲染的分组个数
|