@tarojs/components-advanced 4.2.1-beta.2 → 4.2.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 +0 -2
- package/dist/components/index.js.map +1 -1
- package/dist/components/list/index.d.ts +7 -64
- package/dist/components/list/index.js +162 -1081
- package/dist/components/list/index.js.map +1 -1
- 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 +11 -18
- 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 +2 -32
- package/dist/components/water-flow/node.d.ts +0 -3
- package/dist/components/water-flow/node.js +1 -34
- package/dist/components/water-flow/node.js.map +1 -1
- package/dist/components/water-flow/root.d.ts +4 -39
- package/dist/components/water-flow/root.js +44 -144
- package/dist/components/water-flow/root.js.map +1 -1
- package/dist/components/water-flow/section.d.ts +1 -11
- package/dist/components/water-flow/section.js +19 -81
- package/dist/components/water-flow/section.js.map +1 -1
- package/dist/components/water-flow/utils.d.ts +0 -4
- package/dist/components/water-flow/utils.js +1 -5
- package/dist/components/water-flow/utils.js.map +1 -1
- package/dist/components/water-flow/water-flow.d.ts +3 -2
- package/dist/components/water-flow/water-flow.js +36 -316
- package/dist/components/water-flow/water-flow.js.map +1 -1
- package/dist/index.js +0 -4
- package/dist/index.js.map +1 -1
- package/dist/utils/dom.d.ts +2 -2
- package/dist/utils/dom.js +6 -7
- package/dist/utils/dom.js.map +1 -1
- package/dist/utils/index.d.ts +0 -2
- package/dist/utils/index.js +0 -2
- package/dist/utils/index.js.map +1 -1
- package/package.json +8 -9
- package/dist/components/list/NoMore.d.ts +0 -30
- package/dist/components/list/NoMore.js +0 -10
- package/dist/components/list/NoMore.js.map +0 -1
- package/dist/components/list/hooks/useItemSizeCache.d.ts +0 -13
- package/dist/components/list/hooks/useItemSizeCache.js +0 -40
- package/dist/components/list/hooks/useItemSizeCache.js.map +0 -1
- package/dist/components/list/hooks/useListNestedScroll.d.ts +0 -18
- package/dist/components/list/hooks/useListNestedScroll.js +0 -61
- package/dist/components/list/hooks/useListNestedScroll.js.map +0 -1
- package/dist/components/list/hooks/useListScrollElementAttach.d.ts +0 -25
- package/dist/components/list/hooks/useListScrollElementAttach.js +0 -88
- package/dist/components/list/hooks/useListScrollElementAttach.js.map +0 -1
- package/dist/components/list/hooks/useListScrollElementAttachWeapp.d.ts +0 -15
- package/dist/components/list/hooks/useListScrollElementAttachWeapp.js +0 -135
- package/dist/components/list/hooks/useListScrollElementAttachWeapp.js.map +0 -1
- package/dist/components/list/hooks/useMeasureStartOffset.d.ts +0 -12
- package/dist/components/list/hooks/useMeasureStartOffset.js +0 -84
- package/dist/components/list/hooks/useMeasureStartOffset.js.map +0 -1
- package/dist/components/list/hooks/useMeasureStartOffsetWeapp.d.ts +0 -14
- package/dist/components/list/hooks/useMeasureStartOffsetWeapp.js +0 -87
- package/dist/components/list/hooks/useMeasureStartOffsetWeapp.js.map +0 -1
- package/dist/components/list/hooks/useRefresher.d.ts +0 -80
- package/dist/components/list/hooks/useRefresher.js +0 -561
- package/dist/components/list/hooks/useRefresher.js.map +0 -1
- package/dist/components/list/hooks/useResizeObserver.d.ts +0 -29
- package/dist/components/list/hooks/useResizeObserver.js +0 -153
- package/dist/components/list/hooks/useResizeObserver.js.map +0 -1
- package/dist/components/list/hooks/useScrollCorrection.d.ts +0 -19
- package/dist/components/list/hooks/useScrollCorrection.js +0 -74
- package/dist/components/list/hooks/useScrollCorrection.js.map +0 -1
- package/dist/components/list/hooks/useScrollParentAutoFind.d.ts +0 -20
- package/dist/components/list/hooks/useScrollParentAutoFind.js +0 -81
- package/dist/components/list/hooks/useScrollParentAutoFind.js.map +0 -1
- package/dist/components/list/utils.d.ts +0 -28
- package/dist/components/list/utils.js +0 -41
- package/dist/components/list/utils.js.map +0 -1
- package/dist/components/water-flow/water-flow-node-cache.d.ts +0 -24
- package/dist/components/water-flow/water-flow-node-cache.js +0 -161
- package/dist/components/water-flow/water-flow-node-cache.js.map +0 -1
- package/dist/utils/scrollElementContext.d.ts +0 -15
- package/dist/utils/scrollElementContext.js +0 -14
- package/dist/utils/scrollElementContext.js.map +0 -1
- package/dist/utils/scrollParent.d.ts +0 -33
- package/dist/utils/scrollParent.js +0 -88
- package/dist/utils/scrollParent.js.map +0 -1
- package/dist/utils/weapp-scope.d.ts +0 -7
- package/dist/utils/weapp-scope.js +0 -20
- package/dist/utils/weapp-scope.js.map +0 -1
|
@@ -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$, id])\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
|
|
3
|
+
export type { FlowSectionProps, WaterFlowProps } 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
|
|
3
|
+
import type { CSSProperties } 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'
|
|
9
|
+
export interface WaterFlowProps extends Omit<ScrollViewProps, 'cacheExtent' | 'upperThreshold' | 'lowerThreshold' | 'style'>, Pick<BaseProps, 'style'> {
|
|
10
10
|
/**
|
|
11
11
|
* 距顶部多少个FlowItem时,触发 scrolltoupper 事件
|
|
12
12
|
* @default 0
|
|
@@ -22,36 +22,6 @@ export interface WaterFlowProps extends Omit<ScrollViewProps, 'cacheExtent' | 'u
|
|
|
22
22
|
* @default 50
|
|
23
23
|
*/
|
|
24
24
|
cacheCount?: number;
|
|
25
|
-
/**
|
|
26
|
-
* 滚动事件。与内部虚拟列表滚动处理链式调用,不会覆盖触底/分页逻辑。
|
|
27
|
-
* 仅 default 模式(自带 ScrollView)时生效。
|
|
28
|
-
*/
|
|
29
|
-
onScroll?: ScrollViewProps['onScroll'];
|
|
30
|
-
/**
|
|
31
|
-
* 受控竖向滚动位置。仅传入有效 number 时下发给 ScrollView;
|
|
32
|
-
* undefined/null 表示取消受控(避免 H5 将 null 转为 0 导致归顶)。
|
|
33
|
-
*/
|
|
34
|
-
scrollTop?: number;
|
|
35
|
-
/**
|
|
36
|
-
* 受控横向滚动位置,语义同 scrollTop。
|
|
37
|
-
*/
|
|
38
|
-
scrollLeft?: number;
|
|
39
|
-
/** 是否嵌套模式,与 plato 对齐;true=使用父级滚动,需配合 scrollElement 或 Context;不传或 false=default */
|
|
40
|
-
nestedScroll?: boolean;
|
|
41
|
-
/** 自定义滚动容器 ref,nestedScroll 模式下从 props 或 Context 获取 */
|
|
42
|
-
scrollElement?: RefObject<HTMLElement | null>;
|
|
43
|
-
/** WaterFlow 内容在滚动容器中的起始偏移(上方有其他内容时使用) */
|
|
44
|
-
startOffset?: number;
|
|
45
|
-
/** 可视区高度,scrollElement 模式下可选,不传则从 scrollElement.clientHeight 获取 */
|
|
46
|
-
containerHeight?: number;
|
|
47
|
-
/** 瀑布流内容高度变化时回调,便于 List 动高联动(避免底部空白) */
|
|
48
|
-
onScrollHeightChange?: (height: number) => void;
|
|
49
|
-
/** scrollIntoView 滚动完成后回调,便于父组件清空 scrollIntoView 以支持重复点击同一目标 */
|
|
50
|
-
onScrollIntoViewComplete?: () => void;
|
|
51
|
-
}
|
|
52
|
-
/** WaterFlow ref 类型,current 指向内容容器,用于 IntersectionObserver root、SelectorQuery.in 等 */
|
|
53
|
-
export interface WaterFlowRef {
|
|
54
|
-
current: HTMLElement | null;
|
|
55
25
|
}
|
|
56
26
|
export interface FlowSectionProps extends BaseProps {
|
|
57
27
|
/**
|
|
@@ -29,8 +29,6 @@ export declare const NodeEvents: {
|
|
|
29
29
|
export declare class Node extends StatefulEventBus<NodeState> {
|
|
30
30
|
root: Root;
|
|
31
31
|
section: Section;
|
|
32
|
-
/** 小程序:测量用内层 View 的 DOM;H5:getBoundingClientRect 用 */
|
|
33
|
-
private _measureEl;
|
|
34
32
|
id: string;
|
|
35
33
|
/**
|
|
36
34
|
* 原始索引,即一维数组中的索引
|
|
@@ -45,7 +43,6 @@ export declare class Node extends StatefulEventBus<NodeState> {
|
|
|
45
43
|
*/
|
|
46
44
|
col: number;
|
|
47
45
|
constructor(root: Root, section: Section, props: NodeProps);
|
|
48
|
-
attachMeasureElement(el: HTMLElement | null): void;
|
|
49
46
|
private setupSubscriptions;
|
|
50
47
|
/**
|
|
51
48
|
* 测量节点的尺寸信息
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import '../../utils/index.js';
|
|
2
2
|
import { SectionEvents } from './section.js';
|
|
3
3
|
import { StatefulEventBus } from './stateful-event-bus.js';
|
|
4
|
-
import { isWeb, isWeapp } from './utils.js';
|
|
5
|
-
import { weappScope } from '../../utils/weapp-scope.js';
|
|
6
4
|
import { getRectSizeSync } from '../../utils/dom.js';
|
|
7
5
|
|
|
8
6
|
const NodeEvents = {
|
|
@@ -20,15 +18,10 @@ class Node extends StatefulEventBus {
|
|
|
20
18
|
});
|
|
21
19
|
this.root = root;
|
|
22
20
|
this.section = section;
|
|
23
|
-
/** 小程序:测量用内层 View 的 DOM;H5:getBoundingClientRect 用 */
|
|
24
|
-
this._measureEl = null;
|
|
25
21
|
const nodeId = `${root.id}-${section.id}-item-${childIndex}`;
|
|
26
22
|
Object.assign(this, { id: nodeId, childIndex, order, col });
|
|
27
23
|
this.setupSubscriptions();
|
|
28
24
|
}
|
|
29
|
-
attachMeasureElement(el) {
|
|
30
|
-
this._measureEl = el;
|
|
31
|
-
}
|
|
32
25
|
setupSubscriptions() {
|
|
33
26
|
this.sub('layouted', () => {
|
|
34
27
|
/**
|
|
@@ -63,33 +56,7 @@ class Node extends StatefulEventBus {
|
|
|
63
56
|
* 测量节点的尺寸信息
|
|
64
57
|
*/
|
|
65
58
|
async measure() {
|
|
66
|
-
|
|
67
|
-
let height;
|
|
68
|
-
if (isWeb() && this._measureEl) {
|
|
69
|
-
const r = this._measureEl.getBoundingClientRect();
|
|
70
|
-
width = r.width;
|
|
71
|
-
height = r.height;
|
|
72
|
-
}
|
|
73
|
-
else if (isWeapp && this._measureEl) {
|
|
74
|
-
const scope = weappScope({ current: this._measureEl });
|
|
75
|
-
const res = await getRectSizeSync(`#${this.id}`, 100, 3, scope);
|
|
76
|
-
width = res.width;
|
|
77
|
-
height = res.height;
|
|
78
|
-
}
|
|
79
|
-
else {
|
|
80
|
-
const res = await getRectSizeSync(`#${this.id}`, 100, 3);
|
|
81
|
-
width = res.width;
|
|
82
|
-
height = res.height;
|
|
83
|
-
}
|
|
84
|
-
if (typeof width !== 'number' ||
|
|
85
|
-
typeof height !== 'number' ||
|
|
86
|
-
!Number.isFinite(width) ||
|
|
87
|
-
!Number.isFinite(height) ||
|
|
88
|
-
width <= 0 ||
|
|
89
|
-
height <= 0) {
|
|
90
|
-
const s = this.getState();
|
|
91
|
-
return { width: s.width, height: s.height };
|
|
92
|
-
}
|
|
59
|
+
const { height, width } = await getRectSizeSync(`#${this.id}`, 100, 3);
|
|
93
60
|
this.setStateBatch({
|
|
94
61
|
width,
|
|
95
62
|
height,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.js","sources":["../../../src/components/water-flow/node.ts"],"sourcesContent":["import { getRectSizeSync
|
|
1
|
+
{"version":3,"file":"node.js","sources":["../../../src/components/water-flow/node.ts"],"sourcesContent":["import { getRectSizeSync } from '../../utils'\nimport { Root } from './root'\nimport { Section, SectionEvents } from './section'\nimport { StatefulEventBus } from './stateful-event-bus'\n\ninterface NodeProps {\n /**\n * 原始索引,即一维数组中的索引\n */\n childIndex: number\n /**\n * 在列里的顺序\n */\n order: number\n /**\n * 位于哪一列\n */\n col: number\n height: number\n}\n\ntype NodeState = {\n top: number\n width: number\n height: number\n layouted: boolean\n scrollTop: number\n};\n\nexport const NodeEvents = {\n Resize: Symbol.for('resize'),\n}\n\nexport class Node extends StatefulEventBus<NodeState> {\n id: string\n /**\n * 原始索引,即一维数组中的索引\n */\n childIndex: number\n /**\n * 在列里的顺序\n */\n order: number\n /**\n * 位于哪一列\n */\n col: number\n constructor(public root: Root, public section: Section, props: NodeProps) {\n const { height, childIndex, order, col } = props\n super({\n top: 0,\n width: 0,\n height,\n scrollTop: 0,\n layouted: false,\n })\n const nodeId = `${root.id}-${section.id}-item-${childIndex}`\n Object.assign(this, { id: nodeId, childIndex, order, col })\n this.setupSubscriptions()\n }\n\n private setupSubscriptions() {\n this.sub('layouted', () => {\n /**\n * 如果当前分组所有的节点都完成布局计算,那么向分组推送 `AllNodesLayouted` 事件,section会在这个时机做一些计算\n */\n if (\n [...this.section.nodes.values()].every(\n (node) => node.getState().layouted\n )\n ) {\n this.section.notify(SectionEvents.AllNodesLayouted)\n }\n })\n\n /**\n * 如果节点的尺寸发生了变化(这通常出现在节点内容包含网络数据的情况下,比如图片,这时要求用户调用 useFlowItemPositioner 返回的 resize 方法通知数据模型去重新计算布局)\n *\n * - 更新当前节点所在列之后的所有节点的位置信息\n *\n * - 通知 section 更新布局\n */\n this.sub(NodeEvents.Resize, async () => {\n const { width, height } = this.getState()\n const newSize = await this.measure()\n if (newSize.height === height && newSize.width === width) {\n return\n }\n this.updateBehindNodesPosition()\n this.section.pub(SectionEvents.Resize, {\n node: this,\n newSize,\n originalSize: { width, height },\n })\n })\n }\n\n /**\n * 测量节点的尺寸信息\n */\n public async measure() {\n const { height, width } = await getRectSizeSync(`#${this.id}`, 100, 3)\n this.setStateBatch({\n width,\n height,\n layouted: true,\n })\n return { width, height }\n }\n\n /**\n * 更新节点所在列后面的节点的位置\n */\n updateBehindNodesPosition() {\n const currentColumn = this.section.columnMap[this.col]\n let start = this.order + 1\n\n if (start > currentColumn.length - 1) {\n return\n }\n for (; start < currentColumn.length; start++) {\n const node = currentColumn[start]\n const previousNode = currentColumn[start - 1]\n const {\n top: previousNodeTop,\n height: previousNodeHeight,\n scrollTop: previousNodeScrollTop,\n } = previousNode.getState()\n const rowGap = this.section.rowGap\n node.setStateBatch({\n top: previousNodeTop + previousNodeHeight + rowGap,\n scrollTop: previousNodeScrollTop + previousNodeHeight + rowGap,\n })\n }\n }\n\n /**\n * 节点是否可见\n */\n get isInRange() {\n const { scrollBoundaryStart, scrollBoundaryEnd } = this.root\n const { height: nodeHeight, scrollTop: nodeScrollTop } = this.getState()\n return (\n nodeScrollTop < scrollBoundaryEnd &&\n nodeScrollTop + nodeHeight > scrollBoundaryStart\n )\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -2,10 +2,7 @@ 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'
|
|
6
|
-
/** scrollElement 模式下为 true,不测量自有容器;此时需布局全部 section 以展开完整高度 */
|
|
7
|
-
skipContainerMeasure?: boolean;
|
|
8
|
-
};
|
|
5
|
+
export type RootProps = Pick<WaterFlowProps, 'cacheCount' | 'lowerThresholdCount' | 'upperThresholdCount'> & Required<Pick<BaseProps, 'id'>>;
|
|
9
6
|
type RootState = {
|
|
10
7
|
/** 是否在滚动中 */
|
|
11
8
|
isScrolling: boolean;
|
|
@@ -55,17 +52,9 @@ export declare class Root extends StatefulEventBus<RootState, Events> {
|
|
|
55
52
|
*/
|
|
56
53
|
sections: Section[];
|
|
57
54
|
/**
|
|
58
|
-
* 设置预加载的 Item
|
|
55
|
+
* 设置预加载的 Item 条数。
|
|
59
56
|
*/
|
|
60
57
|
cacheCount: number;
|
|
61
|
-
/**
|
|
62
|
-
* Node 层向上(列索引减小方向)预缓存条数,可与 cacheCount 不同(快速滑动单边放大)。
|
|
63
|
-
*/
|
|
64
|
-
nodeCacheBackward: number;
|
|
65
|
-
/**
|
|
66
|
-
* Node 层向下(列索引增大方向)预缓存条数。
|
|
67
|
-
*/
|
|
68
|
-
nodeCacheForward: number;
|
|
69
58
|
upperThresholdCount: number;
|
|
70
59
|
lowerThresholdCount: number;
|
|
71
60
|
/**
|
|
@@ -76,19 +65,7 @@ export declare class Root extends StatefulEventBus<RootState, Events> {
|
|
|
76
65
|
* 触发滚动阈值对应的 scrollTop 值
|
|
77
66
|
*/
|
|
78
67
|
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;
|
|
87
68
|
constructor(props: RootProps);
|
|
88
|
-
/**
|
|
89
|
-
* 挂载后由 WaterFlow 调用:用当前根容器 DOM(与 #id 同节点或 ScrollView 外壳)测量 containerSize。
|
|
90
|
-
*/
|
|
91
|
-
measureContainerSize(measureEl: HTMLElement | null): Promise<void>;
|
|
92
69
|
/**
|
|
93
70
|
* 设置订阅事件
|
|
94
71
|
*/
|
|
@@ -117,15 +94,8 @@ export declare class Root extends StatefulEventBus<RootState, Events> {
|
|
|
117
94
|
/**
|
|
118
95
|
* 处理滚动到阈值的情况
|
|
119
96
|
* 检测当前滚动位置是否达到了上下阈值,并触发相应的事件
|
|
120
|
-
* scrollElement 模式:scrollOffset 为内容内偏移(scrollTop - startOffset),upper/lowerThresholdScrollTop 基于本组件内容计算,触顶/触底以本 WaterFlow 内容为基准
|
|
121
97
|
*/
|
|
122
98
|
private handleReachThreshold;
|
|
123
|
-
/**
|
|
124
|
-
* 列表追加并完成 finalize 后调用:重置触底边沿状态(_inLowerZone),
|
|
125
|
-
* 使用户仍在底部时下一次滚动能再次触发 onScrollToLower,而不必先上滑再下滑。
|
|
126
|
-
* 不在此处同步调用 handleReachThreshold,避免仍在底部时立刻连发触底(与误触区分)。
|
|
127
|
-
*/
|
|
128
|
-
resetLowerReachEdgeAfterContentChange(): void;
|
|
129
99
|
/**
|
|
130
100
|
* 容器的滚动上边界
|
|
131
101
|
*/
|
|
@@ -143,10 +113,9 @@ export declare class Root extends StatefulEventBus<RootState, Events> {
|
|
|
143
113
|
*/
|
|
144
114
|
get sectionRange(): number[][];
|
|
145
115
|
/**
|
|
146
|
-
*
|
|
147
|
-
* @param immediate true 时跳过 raf 防抖(如 finalizePushNodesStateIfNeeded),避免高度滞后引起跳动
|
|
116
|
+
* 计算滚动高度
|
|
148
117
|
*/
|
|
149
|
-
updateScrollHeight(
|
|
118
|
+
updateScrollHeight(): void;
|
|
150
119
|
/**
|
|
151
120
|
* 注册分组
|
|
152
121
|
*/
|
|
@@ -163,10 +132,6 @@ export declare class Root extends StatefulEventBus<RootState, Events> {
|
|
|
163
132
|
* 查找节点
|
|
164
133
|
*/
|
|
165
134
|
findNode(id: string): Node;
|
|
166
|
-
/**
|
|
167
|
-
* 设置 Node 层上下方向预缓存条数,并刷新可见分组内的列渲染区间。
|
|
168
|
-
*/
|
|
169
|
-
setNodeCacheRange(backward: number, forward: number): void;
|
|
170
135
|
/**
|
|
171
136
|
* 获取分组渲染区间
|
|
172
137
|
*/
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { cancelAnimationFrame, requestAnimationFrame } from '@tarojs/runtime';
|
|
2
1
|
import { nextTick } from '@tarojs/taro';
|
|
3
2
|
import '../../utils/index.js';
|
|
4
3
|
import { StatefulEventBus } from './stateful-event-bus.js';
|
|
5
|
-
import { getSysInfo,
|
|
6
|
-
import { weappScope } from '../../utils/weapp-scope.js';
|
|
4
|
+
import { getSysInfo, isSameRenderRange } from './utils.js';
|
|
7
5
|
import { getRectSizeSync } from '../../utils/dom.js';
|
|
8
6
|
|
|
9
7
|
/* eslint-disable no-labels */
|
|
@@ -20,7 +18,7 @@ const RootEvents = {
|
|
|
20
18
|
*/
|
|
21
19
|
class Root extends StatefulEventBus {
|
|
22
20
|
constructor(props) {
|
|
23
|
-
const { id, cacheCount, lowerThresholdCount, upperThresholdCount
|
|
21
|
+
const { id, cacheCount, lowerThresholdCount, upperThresholdCount } = props;
|
|
24
22
|
super({
|
|
25
23
|
isScrolling: false,
|
|
26
24
|
scrollOffset: 0,
|
|
@@ -45,17 +43,9 @@ class Root extends StatefulEventBus {
|
|
|
45
43
|
*/
|
|
46
44
|
this.sections = [];
|
|
47
45
|
/**
|
|
48
|
-
* 设置预加载的 Item
|
|
46
|
+
* 设置预加载的 Item 条数。
|
|
49
47
|
*/
|
|
50
48
|
this.cacheCount = 1;
|
|
51
|
-
/**
|
|
52
|
-
* Node 层向上(列索引减小方向)预缓存条数,可与 cacheCount 不同(快速滑动单边放大)。
|
|
53
|
-
*/
|
|
54
|
-
this.nodeCacheBackward = 1;
|
|
55
|
-
/**
|
|
56
|
-
* Node 层向下(列索引增大方向)预缓存条数。
|
|
57
|
-
*/
|
|
58
|
-
this.nodeCacheForward = 1;
|
|
59
49
|
this.upperThresholdCount = 0;
|
|
60
50
|
this.lowerThresholdCount = 0;
|
|
61
51
|
/**
|
|
@@ -66,83 +56,48 @@ class Root extends StatefulEventBus {
|
|
|
66
56
|
* 触发滚动阈值对应的 scrollTop 值
|
|
67
57
|
*/
|
|
68
58
|
this.lowerThresholdScrollTop = Infinity;
|
|
69
|
-
/** scrollElement 模式下为 true,需布局全部 section 以展开完整高度供父容器滚动 */
|
|
70
|
-
this.skipContainerMeasure = false;
|
|
71
|
-
/** 当前是否处于触顶区域;初始为 true(起始在顶部),只有从 false→true 时才触发事件 */
|
|
72
|
-
this._inUpperZone = true;
|
|
73
|
-
/** 当前是否处于触底区域;初始为 false */
|
|
74
|
-
this._inLowerZone = false;
|
|
75
|
-
/** scrollHeight 更新防抖(raf),减轻 pushNodes 后测量前后的高度跳变 */
|
|
76
|
-
this._scrollHeightRafId = null;
|
|
77
59
|
Object.assign(this, {
|
|
78
60
|
id,
|
|
79
61
|
cacheCount,
|
|
80
62
|
lowerThresholdCount,
|
|
81
63
|
upperThresholdCount,
|
|
82
|
-
skipContainerMeasure: !!skipContainerMeasure,
|
|
83
64
|
});
|
|
84
|
-
this.nodeCacheBackward = cacheCount;
|
|
85
|
-
this.nodeCacheForward = cacheCount;
|
|
86
65
|
this.setupSubscriptions();
|
|
66
|
+
getRectSizeSync(`#${id}`, 100).then(({ width = windowWidth, height = windowHeight }) => {
|
|
67
|
+
this.setStateIn('containerSize', {
|
|
68
|
+
width,
|
|
69
|
+
height,
|
|
70
|
+
});
|
|
71
|
+
});
|
|
87
72
|
this.renderInitialLayout();
|
|
88
73
|
}
|
|
89
|
-
/**
|
|
90
|
-
* 挂载后由 WaterFlow 调用:用当前根容器 DOM(与 #id 同节点或 ScrollView 外壳)测量 containerSize。
|
|
91
|
-
*/
|
|
92
|
-
async measureContainerSize(measureEl) {
|
|
93
|
-
var _a, _b, _c, _d;
|
|
94
|
-
if (this.skipContainerMeasure)
|
|
95
|
-
return;
|
|
96
|
-
const { windowWidth, windowHeight } = getSysInfo();
|
|
97
|
-
let width = windowWidth;
|
|
98
|
-
let height = windowHeight;
|
|
99
|
-
if (isH5 && measureEl && typeof measureEl.getBoundingClientRect === 'function') {
|
|
100
|
-
const r = measureEl.getBoundingClientRect();
|
|
101
|
-
width = r.width;
|
|
102
|
-
height = r.height;
|
|
103
|
-
}
|
|
104
|
-
else if (isWeapp && measureEl) {
|
|
105
|
-
const scope = weappScope({ current: measureEl });
|
|
106
|
-
const res = await getRectSizeSync(`#${this.id}`, 100, 5, scope);
|
|
107
|
-
width = (_a = res.width) !== null && _a !== void 0 ? _a : width;
|
|
108
|
-
height = (_b = res.height) !== null && _b !== void 0 ? _b : height;
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
const res = await getRectSizeSync(`#${this.id}`, 100, 5);
|
|
112
|
-
width = (_c = res.width) !== null && _c !== void 0 ? _c : width;
|
|
113
|
-
height = (_d = res.height) !== null && _d !== void 0 ? _d : height;
|
|
114
|
-
}
|
|
115
|
-
if (typeof width === 'number' &&
|
|
116
|
-
typeof height === 'number' &&
|
|
117
|
-
Number.isFinite(width) &&
|
|
118
|
-
Number.isFinite(height) &&
|
|
119
|
-
width > 0 &&
|
|
120
|
-
height > 0) {
|
|
121
|
-
this.setStateIn('containerSize', { width, height });
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
74
|
/**
|
|
125
75
|
* 设置订阅事件
|
|
126
76
|
*/
|
|
127
77
|
setupSubscriptions() {
|
|
128
|
-
/**
|
|
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
|
+
});
|
|
129
89
|
this.sub('scrollOffset', () => {
|
|
130
90
|
const sectionSize = this.sections.length;
|
|
131
91
|
const lastSection = this.sections[sectionSize - 1];
|
|
132
|
-
|
|
92
|
+
// 最后一个分组的每一列最后一行都已经完成了布局计算,那么这个时候的总高度应该是准确的
|
|
93
|
+
if (lastSection.columnMap.every((column) => column[column.length - 1].getState().layouted)) {
|
|
133
94
|
this.setLowerThresholdScrollTop();
|
|
134
95
|
}
|
|
135
|
-
this.setStateIn('renderRange', this.getSectionRenderRange());
|
|
136
|
-
this.handleReachThreshold();
|
|
137
|
-
this.updateScrollHeight();
|
|
138
96
|
});
|
|
139
97
|
this.sub(RootEvents.AllSectionsLayouted, () => {
|
|
140
|
-
this.updateScrollHeight();
|
|
141
98
|
this.setUpperThresholdScrollTop();
|
|
142
|
-
this.setLowerThresholdScrollTop();
|
|
143
99
|
});
|
|
144
100
|
this.sub(RootEvents.Resize, () => {
|
|
145
|
-
this.updateScrollHeight();
|
|
146
101
|
this.setUpperThresholdScrollTop();
|
|
147
102
|
this.setLowerThresholdScrollTop();
|
|
148
103
|
});
|
|
@@ -167,10 +122,8 @@ class Root extends StatefulEventBus {
|
|
|
167
122
|
const section = this.sections[i];
|
|
168
123
|
section.layoutedSignal.promise.then(() => {
|
|
169
124
|
this.setStateIn('renderRange', [0, i + 1 > sectionSize ? sectionSize - 1 : i + 1]);
|
|
170
|
-
//
|
|
171
|
-
|
|
172
|
-
if (!this.skipContainerMeasure &&
|
|
173
|
-
section.getState().scrollTop > this.getState().containerSize.height) {
|
|
125
|
+
// 容器可视区域已经填满了,没必要再继续
|
|
126
|
+
if (section.getState().scrollTop > this.getState().containerSize.height) {
|
|
174
127
|
this.pub(RootEvents.InitialRenderCompleted, section);
|
|
175
128
|
return;
|
|
176
129
|
}
|
|
@@ -236,14 +189,8 @@ class Root extends StatefulEventBus {
|
|
|
236
189
|
* 当距底部还有 lowerThresholdCount 个 FlowItem 时的 scrollTop 值
|
|
237
190
|
*/
|
|
238
191
|
setLowerThresholdScrollTop() {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
// 必须用 sectionRange 实时计算,避免依赖可能未更新的 scrollHeight 状态
|
|
242
|
-
const range = this.sectionRange;
|
|
243
|
-
const totalHeight = range.length > 0 ? range[range.length - 1][1] : 0;
|
|
244
|
-
// 触底判定:scrollOffset + containerSize.height >= lowerThresholdScrollTop
|
|
245
|
-
// 须存内容底边 totalHeight(H)。若误存 H-h,则顶部时 h 与 H-h 比较,当 2h>=H 会恒判为在触底区,误触 onScrollToLower。
|
|
246
|
-
this.lowerThresholdScrollTop = totalHeight;
|
|
192
|
+
if (this.lowerThresholdCount === 0) {
|
|
193
|
+
this.lowerThresholdScrollTop = this.getState().scrollHeight - this.getState().containerSize.height;
|
|
247
194
|
return 0;
|
|
248
195
|
}
|
|
249
196
|
const sectionSize = this.sections.length;
|
|
@@ -291,26 +238,20 @@ class Root extends StatefulEventBus {
|
|
|
291
238
|
/**
|
|
292
239
|
* 处理滚动到阈值的情况
|
|
293
240
|
* 检测当前滚动位置是否达到了上下阈值,并触发相应的事件
|
|
294
|
-
* scrollElement 模式:scrollOffset 为内容内偏移(scrollTop - startOffset),upper/lowerThresholdScrollTop 基于本组件内容计算,触顶/触底以本 WaterFlow 内容为基准
|
|
295
241
|
*/
|
|
296
242
|
handleReachThreshold() {
|
|
297
|
-
const {
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
|
|
243
|
+
const { upperThresholdScrollTop } = this;
|
|
244
|
+
const { scrollOffset, scrollDirection, containerSize } = this.getState();
|
|
245
|
+
if (scrollDirection === 'backward' &&
|
|
246
|
+
this.upperThresholdScrollTop !== -Infinity &&
|
|
247
|
+
scrollOffset <= upperThresholdScrollTop) {
|
|
301
248
|
this.pub(RootEvents.ReachUpperThreshold);
|
|
302
|
-
|
|
249
|
+
}
|
|
250
|
+
if (scrollDirection === 'forward' &&
|
|
251
|
+
this.lowerThresholdCount !== Infinity &&
|
|
252
|
+
scrollOffset + containerSize.height >= this.lowerThresholdScrollTop) {
|
|
303
253
|
this.pub(RootEvents.ReachLowerThreshold);
|
|
304
|
-
|
|
305
|
-
this._inLowerZone = inLower;
|
|
306
|
-
}
|
|
307
|
-
/**
|
|
308
|
-
* 列表追加并完成 finalize 后调用:重置触底边沿状态(_inLowerZone),
|
|
309
|
-
* 使用户仍在底部时下一次滚动能再次触发 onScrollToLower,而不必先上滑再下滑。
|
|
310
|
-
* 不在此处同步调用 handleReachThreshold,避免仍在底部时立刻连发触底(与误触区分)。
|
|
311
|
-
*/
|
|
312
|
-
resetLowerReachEdgeAfterContentChange() {
|
|
313
|
-
this._inLowerZone = false;
|
|
254
|
+
}
|
|
314
255
|
}
|
|
315
256
|
/**
|
|
316
257
|
* 容器的滚动上边界
|
|
@@ -332,44 +273,21 @@ class Root extends StatefulEventBus {
|
|
|
332
273
|
* @returns [number,number][]
|
|
333
274
|
*/
|
|
334
275
|
get sectionRange() {
|
|
335
|
-
var _a;
|
|
336
276
|
const length = this.sections.length;
|
|
337
277
|
if (length === 0)
|
|
338
278
|
return [];
|
|
339
279
|
const range = Array.from({ length }, () => [0, this.sections[0].maxColumnHeight]);
|
|
340
280
|
for (let i = 1; i < length; i++) {
|
|
341
281
|
const previous = range[i - 1];
|
|
342
|
-
|
|
343
|
-
const gap = (_a = prevSection.rowGap) !== null && _a !== void 0 ? _a : 0;
|
|
344
|
-
range[i] = [previous[1] + gap, previous[1] + gap + this.sections[i].maxColumnHeight];
|
|
282
|
+
range[i] = [previous[1], previous[1] + this.sections[i].maxColumnHeight];
|
|
345
283
|
}
|
|
346
284
|
return range;
|
|
347
285
|
}
|
|
348
286
|
/**
|
|
349
|
-
*
|
|
350
|
-
* @param immediate true 时跳过 raf 防抖(如 finalizePushNodesStateIfNeeded),避免高度滞后引起跳动
|
|
287
|
+
* 计算滚动高度
|
|
351
288
|
*/
|
|
352
|
-
updateScrollHeight(
|
|
353
|
-
|
|
354
|
-
var _a, _b;
|
|
355
|
-
const next = (_b = (_a = this.sectionRange[this.sectionRange.length - 1]) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : 0;
|
|
356
|
-
this.setStateIn('scrollHeight', next);
|
|
357
|
-
};
|
|
358
|
-
if (immediate) {
|
|
359
|
-
if (this._scrollHeightRafId != null) {
|
|
360
|
-
cancelAnimationFrame(this._scrollHeightRafId);
|
|
361
|
-
this._scrollHeightRafId = null;
|
|
362
|
-
}
|
|
363
|
-
flush();
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
if (this._scrollHeightRafId != null) {
|
|
367
|
-
cancelAnimationFrame(this._scrollHeightRafId);
|
|
368
|
-
}
|
|
369
|
-
this._scrollHeightRafId = requestAnimationFrame(() => {
|
|
370
|
-
this._scrollHeightRafId = null;
|
|
371
|
-
flush();
|
|
372
|
-
});
|
|
289
|
+
updateScrollHeight() {
|
|
290
|
+
this.setStateIn('scrollHeight', this.sectionRange[this.sectionRange.length - 1][1]);
|
|
373
291
|
}
|
|
374
292
|
/**
|
|
375
293
|
* 注册分组
|
|
@@ -397,23 +315,6 @@ class Root extends StatefulEventBus {
|
|
|
397
315
|
findNode(id) {
|
|
398
316
|
return this.nodeMap.get(id);
|
|
399
317
|
}
|
|
400
|
-
/**
|
|
401
|
-
* 设置 Node 层上下方向预缓存条数,并刷新可见分组内的列渲染区间。
|
|
402
|
-
*/
|
|
403
|
-
setNodeCacheRange(backward, forward) {
|
|
404
|
-
const b = Math.max(0, Math.floor(backward));
|
|
405
|
-
const f = Math.max(0, Math.floor(forward));
|
|
406
|
-
if (this.nodeCacheBackward === b && this.nodeCacheForward === f) {
|
|
407
|
-
return;
|
|
408
|
-
}
|
|
409
|
-
this.nodeCacheBackward = b;
|
|
410
|
-
this.nodeCacheForward = f;
|
|
411
|
-
for (const section of this.sections) {
|
|
412
|
-
if (section.isInRange) {
|
|
413
|
-
section.setStateIn('renderRange', section.getNodeRenderRange());
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
318
|
/**
|
|
418
319
|
* 获取分组渲染区间
|
|
419
320
|
*/
|
|
@@ -432,16 +333,15 @@ class Root extends StatefulEventBus {
|
|
|
432
333
|
if (result[1] === -Infinity) {
|
|
433
334
|
result[1] = this.sections.length - 1;
|
|
434
335
|
}
|
|
336
|
+
const scrollDirection = this.getState().scrollDirection;
|
|
435
337
|
const [backwardCache, forwardCache] = this.calcCacheSection(result);
|
|
436
|
-
|
|
437
|
-
const
|
|
438
|
-
const forwardDistance = forwardCache;
|
|
338
|
+
const backwardDistance = scrollDirection === 'backward' ? backwardCache : 0;
|
|
339
|
+
const forwardDistance = scrollDirection === 'forward' ? forwardCache : 0;
|
|
439
340
|
const overscanBackward = result[0] - backwardDistance;
|
|
440
341
|
const overscanForward = result[1] + forwardDistance;
|
|
441
342
|
result[0] = overscanBackward < 0 ? 0 : overscanBackward;
|
|
442
343
|
result[1] = overscanForward > this.sections.length ? this.sections.length - 1 : overscanForward;
|
|
443
|
-
|
|
444
|
-
return isSameRenderRange(result, prevRange) ? prevRange : result;
|
|
344
|
+
return isSameRenderRange(result, this.getState().renderRange) ? this.getState().renderRange : result;
|
|
445
345
|
}
|
|
446
346
|
/**
|
|
447
347
|
* 计算预渲染的分组个数
|