@tarojs/components-advanced 3.6.0-alpha.0
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/LICENSE +21 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/components/virtual-list/constants.d.ts +1 -0
- package/dist/components/virtual-list/constants.js +1 -0
- package/dist/components/virtual-list/dom-helpers.d.ts +1 -0
- package/dist/components/virtual-list/dom-helpers.js +38 -0
- package/dist/components/virtual-list/index.d.ts +189 -0
- package/dist/components/virtual-list/index.js +103 -0
- package/dist/components/virtual-list/list-set.d.ts +27 -0
- package/dist/components/virtual-list/list-set.js +227 -0
- package/dist/components/virtual-list/preset.d.ts +49 -0
- package/dist/components/virtual-list/preset.js +166 -0
- package/dist/components/virtual-list/react/index.d.ts +4 -0
- package/dist/components/virtual-list/react/index.js +67 -0
- package/dist/components/virtual-list/react/list.d.ts +39 -0
- package/dist/components/virtual-list/react/list.js +481 -0
- package/dist/components/virtual-list/react/validate.d.ts +3 -0
- package/dist/components/virtual-list/react/validate.js +69 -0
- package/dist/components/virtual-list/utils.d.ts +12 -0
- package/dist/components/virtual-list/utils.js +33 -0
- package/dist/components/virtual-list/vue/index.d.ts +17 -0
- package/dist/components/virtual-list/vue/index.js +8 -0
- package/dist/components/virtual-list/vue/list.d.ts +120 -0
- package/dist/components/virtual-list/vue/list.js +489 -0
- package/dist/components/virtual-list/vue/render.d.ts +3 -0
- package/dist/components/virtual-list/vue/render.js +24 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/utils/convert.d.ts +5 -0
- package/dist/utils/convert.js +16 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/lodash.d.ts +1 -0
- package/dist/utils/lodash.js +10 -0
- package/dist/utils/math.d.ts +2 -0
- package/dist/utils/math.js +18 -0
- package/dist/utils/timer.d.ts +6 -0
- package/dist/utils/timer.js +20 -0
- package/package.json +49 -0
- package/typings/global.d.ts +1 -0
- package/typings/vue.d.ts +7 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './virtual-list';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './virtual-list';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const IS_SCROLLING_DEBOUNCE_INTERVAL = 200;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export var IS_SCROLLING_DEBOUNCE_INTERVAL = 200;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getRTLOffsetType(recalculate?: boolean): any;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// TRICKY According to the spec, scrollLeft should be negative for RTL aligned elements.
|
|
2
|
+
// Chrome does not seem to adhere; its scrollLeft values are positive (measured relative to the left).
|
|
3
|
+
// Safari's elastic bounce makes detecting this even more complicated wrt potential false positives.
|
|
4
|
+
// The safest way to check this is to intentionally set a negative offset,
|
|
5
|
+
// and then verify that the subsequent "scroll" event matches the negative offset.
|
|
6
|
+
// If it does not match, then we can assume a non-standard RTL scroll implementation.
|
|
7
|
+
|
|
8
|
+
var cachedRTLResult = null;
|
|
9
|
+
export function getRTLOffsetType() {
|
|
10
|
+
var recalculate = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
|
11
|
+
if (cachedRTLResult === null || recalculate) {
|
|
12
|
+
var outerDiv = document.createElement('div');
|
|
13
|
+
var outerStyle = outerDiv.style;
|
|
14
|
+
outerStyle.width = '50px';
|
|
15
|
+
outerStyle.height = '50px';
|
|
16
|
+
outerStyle.overflow = 'scroll';
|
|
17
|
+
outerStyle.direction = 'rtl';
|
|
18
|
+
var innerDiv = document.createElement('div');
|
|
19
|
+
var innerStyle = innerDiv.style;
|
|
20
|
+
innerStyle.width = '100px';
|
|
21
|
+
innerStyle.height = '100px';
|
|
22
|
+
outerDiv.appendChild(innerDiv);
|
|
23
|
+
document.body.appendChild(outerDiv);
|
|
24
|
+
if (outerDiv.scrollLeft > 0) {
|
|
25
|
+
cachedRTLResult = 'positive-descending';
|
|
26
|
+
} else {
|
|
27
|
+
outerDiv.scrollLeft = 1;
|
|
28
|
+
if (outerDiv.scrollLeft === 0) {
|
|
29
|
+
cachedRTLResult = 'negative';
|
|
30
|
+
} else {
|
|
31
|
+
cachedRTLResult = 'positive-ascending';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
document.body.removeChild(outerDiv);
|
|
35
|
+
return cachedRTLResult;
|
|
36
|
+
}
|
|
37
|
+
return cachedRTLResult;
|
|
38
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import type { BaseEventOrig, BaseEventOrigFunction, ScrollViewProps, StandardProps } from '@tarojs/components';
|
|
2
|
+
import type { Component, ComponentType, CSSProperties, ReactNode } from 'react';
|
|
3
|
+
interface VirtualListProps extends Omit<StandardProps, 'children'> {
|
|
4
|
+
/** 列表的高度。 */
|
|
5
|
+
height: string | number;
|
|
6
|
+
/** 列表的宽度。 */
|
|
7
|
+
width: string | number;
|
|
8
|
+
/** 子组件 */
|
|
9
|
+
item: ComponentType<{
|
|
10
|
+
/** 组件 ID */
|
|
11
|
+
id: string;
|
|
12
|
+
/** 单项的样式,样式必须传入组件的 style 中 */
|
|
13
|
+
style?: CSSProperties;
|
|
14
|
+
/** 组件渲染的数据 */
|
|
15
|
+
data: any;
|
|
16
|
+
/** 组件渲染数据的索引 */
|
|
17
|
+
index: number;
|
|
18
|
+
/** 组件是否正在滚动,当 useIsScrolling 值为 true 时返回布尔值,否则返回 undefined */
|
|
19
|
+
isScrolling?: boolean;
|
|
20
|
+
}>;
|
|
21
|
+
/** 列表的长度 */
|
|
22
|
+
itemCount: number;
|
|
23
|
+
/** 渲染数据 */
|
|
24
|
+
itemData: any[];
|
|
25
|
+
/** 列表单项的大小,垂直滚动时为高度,水平滚动时为宽度。
|
|
26
|
+
*
|
|
27
|
+
* > Note:
|
|
28
|
+
* > - unlimitedSize 模式下如果传入函数,只会调用一次用于设置初始值
|
|
29
|
+
* > - 非 unlimitedSize 模式下如果传入函数,为避免性能问题,每个节点只会调用一次用于设置初始值
|
|
30
|
+
*/
|
|
31
|
+
itemSize: number | ((index?: number, itemData?: any[]) => number);
|
|
32
|
+
/** 解开高度列表单项大小限制,默认值使用: itemSize (请注意,初始高度与实际高度差异过大会导致隐患)。
|
|
33
|
+
*
|
|
34
|
+
* > Note: 通过 itemSize 设置的初始高度与子节点实际高度差异过大会导致隐患
|
|
35
|
+
* @default false
|
|
36
|
+
*/
|
|
37
|
+
unlimitedSize?: boolean;
|
|
38
|
+
/** 布局方式
|
|
39
|
+
* @default "absolute"
|
|
40
|
+
*/
|
|
41
|
+
position?: 'absolute' | 'relative';
|
|
42
|
+
/** 初始滚动偏移值,水平滚动影响 scrollLeft,垂直滚动影响 scrollTop。 */
|
|
43
|
+
initialScrollOffset?: number;
|
|
44
|
+
/** 列表内部容器组件类型。
|
|
45
|
+
* @default View
|
|
46
|
+
*/
|
|
47
|
+
innerElementType?: ComponentType;
|
|
48
|
+
/** 顶部区域 */
|
|
49
|
+
renderTop?: ReactNode;
|
|
50
|
+
/** 底部区域 */
|
|
51
|
+
renderBottom?: ReactNode;
|
|
52
|
+
/** 滚动方向。vertical 为垂直滚动,horizontal 为平行滚动。
|
|
53
|
+
* @default "vertical"
|
|
54
|
+
*/
|
|
55
|
+
layout?: 'vertical' | 'horizontal';
|
|
56
|
+
/** 列表滚动时调用函数 */
|
|
57
|
+
onScroll?: (event: VirtualListProps.IVirtualListEvent<VirtualListProps.IVirtualListEventDetail>) => void;
|
|
58
|
+
/** 调用平台原生的滚动监听函数。 */
|
|
59
|
+
onScrollNative?: BaseEventOrigFunction<ScrollViewProps.onScrollDetail>;
|
|
60
|
+
/** 在可视区域之外渲染的列表单项数量,值设置得越高,快速滚动时出现白屏的概率就越小,相应地,每次滚动的性能会变得越差。 */
|
|
61
|
+
overscanCount?: number;
|
|
62
|
+
/** 上下滚动预占位节点 */
|
|
63
|
+
placeholderCount?: number;
|
|
64
|
+
/** 是否注入 isScrolling 属性到 item 组件。这个参数一般用于实现滚动骨架屏(或其它 placeholder) 时比较有用。 */
|
|
65
|
+
useIsScrolling?: boolean;
|
|
66
|
+
style?: CSSProperties;
|
|
67
|
+
}
|
|
68
|
+
declare namespace VirtualListProps {
|
|
69
|
+
interface IVirtualListEventDetail extends ScrollViewProps.onScrollDetail {
|
|
70
|
+
scrollLeft: number;
|
|
71
|
+
scrollTop: number;
|
|
72
|
+
scrollHeight: number;
|
|
73
|
+
scrollWidth: number;
|
|
74
|
+
}
|
|
75
|
+
interface IVirtualListEvent<T extends ScrollViewProps.onScrollDetail = ScrollViewProps.onScrollDetail> extends BaseEventOrig {
|
|
76
|
+
/** 滚动方向,可能值为 forward 往前, backward 往后。 */
|
|
77
|
+
scrollDirection: 'forward' | 'backward';
|
|
78
|
+
/** 滚动距离 */
|
|
79
|
+
scrollOffset: number;
|
|
80
|
+
/** 当滚动是由 scrollTo() 或 scrollToItem() 调用时返回 true,否则返回 false */
|
|
81
|
+
scrollUpdateWasRequested: boolean;
|
|
82
|
+
/** 当前只有 React 支持 */
|
|
83
|
+
detail: T;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** 虚拟列表
|
|
87
|
+
* @classification viewContainer
|
|
88
|
+
* @supported weapp, swan, alipay, tt, qq, jd, h5
|
|
89
|
+
* @example_react
|
|
90
|
+
* ```tsx
|
|
91
|
+
* import VirtualList from `@tarojs/components/virtual-list`
|
|
92
|
+
*
|
|
93
|
+
* function buildData (offset = 0) {
|
|
94
|
+
* return Array(100).fill(0).map((_, i) => i + offset);
|
|
95
|
+
* }
|
|
96
|
+
*
|
|
97
|
+
* const Row = React.memo(({ id, index, style, data }) => {
|
|
98
|
+
* return (
|
|
99
|
+
* <View id={id} className={index % 2 ? 'ListItemOdd' : 'ListItemEven'} style={style}>
|
|
100
|
+
* Row {index}
|
|
101
|
+
* </View>
|
|
102
|
+
* );
|
|
103
|
+
* })
|
|
104
|
+
*
|
|
105
|
+
* export default class Index extends Component {
|
|
106
|
+
* state = {
|
|
107
|
+
* data: buildData(0),
|
|
108
|
+
* }
|
|
109
|
+
*
|
|
110
|
+
* render() {
|
|
111
|
+
* const { data } = this.state
|
|
112
|
+
* const dataLen = data.length
|
|
113
|
+
* return (
|
|
114
|
+
* <VirtualList
|
|
115
|
+
* height={500} // 列表的高度
|
|
116
|
+
* width='100%' // 列表的宽度
|
|
117
|
+
* item={Row} // 列表单项组件,这里只能传入一个组件
|
|
118
|
+
* itemData={data} // 渲染列表的数据
|
|
119
|
+
* itemCount={dataLen} // 渲染列表的长度
|
|
120
|
+
* itemSize={100} // 列表单项的高度
|
|
121
|
+
* />
|
|
122
|
+
* );
|
|
123
|
+
* }
|
|
124
|
+
* }
|
|
125
|
+
* ```
|
|
126
|
+
* @example_vue
|
|
127
|
+
* ```js
|
|
128
|
+
* // app.js 入口文件
|
|
129
|
+
* import Vue from 'vue'
|
|
130
|
+
* import VirtualList from '@tarojs/components/virtual-list'
|
|
131
|
+
*
|
|
132
|
+
* Vue.use(VirtualList)
|
|
133
|
+
* ```
|
|
134
|
+
* ```js
|
|
135
|
+
* <! –– row.vue 单项组件 ––>
|
|
136
|
+
* <template>
|
|
137
|
+
* <view
|
|
138
|
+
* :class="index % 2 ? 'ListItemOdd' : 'ListItemEven'"
|
|
139
|
+
* :style="css"
|
|
140
|
+
* >
|
|
141
|
+
* Row {{ index }} : {{ data[index] }}
|
|
142
|
+
* </view>
|
|
143
|
+
* </template>
|
|
144
|
+
*
|
|
145
|
+
* <script>
|
|
146
|
+
* export default {
|
|
147
|
+
* props: ['index', 'data', 'css']
|
|
148
|
+
* }
|
|
149
|
+
* </script>
|
|
150
|
+
* ```
|
|
151
|
+
* ```js
|
|
152
|
+
* <! –– page.vue 页面组件 ––>
|
|
153
|
+
* <template>
|
|
154
|
+
* <virtual-list
|
|
155
|
+
* wclass="List"
|
|
156
|
+
* :height="500"
|
|
157
|
+
* :item-data="list"
|
|
158
|
+
* :item-count="list.length"
|
|
159
|
+
* :item-size="100"
|
|
160
|
+
* :item="Row"
|
|
161
|
+
* width="100%"
|
|
162
|
+
* />
|
|
163
|
+
* </template>
|
|
164
|
+
*
|
|
165
|
+
* <script>
|
|
166
|
+
* import Row from './row.vue'
|
|
167
|
+
* import { markRaw } from 'vue'
|
|
168
|
+
*
|
|
169
|
+
* function buildData (offset = 0) {
|
|
170
|
+
* return Array(100).fill(0).map((_, i) => i + offset)
|
|
171
|
+
* }
|
|
172
|
+
*
|
|
173
|
+
* export default {
|
|
174
|
+
* data() {
|
|
175
|
+
* return {
|
|
176
|
+
* Row: markRaw(Row),
|
|
177
|
+
* list: buildData(0)
|
|
178
|
+
* }
|
|
179
|
+
* },
|
|
180
|
+
* }
|
|
181
|
+
* </script>
|
|
182
|
+
* ```
|
|
183
|
+
* @see https://taro-docs.jd.com/docs/virtual-list
|
|
184
|
+
*/
|
|
185
|
+
declare class VirtualListComponent extends Component<VirtualListProps> {
|
|
186
|
+
}
|
|
187
|
+
declare const VirtualList: typeof VirtualListComponent;
|
|
188
|
+
export { VirtualList, VirtualListProps };
|
|
189
|
+
export default VirtualList;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/** 虚拟列表
|
|
2
|
+
* @classification viewContainer
|
|
3
|
+
* @supported weapp, swan, alipay, tt, qq, jd, h5
|
|
4
|
+
* @example_react
|
|
5
|
+
* ```tsx
|
|
6
|
+
* import VirtualList from `@tarojs/components/virtual-list`
|
|
7
|
+
*
|
|
8
|
+
* function buildData (offset = 0) {
|
|
9
|
+
* return Array(100).fill(0).map((_, i) => i + offset);
|
|
10
|
+
* }
|
|
11
|
+
*
|
|
12
|
+
* const Row = React.memo(({ id, index, style, data }) => {
|
|
13
|
+
* return (
|
|
14
|
+
* <View id={id} className={index % 2 ? 'ListItemOdd' : 'ListItemEven'} style={style}>
|
|
15
|
+
* Row {index}
|
|
16
|
+
* </View>
|
|
17
|
+
* );
|
|
18
|
+
* })
|
|
19
|
+
*
|
|
20
|
+
* export default class Index extends Component {
|
|
21
|
+
* state = {
|
|
22
|
+
* data: buildData(0),
|
|
23
|
+
* }
|
|
24
|
+
*
|
|
25
|
+
* render() {
|
|
26
|
+
* const { data } = this.state
|
|
27
|
+
* const dataLen = data.length
|
|
28
|
+
* return (
|
|
29
|
+
* <VirtualList
|
|
30
|
+
* height={500} // 列表的高度
|
|
31
|
+
* width='100%' // 列表的宽度
|
|
32
|
+
* item={Row} // 列表单项组件,这里只能传入一个组件
|
|
33
|
+
* itemData={data} // 渲染列表的数据
|
|
34
|
+
* itemCount={dataLen} // 渲染列表的长度
|
|
35
|
+
* itemSize={100} // 列表单项的高度
|
|
36
|
+
* />
|
|
37
|
+
* );
|
|
38
|
+
* }
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
* @example_vue
|
|
42
|
+
* ```js
|
|
43
|
+
* // app.js 入口文件
|
|
44
|
+
* import Vue from 'vue'
|
|
45
|
+
* import VirtualList from '@tarojs/components/virtual-list'
|
|
46
|
+
*
|
|
47
|
+
* Vue.use(VirtualList)
|
|
48
|
+
* ```
|
|
49
|
+
* ```js
|
|
50
|
+
* <! –– row.vue 单项组件 ––>
|
|
51
|
+
* <template>
|
|
52
|
+
* <view
|
|
53
|
+
* :class="index % 2 ? 'ListItemOdd' : 'ListItemEven'"
|
|
54
|
+
* :style="css"
|
|
55
|
+
* >
|
|
56
|
+
* Row {{ index }} : {{ data[index] }}
|
|
57
|
+
* </view>
|
|
58
|
+
* </template>
|
|
59
|
+
*
|
|
60
|
+
* <script>
|
|
61
|
+
* export default {
|
|
62
|
+
* props: ['index', 'data', 'css']
|
|
63
|
+
* }
|
|
64
|
+
* </script>
|
|
65
|
+
* ```
|
|
66
|
+
* ```js
|
|
67
|
+
* <! –– page.vue 页面组件 ––>
|
|
68
|
+
* <template>
|
|
69
|
+
* <virtual-list
|
|
70
|
+
* wclass="List"
|
|
71
|
+
* :height="500"
|
|
72
|
+
* :item-data="list"
|
|
73
|
+
* :item-count="list.length"
|
|
74
|
+
* :item-size="100"
|
|
75
|
+
* :item="Row"
|
|
76
|
+
* width="100%"
|
|
77
|
+
* />
|
|
78
|
+
* </template>
|
|
79
|
+
*
|
|
80
|
+
* <script>
|
|
81
|
+
* import Row from './row.vue'
|
|
82
|
+
* import { markRaw } from 'vue'
|
|
83
|
+
*
|
|
84
|
+
* function buildData (offset = 0) {
|
|
85
|
+
* return Array(100).fill(0).map((_, i) => i + offset)
|
|
86
|
+
* }
|
|
87
|
+
*
|
|
88
|
+
* export default {
|
|
89
|
+
* data() {
|
|
90
|
+
* return {
|
|
91
|
+
* Row: markRaw(Row),
|
|
92
|
+
* list: buildData(0)
|
|
93
|
+
* }
|
|
94
|
+
* },
|
|
95
|
+
* }
|
|
96
|
+
* </script>
|
|
97
|
+
* ```
|
|
98
|
+
* @see https://taro-docs.jd.com/docs/virtual-list
|
|
99
|
+
*/
|
|
100
|
+
|
|
101
|
+
var VirtualList = process.env.FRAMEWORK === 'vue' || process.env.FRAMEWORK === 'vue3' ? require('./vue').default : require('./react').default;
|
|
102
|
+
export { VirtualList };
|
|
103
|
+
export default VirtualList;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { IProps } from './preset';
|
|
2
|
+
declare type TProps = Pick<IProps, 'width' | 'height' | 'unlimitedSize' | 'itemCount' | 'itemData' | 'itemSize' | 'overscanCount' | 'direction' | 'layout'>;
|
|
3
|
+
export default class ListSet {
|
|
4
|
+
protected props: TProps;
|
|
5
|
+
protected refresh?: TFunc;
|
|
6
|
+
list: number[];
|
|
7
|
+
mode?: 'normal' | 'function' | 'unlimited';
|
|
8
|
+
defaultSize: number;
|
|
9
|
+
constructor(props: TProps, refresh?: TFunc);
|
|
10
|
+
get isNormalMode(): boolean;
|
|
11
|
+
get isFunctionMode(): boolean;
|
|
12
|
+
get isUnlimitedMode(): boolean;
|
|
13
|
+
get length(): number;
|
|
14
|
+
get overscan(): number;
|
|
15
|
+
get wrapperSize(): number;
|
|
16
|
+
update(props: TProps): void;
|
|
17
|
+
setSize(i?: number, size?: number): void;
|
|
18
|
+
getSize(i?: number): number;
|
|
19
|
+
getOffsetSize(i?: number): number;
|
|
20
|
+
getSizeCount(offset?: number): number;
|
|
21
|
+
getStartIndex(scrollOffset?: number): number;
|
|
22
|
+
getStopIndex(wrapperSize?: number, scrollOffset?: number, startIndex?: number): number;
|
|
23
|
+
getRangeToRender(direction: 'forward' | 'backward', scrollOffset?: number, block?: boolean): number[];
|
|
24
|
+
getOffsetForIndexAndAlignment(index: number, align: string, scrollOffset: number): number;
|
|
25
|
+
compareSize(i?: number, size?: number): boolean;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
|
|
2
|
+
import _typeof from "@babel/runtime/helpers/esm/typeof";
|
|
3
|
+
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
|
|
4
|
+
import _createClass from "@babel/runtime/helpers/esm/createClass";
|
|
5
|
+
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
6
|
+
import { isFunction } from '@tarojs/shared';
|
|
7
|
+
import { isHorizontalFunc } from './utils';
|
|
8
|
+
var ListSet = /*#__PURE__*/function () {
|
|
9
|
+
function ListSet(props, refresh) {
|
|
10
|
+
_classCallCheck(this, ListSet);
|
|
11
|
+
this.props = props;
|
|
12
|
+
this.refresh = refresh;
|
|
13
|
+
_defineProperty(this, "list", []);
|
|
14
|
+
_defineProperty(this, "mode", void 0);
|
|
15
|
+
_defineProperty(this, "defaultSize", 1);
|
|
16
|
+
this.update(props);
|
|
17
|
+
|
|
18
|
+
// Note: 不考虑列表模式切换情况,可能会导致列表抖动体验过差
|
|
19
|
+
if (this.props.unlimitedSize) {
|
|
20
|
+
this.mode = 'unlimited';
|
|
21
|
+
} else if (isFunction(this.props.itemSize)) {
|
|
22
|
+
this.mode = 'function';
|
|
23
|
+
} else {
|
|
24
|
+
this.mode = 'normal';
|
|
25
|
+
}
|
|
26
|
+
this.defaultSize = (isFunction(this.props.itemSize) ? this.props.itemSize() : this.props.itemSize) || 1;
|
|
27
|
+
if (!this.isNormalMode) {
|
|
28
|
+
this.list = new Array(this.length).fill(-1);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
_createClass(ListSet, [{
|
|
32
|
+
key: "isNormalMode",
|
|
33
|
+
get: function get() {
|
|
34
|
+
return this.mode === 'normal';
|
|
35
|
+
}
|
|
36
|
+
}, {
|
|
37
|
+
key: "isFunctionMode",
|
|
38
|
+
get: function get() {
|
|
39
|
+
return this.mode === 'function';
|
|
40
|
+
}
|
|
41
|
+
}, {
|
|
42
|
+
key: "isUnlimitedMode",
|
|
43
|
+
get: function get() {
|
|
44
|
+
return this.mode === 'unlimited';
|
|
45
|
+
}
|
|
46
|
+
}, {
|
|
47
|
+
key: "length",
|
|
48
|
+
get: function get() {
|
|
49
|
+
return this.props.itemCount || 100;
|
|
50
|
+
}
|
|
51
|
+
}, {
|
|
52
|
+
key: "overscan",
|
|
53
|
+
get: function get() {
|
|
54
|
+
return this.props.overscanCount || 0;
|
|
55
|
+
}
|
|
56
|
+
}, {
|
|
57
|
+
key: "wrapperSize",
|
|
58
|
+
get: function get() {
|
|
59
|
+
var _this$props = this.props,
|
|
60
|
+
height = _this$props.height,
|
|
61
|
+
width = _this$props.width;
|
|
62
|
+
var isHorizontal = isHorizontalFunc(this.props);
|
|
63
|
+
var size = isHorizontal ? width : height;
|
|
64
|
+
if (process.env.NODE_ENV !== 'production' && typeof size !== 'number') {
|
|
65
|
+
console.warn("In mode ".concat(isHorizontal ? 'horizontal, width' : 'vertical, height', " parameter should be a number, but got ").concat(_typeof(size), "."));
|
|
66
|
+
}
|
|
67
|
+
return size;
|
|
68
|
+
}
|
|
69
|
+
}, {
|
|
70
|
+
key: "update",
|
|
71
|
+
value: function update(props) {
|
|
72
|
+
this.props = props;
|
|
73
|
+
if (this.length > this.list.length) {
|
|
74
|
+
var _this$list;
|
|
75
|
+
var arr = new Array(this.length - this.list.length).fill(-1);
|
|
76
|
+
(_this$list = this.list).push.apply(_this$list, _toConsumableArray(arr));
|
|
77
|
+
} else if (this.length < this.list.length) {
|
|
78
|
+
this.list.length = this.length;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}, {
|
|
82
|
+
key: "setSize",
|
|
83
|
+
value: function setSize() {
|
|
84
|
+
var _this$refresh;
|
|
85
|
+
var i = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
86
|
+
var size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.defaultSize;
|
|
87
|
+
this.list[i] = size;
|
|
88
|
+
(_this$refresh = this.refresh) === null || _this$refresh === void 0 ? void 0 : _this$refresh.call(this);
|
|
89
|
+
}
|
|
90
|
+
}, {
|
|
91
|
+
key: "getSize",
|
|
92
|
+
value: function getSize() {
|
|
93
|
+
var i = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
94
|
+
var size = this.props.itemSize;
|
|
95
|
+
var item = this.list[i];
|
|
96
|
+
if (item >= 0) return item;
|
|
97
|
+
if (this.isFunctionMode && isFunction(size)) {
|
|
98
|
+
var itemSize = size(i, this.props.itemData);
|
|
99
|
+
this.setSize(i, itemSize);
|
|
100
|
+
return itemSize;
|
|
101
|
+
}
|
|
102
|
+
return this.defaultSize;
|
|
103
|
+
}
|
|
104
|
+
}, {
|
|
105
|
+
key: "getOffsetSize",
|
|
106
|
+
value: function getOffsetSize() {
|
|
107
|
+
var _this = this;
|
|
108
|
+
var i = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.list.length;
|
|
109
|
+
if (this.isNormalMode) return i * this.defaultSize;
|
|
110
|
+
return this.list.slice(0, i).reduce(function (sum, _, idx) {
|
|
111
|
+
return sum + _this.getSize(idx);
|
|
112
|
+
}, 0);
|
|
113
|
+
}
|
|
114
|
+
}, {
|
|
115
|
+
key: "getSizeCount",
|
|
116
|
+
value: function getSizeCount() {
|
|
117
|
+
var _this2 = this;
|
|
118
|
+
var offset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
119
|
+
if (offset === 0) {
|
|
120
|
+
return 0;
|
|
121
|
+
}
|
|
122
|
+
// if (this.isNormalMode) {
|
|
123
|
+
// return Math.min(this.length - 1, Math.floor(offset / this.length))
|
|
124
|
+
// }
|
|
125
|
+
var offsetSize = 0;
|
|
126
|
+
var count = this.list.reduce(function (sum, _, idx) {
|
|
127
|
+
if (offsetSize < offset) {
|
|
128
|
+
offsetSize += _this2.getSize(idx);
|
|
129
|
+
return ++sum;
|
|
130
|
+
}
|
|
131
|
+
return sum;
|
|
132
|
+
}, 0);
|
|
133
|
+
return count - 1;
|
|
134
|
+
}
|
|
135
|
+
}, {
|
|
136
|
+
key: "getStartIndex",
|
|
137
|
+
value: function getStartIndex() {
|
|
138
|
+
var scrollOffset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
139
|
+
return Math.max(0, this.getSizeCount(scrollOffset) - 1);
|
|
140
|
+
}
|
|
141
|
+
}, {
|
|
142
|
+
key: "getStopIndex",
|
|
143
|
+
value: function getStopIndex() {
|
|
144
|
+
var wrapperSize = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
145
|
+
var scrollOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
146
|
+
var startIndex = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
|
|
147
|
+
// const visibleOffset = this.getOffsetSize(startIndex)
|
|
148
|
+
// if (this.isNormalMode) {
|
|
149
|
+
// const numVisibleItems = Math.ceil((wrapperSize + scrollOffset - visibleOffset) / this.length)
|
|
150
|
+
// /** -1 is because stop index is inclusive */
|
|
151
|
+
// return Math.max(startIndex, Math.min(this.length - 1, startIndex + numVisibleItems - 1))
|
|
152
|
+
// }
|
|
153
|
+
return Math.max(startIndex, Math.min(this.length - 1, this.getSizeCount(wrapperSize + scrollOffset)));
|
|
154
|
+
}
|
|
155
|
+
}, {
|
|
156
|
+
key: "getRangeToRender",
|
|
157
|
+
value: function getRangeToRender(direction) {
|
|
158
|
+
var scrollOffset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
159
|
+
var block = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
160
|
+
if (this.length === 0) {
|
|
161
|
+
return [0, 0, 0, 0];
|
|
162
|
+
}
|
|
163
|
+
var wrapperSize = this.wrapperSize;
|
|
164
|
+
var startIndex = this.getStartIndex(scrollOffset);
|
|
165
|
+
var stopIndex = this.getStopIndex(wrapperSize, scrollOffset, startIndex);
|
|
166
|
+
|
|
167
|
+
// Overscan by one item in each direction so that tab/focus works. If there isn't at least one extra item, tab loops back around.
|
|
168
|
+
var overscanBackward = !block || direction === 'backward' ? Math.max(1, this.overscan) : 1;
|
|
169
|
+
var overscanForward = !block || direction === 'forward' ? Math.max(1, this.overscan) : 1;
|
|
170
|
+
return [Math.max(0, startIndex - overscanBackward), Math.max(0, Math.min(this.length - 1, stopIndex + overscanForward)), startIndex, stopIndex];
|
|
171
|
+
}
|
|
172
|
+
}, {
|
|
173
|
+
key: "getOffsetForIndexAndAlignment",
|
|
174
|
+
value: function getOffsetForIndexAndAlignment(index, align, scrollOffset) {
|
|
175
|
+
var wrapperSize = this.wrapperSize;
|
|
176
|
+
var itemSize = this.getSize(index);
|
|
177
|
+
var lastItemOffset = Math.max(0, this.getOffsetSize(this.props.itemCount) - wrapperSize);
|
|
178
|
+
var maxOffset = Math.min(lastItemOffset, this.getOffsetSize(index));
|
|
179
|
+
var minOffset = Math.max(0, this.getOffsetSize(index) - wrapperSize + itemSize);
|
|
180
|
+
if (align === 'smart') {
|
|
181
|
+
if (scrollOffset >= minOffset - wrapperSize && scrollOffset <= maxOffset + wrapperSize) {
|
|
182
|
+
align = 'auto';
|
|
183
|
+
} else {
|
|
184
|
+
align = 'center';
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
switch (align) {
|
|
188
|
+
case 'start':
|
|
189
|
+
return maxOffset;
|
|
190
|
+
case 'end':
|
|
191
|
+
return minOffset;
|
|
192
|
+
case 'center':
|
|
193
|
+
{
|
|
194
|
+
// "Centered" offset is usually the average of the min and max.
|
|
195
|
+
// But near the edges of the list, this doesn't hold true.
|
|
196
|
+
var middleOffset = Math.round(minOffset + (maxOffset - minOffset) / 2);
|
|
197
|
+
if (middleOffset < Math.ceil(wrapperSize / 2)) {
|
|
198
|
+
return 0; // near the beginning
|
|
199
|
+
} else if (middleOffset > lastItemOffset + Math.floor(wrapperSize / 2)) {
|
|
200
|
+
return lastItemOffset; // near the end
|
|
201
|
+
} else {
|
|
202
|
+
return middleOffset;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
case 'auto':
|
|
206
|
+
default:
|
|
207
|
+
if (scrollOffset >= minOffset && scrollOffset <= maxOffset) {
|
|
208
|
+
return scrollOffset;
|
|
209
|
+
} else if (scrollOffset < minOffset) {
|
|
210
|
+
return minOffset;
|
|
211
|
+
} else {
|
|
212
|
+
return maxOffset;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}, {
|
|
217
|
+
key: "compareSize",
|
|
218
|
+
value: function compareSize() {
|
|
219
|
+
var i = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
|
220
|
+
var size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
221
|
+
if (this.isNormalMode) return true;
|
|
222
|
+
return this.getSize(i) === size;
|
|
223
|
+
}
|
|
224
|
+
}]);
|
|
225
|
+
return ListSet;
|
|
226
|
+
}();
|
|
227
|
+
export { ListSet as default };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import ListSet from './list-set';
|
|
3
|
+
import { defaultItemKey } from './utils';
|
|
4
|
+
import type { VirtualListProps } from './';
|
|
5
|
+
export interface IProps extends Partial<VirtualListProps> {
|
|
6
|
+
children?: VirtualListProps['item'];
|
|
7
|
+
direction?: 'ltr' | 'rtl' | 'horizontal' | 'vertical';
|
|
8
|
+
itemKey?: typeof defaultItemKey;
|
|
9
|
+
itemTagName?: string;
|
|
10
|
+
innerTagName?: string;
|
|
11
|
+
outerTagName?: string;
|
|
12
|
+
itemElementType?: React.ComponentType | string;
|
|
13
|
+
outerElementType?: React.ComponentType | string;
|
|
14
|
+
innerRef?: React.Ref<HTMLElement> | string;
|
|
15
|
+
outerRef?: React.Ref<HTMLElement> | string;
|
|
16
|
+
onItemsRendered?: TFunc;
|
|
17
|
+
shouldResetStyleCacheOnItemSizeChange?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export default class Preset {
|
|
20
|
+
protected props: IProps;
|
|
21
|
+
protected refresh?: TFunc;
|
|
22
|
+
itemList: ListSet;
|
|
23
|
+
constructor(props: IProps, refresh?: TFunc);
|
|
24
|
+
wrapperField: {
|
|
25
|
+
scrollLeft: number;
|
|
26
|
+
scrollTop: number;
|
|
27
|
+
scrollHeight: number;
|
|
28
|
+
scrollWidth: number;
|
|
29
|
+
clientHeight: number;
|
|
30
|
+
clientWidth: number;
|
|
31
|
+
diffOffset: number;
|
|
32
|
+
};
|
|
33
|
+
diffList: number[];
|
|
34
|
+
init(props: IProps): void;
|
|
35
|
+
update(props: IProps): void;
|
|
36
|
+
get id(): string;
|
|
37
|
+
get isHorizontal(): boolean;
|
|
38
|
+
get isRtl(): boolean;
|
|
39
|
+
get isRelative(): boolean;
|
|
40
|
+
get placeholderCount(): number;
|
|
41
|
+
get outerTagName(): string | import("react").ComponentType<{}>;
|
|
42
|
+
get innerTagName(): string | import("react").ComponentType<{}>;
|
|
43
|
+
get itemTagName(): string | import("react").ComponentType<{}>;
|
|
44
|
+
get field(): Record<string, number>;
|
|
45
|
+
set field(o: Record<string, number>);
|
|
46
|
+
isShaking(diff?: number): boolean;
|
|
47
|
+
getItemStyleCache: import("memoize-one").MemoizedFn<(_itemSize?: IProps['itemSize'] | false, _layout?: IProps['layout'] | false, _direction?: IProps['direction'] | false) => {}>;
|
|
48
|
+
getItemStyle(index: number): any;
|
|
49
|
+
}
|