@tarojs/components-react 4.2.1-beta.2 → 4.2.1-beta.3
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/image/index.js +3 -5
- package/dist/components/image/index.js.map +1 -1
- package/dist/components/picker/index.js +38 -110
- package/dist/components/picker/index.js.map +1 -1
- package/dist/components/picker/picker-group.js +127 -477
- package/dist/components/picker/picker-group.js.map +1 -1
- package/dist/components/refresher/index.js +5 -5
- package/dist/components/refresher/index.js.map +1 -1
- package/dist/components/scroll-view/index.js +36 -80
- package/dist/components/scroll-view/index.js.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.js +2 -6
- package/dist/index.js.map +1 -1
- package/dist/original/components/image/index.js +3 -5
- package/dist/original/components/image/index.js.map +1 -1
- package/dist/original/components/image/style/index.scss +1 -5
- package/dist/original/components/picker/index.js +38 -110
- package/dist/original/components/picker/index.js.map +1 -1
- package/dist/original/components/picker/picker-group.js +127 -477
- package/dist/original/components/picker/picker-group.js.map +1 -1
- package/dist/original/components/picker/style/index.scss +8 -9
- package/dist/original/components/refresher/index.js +5 -5
- package/dist/original/components/refresher/index.js.map +1 -1
- package/dist/original/components/scroll-view/index.js +36 -80
- package/dist/original/components/scroll-view/index.js.map +1 -1
- package/dist/original/index.js +2 -6
- package/dist/original/index.js.map +1 -1
- package/dist/solid/components/image/index.js +3 -5
- package/dist/solid/components/image/index.js.map +1 -1
- package/dist/solid/components/picker/index.js +45 -121
- package/dist/solid/components/picker/index.js.map +1 -1
- package/dist/solid/components/picker/picker-group.js +151 -500
- package/dist/solid/components/picker/picker-group.js.map +1 -1
- package/dist/solid/components/refresher/index.js +5 -5
- package/dist/solid/components/refresher/index.js.map +1 -1
- package/dist/solid/components/scroll-view/index.js +40 -84
- package/dist/solid/components/scroll-view/index.js.map +1 -1
- package/dist/solid/index.css +1 -1
- package/dist/solid/index.js +1 -1
- package/package.json +6 -8
- package/dist/components/map/MapContext.js +0 -628
- package/dist/components/map/MapContext.js.map +0 -1
- package/dist/components/map/MapCustomCallout.js +0 -91
- package/dist/components/map/MapCustomCallout.js.map +0 -1
- package/dist/components/map/common.js +0 -4
- package/dist/components/map/common.js.map +0 -1
- package/dist/components/map/createMapContext.js +0 -34
- package/dist/components/map/createMapContext.js.map +0 -1
- package/dist/components/map/handler.js +0 -50
- package/dist/components/map/handler.js.map +0 -1
- package/dist/components/map/index.js +0 -329
- package/dist/components/map/index.js.map +0 -1
- package/dist/components/switch/index.js +0 -125
- package/dist/components/switch/index.js.map +0 -1
- package/dist/components/switch/style/index.scss.js +0 -4
- package/dist/components/switch/style/index.scss.js.map +0 -1
- package/dist/contexts/ScrollElementContext.js +0 -6
- package/dist/contexts/ScrollElementContext.js.map +0 -1
- package/dist/original/components/map/MapContext.js +0 -628
- package/dist/original/components/map/MapContext.js.map +0 -1
- package/dist/original/components/map/MapCustomCallout.js +0 -91
- package/dist/original/components/map/MapCustomCallout.js.map +0 -1
- package/dist/original/components/map/common.js +0 -4
- package/dist/original/components/map/common.js.map +0 -1
- package/dist/original/components/map/createMapContext.js +0 -34
- package/dist/original/components/map/createMapContext.js.map +0 -1
- package/dist/original/components/map/handler.js +0 -50
- package/dist/original/components/map/handler.js.map +0 -1
- package/dist/original/components/map/index.js +0 -329
- package/dist/original/components/map/index.js.map +0 -1
- package/dist/original/components/switch/index.js +0 -125
- package/dist/original/components/switch/index.js.map +0 -1
- package/dist/original/components/switch/style/index.scss +0 -35
- package/dist/original/contexts/ScrollElementContext.js +0 -6
- package/dist/original/contexts/ScrollElementContext.js.map +0 -1
- package/dist/solid/contexts/ScrollElementContext.js +0 -6
- package/dist/solid/contexts/ScrollElementContext.js.map +0 -1
|
@@ -3,32 +3,6 @@ import Taro from '@tarojs/taro';
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
5
|
|
|
6
|
-
function requestAccessibilityFocusOnView(node) {
|
|
7
|
-
if (node == null) return;
|
|
8
|
-
const fn = Taro.setAccessibilityFocus;
|
|
9
|
-
if (typeof fn !== 'function') return;
|
|
10
|
-
fn({
|
|
11
|
-
viewRef: {
|
|
12
|
-
current: node
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
/** 部分端同 id 连续 scrollIntoView 不生效:先清空再在下一宏任务设回目标 id */
|
|
17
|
-
function usePickerItemScrollIntoView() {
|
|
18
|
-
const [scrollIntoView, setScrollIntoView] = React.useState('');
|
|
19
|
-
const pulseRef = React.useRef(0);
|
|
20
|
-
const scrollToItemId = React.useCallback(itemId => {
|
|
21
|
-
pulseRef.current += 1;
|
|
22
|
-
const token = pulseRef.current;
|
|
23
|
-
setScrollIntoView('');
|
|
24
|
-
setTimeout(() => {
|
|
25
|
-
if (pulseRef.current !== token) return;
|
|
26
|
-
setScrollIntoView(itemId);
|
|
27
|
-
}, 0);
|
|
28
|
-
}, []);
|
|
29
|
-
return [scrollIntoView, scrollToItemId];
|
|
30
|
-
}
|
|
31
|
-
// 定义常量
|
|
32
6
|
const PICKER_LINE_HEIGHT = 34; // px
|
|
33
7
|
const PICKER_VISIBLE_ITEMS = 7; // 可见行数
|
|
34
8
|
const PICKER_BLANK_ITEMS = 3; // 空白行数
|
|
@@ -38,85 +12,42 @@ const getIndicatorStyle = lineColor => {
|
|
|
38
12
|
borderBottomColor: lineColor
|
|
39
13
|
};
|
|
40
14
|
};
|
|
41
|
-
// 大屏方案版本要求
|
|
42
|
-
const MIN_DESIGN_APP_VERSION = 16;
|
|
43
|
-
// 判断是否启用测量值缩放适配(true=启用, false=使用系统侧缩放)
|
|
44
|
-
const resolveUseMeasuredScale = res => {
|
|
45
|
-
// H5/weapp 不参与大屏系数
|
|
46
|
-
if (process.env.TARO_ENV === 'h5' || process.env.TARO_ENV === 'weapp') {
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
const designAppVersionRaw = res.designAppVersion;
|
|
50
|
-
const designAppVersionMajor = designAppVersionRaw != null ? parseInt(String(designAppVersionRaw).trim(), 10) : Number.NaN;
|
|
51
|
-
if (!Number.isFinite(designAppVersionMajor) || designAppVersionMajor < MIN_DESIGN_APP_VERSION) {
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
const platform = String(res.platform || '').toLowerCase();
|
|
55
|
-
if (platform === 'harmony' || platform === 'android' || platform === 'ios') {
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
return false;
|
|
59
|
-
};
|
|
60
|
-
// 辅助函数:计算 lengthScaleRatio
|
|
61
|
-
const calculateLengthScaleRatio = res => {
|
|
62
|
-
let lengthScaleRatio = res === null || res === void 0 ? void 0 : res.lengthScaleRatio;
|
|
63
|
-
if (lengthScaleRatio == null || lengthScaleRatio === 0) {
|
|
64
|
-
console.warn('Taro.getSystemInfo: lengthScaleRatio 不存在,使用计算值');
|
|
65
|
-
lengthScaleRatio = 1;
|
|
66
|
-
if (res.windowWidth < 320) {
|
|
67
|
-
lengthScaleRatio = res.windowWidth / 320;
|
|
68
|
-
} else if (res.windowWidth >= 400 && res.windowWidth < 600) {
|
|
69
|
-
lengthScaleRatio = res.windowWidth / 400;
|
|
70
|
-
}
|
|
71
|
-
const shortSide = res.windowWidth < res.windowHeight ? res.windowWidth : res.windowHeight;
|
|
72
|
-
const isBigScreen = shortSide >= 600;
|
|
73
|
-
if (isBigScreen) {
|
|
74
|
-
lengthScaleRatio = shortSide / 720;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
return lengthScaleRatio;
|
|
78
|
-
};
|
|
79
15
|
// 辅助函数:获取系统信息的 lengthScaleRatio 并设置 targetScrollTop
|
|
80
|
-
const setTargetScrollTopWithScale =
|
|
81
|
-
let lengthScaleRatio = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1;
|
|
16
|
+
const setTargetScrollTopWithScale = (setTargetScrollTop, baseValue, randomOffset) => {
|
|
82
17
|
// H5 和 weapp 不参与放大计算,直接使用 baseValue
|
|
83
18
|
if (process.env.TARO_ENV === 'h5' || process.env.TARO_ENV === 'weapp') {
|
|
84
19
|
const finalValue = randomOffset !== undefined ? baseValue + randomOffset : baseValue;
|
|
85
20
|
setTargetScrollTop(finalValue);
|
|
86
21
|
return;
|
|
87
22
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
return useMeasuredScale ? scrollView.scrollHeight / lengthScaleRatio / scrollView.childNodes.length : scrollView.scrollHeight / scrollView.childNodes.length;
|
|
117
|
-
}
|
|
118
|
-
console.warn('Height measurement anomaly');
|
|
119
|
-
return PICKER_LINE_HEIGHT;
|
|
23
|
+
Taro.getSystemInfo({
|
|
24
|
+
success: res => {
|
|
25
|
+
let lengthScaleRatio = res === null || res === void 0 ? void 0 : res.lengthScaleRatio;
|
|
26
|
+
if (lengthScaleRatio == null || lengthScaleRatio === 0) {
|
|
27
|
+
console.warn('Taro.getSystemInfo: lengthScaleRatio 不存在,使用计算值');
|
|
28
|
+
lengthScaleRatio = 1;
|
|
29
|
+
if (res.windowWidth < 320) {
|
|
30
|
+
lengthScaleRatio = res.windowWidth / 320;
|
|
31
|
+
} else if (res.windowWidth >= 400 && res.windowWidth < 600) {
|
|
32
|
+
lengthScaleRatio = res.windowWidth / 400;
|
|
33
|
+
}
|
|
34
|
+
const shortSide = res.windowWidth < res.windowHeight ? res.windowWidth : res.windowHeight;
|
|
35
|
+
const isBigScreen = shortSide >= 600;
|
|
36
|
+
if (isBigScreen) {
|
|
37
|
+
lengthScaleRatio = shortSide / 720;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const scaledValue = baseValue * lengthScaleRatio;
|
|
41
|
+
const finalValue = randomOffset !== undefined ? scaledValue + randomOffset : scaledValue;
|
|
42
|
+
setTargetScrollTop(finalValue);
|
|
43
|
+
},
|
|
44
|
+
fail: err => {
|
|
45
|
+
console.error('获取系统信息失败:', err);
|
|
46
|
+
// 失败时使用默认值 1
|
|
47
|
+
const finalValue = randomOffset !== undefined ? baseValue + randomOffset : baseValue;
|
|
48
|
+
setTargetScrollTop(finalValue);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
120
51
|
};
|
|
121
52
|
function PickerGroupBasic(props) {
|
|
122
53
|
const {
|
|
@@ -127,89 +58,66 @@ function PickerGroupBasic(props) {
|
|
|
127
58
|
onColumnChange,
|
|
128
59
|
selectedIndex = 0,
|
|
129
60
|
// 使用selectedIndex参数,默认为0
|
|
130
|
-
colors = {}
|
|
131
|
-
enableClickItemScroll = true
|
|
61
|
+
colors = {}
|
|
132
62
|
} = props;
|
|
133
63
|
const indicatorStyle = colors.lineColor ? getIndicatorStyle(colors.lineColor) : null;
|
|
134
64
|
const [targetScrollTop, setTargetScrollTop] = React.useState(0);
|
|
135
|
-
const [scrollIntoView, scrollToItemId] = usePickerItemScrollIntoView();
|
|
136
65
|
const scrollViewRef = React.useRef(null);
|
|
137
66
|
const itemRefs = React.useRef([]);
|
|
138
|
-
const selectedIndexPropRef = React.useRef(selectedIndex);
|
|
139
|
-
selectedIndexPropRef.current = selectedIndex;
|
|
140
|
-
const syncScrollFromPropsRef = React.useRef(false);
|
|
141
|
-
const pendingScrollSettleFocusRef = React.useRef(false);
|
|
142
67
|
// 使用selectedIndex初始化当前索引
|
|
143
68
|
const [currentIndex, setCurrentIndex] = React.useState(selectedIndex);
|
|
144
69
|
// 触摸状态用于优化用户体验
|
|
145
|
-
const
|
|
146
|
-
const lengthScaleRatioRef = React.useRef(1);
|
|
147
|
-
const useMeasuredScaleRef = React.useRef(false);
|
|
70
|
+
const [isTouching, setIsTouching] = React.useState(false);
|
|
148
71
|
const itemHeightRef = React.useRef(PICKER_LINE_HEIGHT);
|
|
149
|
-
// 初始化时计算 lengthScaleRatio 并判定缩放模式
|
|
150
72
|
React.useEffect(() => {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
fail: () => {
|
|
158
|
-
lengthScaleRatioRef.current = 1;
|
|
159
|
-
useMeasuredScaleRef.current = false;
|
|
73
|
+
var _a;
|
|
74
|
+
if (process.env.TARO_PLATFORM !== 'harmony') {
|
|
75
|
+
if (scrollViewRef.current && ((_a = scrollViewRef.current) === null || _a === void 0 ? void 0 : _a.scrollHeight)) {
|
|
76
|
+
itemHeightRef.current = scrollViewRef.current.scrollHeight / scrollViewRef.current.childNodes.length;
|
|
77
|
+
} else {
|
|
78
|
+
console.warn('Height measurement anomaly');
|
|
160
79
|
}
|
|
161
|
-
}
|
|
162
|
-
}, []);
|
|
163
|
-
React.useEffect(() => {
|
|
164
|
-
itemHeightRef.current = calculateItemHeight(scrollViewRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
|
|
80
|
+
}
|
|
165
81
|
}, [range.length]); // 只在range长度变化时重新计算
|
|
166
|
-
//
|
|
82
|
+
// 获取选中的索引
|
|
83
|
+
const getSelectedIndex = scrollTop => {
|
|
84
|
+
return Math.round(scrollTop / itemHeightRef.current);
|
|
85
|
+
};
|
|
86
|
+
// 当selectedIndex变化时,调整滚动位置
|
|
167
87
|
React.useEffect(() => {
|
|
168
|
-
if (scrollViewRef.current && range.length > 0 && !
|
|
169
|
-
syncScrollFromPropsRef.current = true;
|
|
88
|
+
if (scrollViewRef.current && range.length > 0 && !isTouching) {
|
|
170
89
|
const baseValue = selectedIndex * itemHeightRef.current;
|
|
171
|
-
setTargetScrollTopWithScale(setTargetScrollTop, baseValue
|
|
90
|
+
setTargetScrollTopWithScale(setTargetScrollTop, baseValue);
|
|
172
91
|
setCurrentIndex(selectedIndex);
|
|
173
|
-
const tid = setTimeout(() => {
|
|
174
|
-
syncScrollFromPropsRef.current = false;
|
|
175
|
-
}, 400);
|
|
176
|
-
return () => clearTimeout(tid);
|
|
177
92
|
}
|
|
178
93
|
}, [selectedIndex, range]);
|
|
179
94
|
// 是否处于归中状态
|
|
180
95
|
const isCenterTimerId = React.useRef(null);
|
|
181
|
-
//
|
|
96
|
+
// 简化为直接在滚动结束时通知父组件
|
|
182
97
|
const handleScrollEnd = () => {
|
|
183
98
|
if (!scrollViewRef.current) return;
|
|
184
99
|
if (isCenterTimerId.current) {
|
|
185
100
|
clearTimeout(isCenterTimerId.current);
|
|
186
101
|
isCenterTimerId.current = null;
|
|
187
102
|
}
|
|
188
|
-
//
|
|
103
|
+
// 做一个0.1s延时 0.1s之内没有新的滑动 则把选项归到中间 然后更新选中项
|
|
189
104
|
isCenterTimerId.current = setTimeout(() => {
|
|
190
105
|
if (!scrollViewRef.current) return;
|
|
191
106
|
const scrollTop = scrollViewRef.current.scrollTop;
|
|
192
|
-
const newIndex = getSelectedIndex(scrollTop
|
|
193
|
-
|
|
194
|
-
const shouldFocusOnScrollSettle = pendingScrollSettleFocusRef.current;
|
|
195
|
-
isTouchingRef.current = false;
|
|
107
|
+
const newIndex = getSelectedIndex(scrollTop);
|
|
108
|
+
setIsTouching(false);
|
|
196
109
|
const baseValue = newIndex * itemHeightRef.current;
|
|
197
110
|
const randomOffset = Math.random() * 0.001; // 随机数为了在一个项内滚动时强制刷新
|
|
198
|
-
setTargetScrollTopWithScale(setTargetScrollTop, baseValue, randomOffset
|
|
111
|
+
setTargetScrollTopWithScale(setTargetScrollTop, baseValue, randomOffset);
|
|
199
112
|
updateIndex(newIndex, columnId);
|
|
200
113
|
onColumnChange === null || onColumnChange === void 0 ? void 0 : onColumnChange({
|
|
201
114
|
columnId,
|
|
202
115
|
index: newIndex
|
|
203
116
|
});
|
|
204
|
-
pendingScrollSettleFocusRef.current = false;
|
|
205
|
-
if (allowA11yFocus && shouldFocusOnScrollSettle) {
|
|
206
|
-
requestAccessibilityFocusOnView(itemRefs.current[newIndex]);
|
|
207
|
-
}
|
|
208
|
-
syncScrollFromPropsRef.current = false;
|
|
209
117
|
isCenterTimerId.current = null;
|
|
210
118
|
}, 100);
|
|
211
119
|
};
|
|
212
|
-
//
|
|
120
|
+
// 滚动处理 - 在滚动时计算索引然后更新选中项样式
|
|
213
121
|
const handleScroll = () => {
|
|
214
122
|
if (!scrollViewRef.current) return;
|
|
215
123
|
if (isCenterTimerId.current) {
|
|
@@ -217,17 +125,7 @@ function PickerGroupBasic(props) {
|
|
|
217
125
|
isCenterTimerId.current = null;
|
|
218
126
|
}
|
|
219
127
|
const scrollTop = scrollViewRef.current.scrollTop;
|
|
220
|
-
const
|
|
221
|
-
const newIndex = getSelectedIndex(scrollTop, ih, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
|
|
222
|
-
const spi = selectedIndexPropRef.current;
|
|
223
|
-
if (newIndex !== spi) {
|
|
224
|
-
if (!syncScrollFromPropsRef.current || isTouchingRef.current) {
|
|
225
|
-
pendingScrollSettleFocusRef.current = true;
|
|
226
|
-
}
|
|
227
|
-
if (isTouchingRef.current) {
|
|
228
|
-
syncScrollFromPropsRef.current = false;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
128
|
+
const newIndex = getSelectedIndex(scrollTop);
|
|
231
129
|
if (newIndex !== currentIndex) {
|
|
232
130
|
setCurrentIndex(newIndex);
|
|
233
131
|
}
|
|
@@ -239,9 +137,6 @@ function PickerGroupBasic(props) {
|
|
|
239
137
|
id: `picker-item-${columnId}-${index}`,
|
|
240
138
|
ref: el => itemRefs.current[index] = el,
|
|
241
139
|
className: `taro-picker__item${index === currentIndex ? ' taro-picker__item--selected' : ''}`,
|
|
242
|
-
...(enableClickItemScroll ? {
|
|
243
|
-
onClick: () => scrollToItemId(`picker-item-${columnId}-${index}`)
|
|
244
|
-
} : {}),
|
|
245
140
|
style: {
|
|
246
141
|
height: PICKER_LINE_HEIGHT,
|
|
247
142
|
color: index === currentIndex ? colors.itemSelectedColor || undefined : colors.itemDefaultColor || undefined
|
|
@@ -260,10 +155,6 @@ function PickerGroupBasic(props) {
|
|
|
260
155
|
height: PICKER_LINE_HEIGHT
|
|
261
156
|
}
|
|
262
157
|
}, `blank-bottom-${idx}`))];
|
|
263
|
-
const clickScrollViewProps = enableClickItemScroll ? {
|
|
264
|
-
scrollIntoView,
|
|
265
|
-
scrollIntoViewAlignment: 'center'
|
|
266
|
-
} : {};
|
|
267
158
|
return /*#__PURE__*/jsxs(View, {
|
|
268
159
|
className: "taro-picker__group",
|
|
269
160
|
children: [/*#__PURE__*/jsx(View, {
|
|
@@ -282,11 +173,8 @@ function PickerGroupBasic(props) {
|
|
|
282
173
|
height: PICKER_LINE_HEIGHT * PICKER_VISIBLE_ITEMS
|
|
283
174
|
},
|
|
284
175
|
scrollTop: targetScrollTop,
|
|
285
|
-
...clickScrollViewProps,
|
|
286
176
|
onScroll: handleScroll,
|
|
287
|
-
onTouchStart: () =>
|
|
288
|
-
isTouchingRef.current = true;
|
|
289
|
-
},
|
|
177
|
+
onTouchStart: () => setIsTouching(true),
|
|
290
178
|
onScrollEnd: handleScrollEnd,
|
|
291
179
|
scrollWithAnimation: true,
|
|
292
180
|
children: realPickerItems
|
|
@@ -301,189 +189,63 @@ function PickerGroupTime(props) {
|
|
|
301
189
|
columnId,
|
|
302
190
|
updateIndex,
|
|
303
191
|
selectedIndex = 0,
|
|
304
|
-
colors = {}
|
|
305
|
-
timeA11yLimitFocus,
|
|
306
|
-
onTimeA11yLimitFocusConsumed,
|
|
307
|
-
timeA11yLimitEventNonce,
|
|
308
|
-
enableClickItemScroll = true
|
|
192
|
+
colors = {}
|
|
309
193
|
} = props;
|
|
310
194
|
const indicatorStyle = colors.lineColor ? getIndicatorStyle(colors.lineColor) : null;
|
|
311
195
|
const [targetScrollTop, setTargetScrollTop] = React.useState(0);
|
|
312
|
-
const [scrollIntoView, scrollToItemId] = usePickerItemScrollIntoView();
|
|
313
196
|
const scrollViewRef = React.useRef(null);
|
|
314
197
|
const itemRefs = React.useRef([]);
|
|
315
|
-
const selectedIndexPropRef = React.useRef(selectedIndex);
|
|
316
|
-
selectedIndexPropRef.current = selectedIndex;
|
|
317
|
-
const syncScrollFromPropsRef = React.useRef(false);
|
|
318
|
-
const prevLimitEventNonceRef = React.useRef(undefined);
|
|
319
|
-
const suppressScrollSettleFocusNonceRef = React.useRef(null);
|
|
320
|
-
const pendingScrollSettleFocusRef = React.useRef(false);
|
|
321
|
-
const pendingLimitFocusRef = React.useRef(null);
|
|
322
|
-
const limitFocusTimerRef = React.useRef(null);
|
|
323
198
|
const [currentIndex, setCurrentIndex] = React.useState(selectedIndex);
|
|
324
|
-
const
|
|
325
|
-
const lengthScaleRatioRef = React.useRef(1);
|
|
326
|
-
const useMeasuredScaleRef = React.useRef(false);
|
|
199
|
+
const [isTouching, setIsTouching] = React.useState(false);
|
|
327
200
|
const itemHeightRef = React.useRef(PICKER_LINE_HEIGHT);
|
|
328
|
-
const clearLimitFocusTimer = React.useCallback(() => {
|
|
329
|
-
if (limitFocusTimerRef.current) {
|
|
330
|
-
clearTimeout(limitFocusTimerRef.current);
|
|
331
|
-
limitFocusTimerRef.current = null;
|
|
332
|
-
}
|
|
333
|
-
}, []);
|
|
334
|
-
const tryFocusPendingLimit = React.useCallback(() => {
|
|
335
|
-
const pending = pendingLimitFocusRef.current;
|
|
336
|
-
const scrollView = scrollViewRef.current;
|
|
337
|
-
if (!pending || !scrollView) return;
|
|
338
|
-
const visualIndex = getSelectedIndex(scrollView.scrollTop, itemHeightRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
|
|
339
|
-
const isStable = visualIndex === pending.index;
|
|
340
|
-
if (!isStable) {
|
|
341
|
-
if (pending.attempts >= 20) {
|
|
342
|
-
pendingLimitFocusRef.current = null;
|
|
343
|
-
if (suppressScrollSettleFocusNonceRef.current === pending.nonce) {
|
|
344
|
-
suppressScrollSettleFocusNonceRef.current = null;
|
|
345
|
-
}
|
|
346
|
-
onTimeA11yLimitFocusConsumed === null || onTimeA11yLimitFocusConsumed === void 0 ? void 0 : onTimeA11yLimitFocusConsumed();
|
|
347
|
-
return;
|
|
348
|
-
}
|
|
349
|
-
pending.attempts += 1;
|
|
350
|
-
clearLimitFocusTimer();
|
|
351
|
-
limitFocusTimerRef.current = setTimeout(() => {
|
|
352
|
-
tryFocusPendingLimit();
|
|
353
|
-
}, 50);
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
const node = itemRefs.current[pending.index];
|
|
357
|
-
pendingLimitFocusRef.current = null;
|
|
358
|
-
if (suppressScrollSettleFocusNonceRef.current === pending.nonce) {
|
|
359
|
-
suppressScrollSettleFocusNonceRef.current = null;
|
|
360
|
-
}
|
|
361
|
-
clearLimitFocusTimer();
|
|
362
|
-
requestAccessibilityFocusOnView(node);
|
|
363
|
-
onTimeA11yLimitFocusConsumed === null || onTimeA11yLimitFocusConsumed === void 0 ? void 0 : onTimeA11yLimitFocusConsumed();
|
|
364
|
-
}, [clearLimitFocusTimer, onTimeA11yLimitFocusConsumed]);
|
|
365
|
-
const schedulePendingLimitFocus = React.useCallback(() => {
|
|
366
|
-
if (!pendingLimitFocusRef.current) return;
|
|
367
|
-
clearLimitFocusTimer();
|
|
368
|
-
limitFocusTimerRef.current = setTimeout(() => {
|
|
369
|
-
tryFocusPendingLimit();
|
|
370
|
-
}, 100);
|
|
371
|
-
}, [clearLimitFocusTimer, tryFocusPendingLimit]);
|
|
372
|
-
React.useEffect(() => clearLimitFocusTimer, [clearLimitFocusTimer]);
|
|
373
|
-
// 初始化时计算 lengthScaleRatio 并判定缩放模式
|
|
374
201
|
React.useEffect(() => {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
fail: () => {
|
|
382
|
-
lengthScaleRatioRef.current = 1;
|
|
383
|
-
useMeasuredScaleRef.current = false;
|
|
202
|
+
var _a;
|
|
203
|
+
if (process.env.TARO_PLATFORM !== 'harmony') {
|
|
204
|
+
if (scrollViewRef.current && ((_a = scrollViewRef.current) === null || _a === void 0 ? void 0 : _a.scrollHeight)) {
|
|
205
|
+
itemHeightRef.current = scrollViewRef.current.scrollHeight / scrollViewRef.current.childNodes.length;
|
|
206
|
+
} else {
|
|
207
|
+
console.warn('Height measurement anomaly');
|
|
384
208
|
}
|
|
385
|
-
}
|
|
386
|
-
}, []);
|
|
387
|
-
React.useEffect(() => {
|
|
388
|
-
itemHeightRef.current = calculateItemHeight(scrollViewRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
|
|
209
|
+
}
|
|
389
210
|
}, [range.length]); // 只在range长度变化时重新计算
|
|
390
|
-
|
|
211
|
+
const getSelectedIndex = scrollTop => {
|
|
212
|
+
return Math.round(scrollTop / itemHeightRef.current);
|
|
213
|
+
};
|
|
214
|
+
// 当selectedIndex变化时,调整滚动位置
|
|
391
215
|
React.useEffect(() => {
|
|
392
|
-
if (scrollViewRef.current && range.length > 0 && !
|
|
393
|
-
syncScrollFromPropsRef.current = true;
|
|
216
|
+
if (scrollViewRef.current && range.length > 0 && !isTouching) {
|
|
394
217
|
const baseValue = selectedIndex * itemHeightRef.current;
|
|
395
|
-
setTargetScrollTopWithScale(setTargetScrollTop, baseValue
|
|
218
|
+
setTargetScrollTopWithScale(setTargetScrollTop, baseValue);
|
|
396
219
|
setCurrentIndex(selectedIndex);
|
|
397
|
-
const tid = setTimeout(() => {
|
|
398
|
-
syncScrollFromPropsRef.current = false;
|
|
399
|
-
}, 400);
|
|
400
|
-
return () => clearTimeout(tid);
|
|
401
220
|
}
|
|
402
221
|
}, [selectedIndex, range]);
|
|
403
|
-
// time 限位 nonce 变更:强制对齐 scrollTop(避免 remount 打断读屏焦点)
|
|
404
|
-
React.useEffect(() => {
|
|
405
|
-
if (!timeA11yLimitEventNonce) return;
|
|
406
|
-
if (!scrollViewRef.current || range.length === 0 || isTouchingRef.current) return;
|
|
407
|
-
syncScrollFromPropsRef.current = true;
|
|
408
|
-
const baseValue = selectedIndex * itemHeightRef.current;
|
|
409
|
-
setTargetScrollTopWithScale(setTargetScrollTop, baseValue, Math.random() * 0.001, lengthScaleRatioRef.current);
|
|
410
|
-
setCurrentIndex(selectedIndex);
|
|
411
|
-
const tid = setTimeout(() => {
|
|
412
|
-
syncScrollFromPropsRef.current = false;
|
|
413
|
-
}, 400);
|
|
414
|
-
return () => clearTimeout(tid);
|
|
415
|
-
}, [timeA11yLimitEventNonce]); // 仅依赖 nonce,其余用 ref
|
|
416
|
-
React.useLayoutEffect(() => {
|
|
417
|
-
if (timeA11yLimitEventNonce === undefined) return;
|
|
418
|
-
const prev = prevLimitEventNonceRef.current;
|
|
419
|
-
prevLimitEventNonceRef.current = timeA11yLimitEventNonce;
|
|
420
|
-
if (timeA11yLimitEventNonce > 0 && (prev === undefined || timeA11yLimitEventNonce > prev)) {
|
|
421
|
-
suppressScrollSettleFocusNonceRef.current = timeA11yLimitEventNonce;
|
|
422
|
-
}
|
|
423
|
-
}, [timeA11yLimitEventNonce]);
|
|
424
|
-
// 限位后登记本列待聚焦项,稳定后再 requestAccessibilityFocus
|
|
425
|
-
React.useEffect(() => {
|
|
426
|
-
const req = timeA11yLimitFocus;
|
|
427
|
-
if (!req || req.columnId !== columnId) return;
|
|
428
|
-
const idx = selectedIndex;
|
|
429
|
-
const nonce = req.nonce;
|
|
430
|
-
pendingScrollSettleFocusRef.current = false;
|
|
431
|
-
pendingLimitFocusRef.current = {
|
|
432
|
-
index: idx,
|
|
433
|
-
nonce,
|
|
434
|
-
attempts: 0
|
|
435
|
-
};
|
|
436
|
-
schedulePendingLimitFocus();
|
|
437
|
-
}, [timeA11yLimitFocus, columnId, selectedIndex, schedulePendingLimitFocus]);
|
|
438
222
|
// 是否处于归中状态
|
|
439
223
|
const isCenterTimerId = React.useRef(null);
|
|
440
|
-
//
|
|
224
|
+
// 简化为直接在滚动结束时通知父组件
|
|
441
225
|
const handleScrollEnd = () => {
|
|
442
226
|
if (!scrollViewRef.current) return;
|
|
443
227
|
if (isCenterTimerId.current) {
|
|
444
228
|
clearTimeout(isCenterTimerId.current);
|
|
445
229
|
isCenterTimerId.current = null;
|
|
446
230
|
}
|
|
447
|
-
//
|
|
231
|
+
// 做一个0.1s延时 0.1s之内没有新的滑动 则把选项归到中间 然后更新选中项
|
|
448
232
|
isCenterTimerId.current = setTimeout(() => {
|
|
449
233
|
if (!scrollViewRef.current) return;
|
|
450
234
|
const scrollTop = scrollViewRef.current.scrollTop;
|
|
451
|
-
const newIndex = getSelectedIndex(scrollTop
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
isTouchingRef.current = false;
|
|
235
|
+
const newIndex = getSelectedIndex(scrollTop);
|
|
236
|
+
setIsTouching(false);
|
|
237
|
+
// 调用updateIndex执行限位逻辑,获取是否触发了限位
|
|
455
238
|
const isLimited = Boolean(updateIndex(newIndex, columnId, true));
|
|
456
|
-
|
|
457
|
-
if (isLimited) {
|
|
458
|
-
pendingScrollSettleFocusRef.current = false;
|
|
459
|
-
}
|
|
239
|
+
// 如果没有触发限位,才执行归中逻辑
|
|
460
240
|
if (!isLimited) {
|
|
461
241
|
const baseValue = newIndex * itemHeightRef.current;
|
|
462
242
|
const randomOffset = Math.random() * 0.001;
|
|
463
|
-
setTargetScrollTopWithScale(setTargetScrollTop, baseValue, randomOffset
|
|
464
|
-
}
|
|
465
|
-
if (!isLimited && hasPendingLimitFocus) {
|
|
466
|
-
pendingScrollSettleFocusRef.current = false;
|
|
467
|
-
schedulePendingLimitFocus();
|
|
468
|
-
syncScrollFromPropsRef.current = false;
|
|
469
|
-
isCenterTimerId.current = null;
|
|
470
|
-
return;
|
|
243
|
+
setTargetScrollTopWithScale(setTargetScrollTop, baseValue, randomOffset);
|
|
471
244
|
}
|
|
472
|
-
if (!isLimited && pendingLimitFocusRef.current == null && suppressScrollSettleFocusNonceRef.current != null) {
|
|
473
|
-
suppressScrollSettleFocusNonceRef.current = null;
|
|
474
|
-
}
|
|
475
|
-
const suppressByLimitNonce = suppressScrollSettleFocusNonceRef.current != null;
|
|
476
|
-
if (!isLimited && allowA11yFocus && shouldFocusOnScrollSettle) {
|
|
477
|
-
pendingScrollSettleFocusRef.current = false;
|
|
478
|
-
if (!suppressByLimitNonce) {
|
|
479
|
-
requestAccessibilityFocusOnView(itemRefs.current[newIndex]);
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
syncScrollFromPropsRef.current = false;
|
|
483
245
|
isCenterTimerId.current = null;
|
|
484
246
|
}, 100);
|
|
485
247
|
};
|
|
486
|
-
//
|
|
248
|
+
// 滚动处理
|
|
487
249
|
const handleScroll = () => {
|
|
488
250
|
if (!scrollViewRef.current) return;
|
|
489
251
|
if (isCenterTimerId.current) {
|
|
@@ -491,23 +253,10 @@ function PickerGroupTime(props) {
|
|
|
491
253
|
isCenterTimerId.current = null;
|
|
492
254
|
}
|
|
493
255
|
const scrollTop = scrollViewRef.current.scrollTop;
|
|
494
|
-
const
|
|
495
|
-
const newIndex = getSelectedIndex(scrollTop, ih, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
|
|
496
|
-
const spi = selectedIndexPropRef.current;
|
|
497
|
-
if (newIndex !== spi) {
|
|
498
|
-
if (!syncScrollFromPropsRef.current || isTouchingRef.current) {
|
|
499
|
-
pendingScrollSettleFocusRef.current = true;
|
|
500
|
-
}
|
|
501
|
-
if (isTouchingRef.current) {
|
|
502
|
-
syncScrollFromPropsRef.current = false;
|
|
503
|
-
}
|
|
504
|
-
}
|
|
256
|
+
const newIndex = getSelectedIndex(scrollTop);
|
|
505
257
|
if (newIndex !== currentIndex) {
|
|
506
258
|
setCurrentIndex(newIndex);
|
|
507
259
|
}
|
|
508
|
-
if (pendingLimitFocusRef.current) {
|
|
509
|
-
schedulePendingLimitFocus();
|
|
510
|
-
}
|
|
511
260
|
};
|
|
512
261
|
// 渲染选项
|
|
513
262
|
const pickerItem = range.map((item, index) => {
|
|
@@ -516,9 +265,6 @@ function PickerGroupTime(props) {
|
|
|
516
265
|
id: `picker-item-${columnId}-${index}`,
|
|
517
266
|
ref: el => itemRefs.current[index] = el,
|
|
518
267
|
className: `taro-picker__item${index === currentIndex ? ' taro-picker__item--selected' : ''}`,
|
|
519
|
-
...(enableClickItemScroll ? {
|
|
520
|
-
onClick: () => scrollToItemId(`picker-item-${columnId}-${index}`)
|
|
521
|
-
} : {}),
|
|
522
268
|
style: {
|
|
523
269
|
height: PICKER_LINE_HEIGHT,
|
|
524
270
|
color: index === currentIndex ? colors.itemSelectedColor || undefined : colors.itemDefaultColor || undefined
|
|
@@ -537,10 +283,6 @@ function PickerGroupTime(props) {
|
|
|
537
283
|
height: PICKER_LINE_HEIGHT
|
|
538
284
|
}
|
|
539
285
|
}, `blank-bottom-${idx}`))];
|
|
540
|
-
const clickScrollViewProps = enableClickItemScroll ? {
|
|
541
|
-
scrollIntoView,
|
|
542
|
-
scrollIntoViewAlignment: 'center'
|
|
543
|
-
} : {};
|
|
544
286
|
return /*#__PURE__*/jsxs(View, {
|
|
545
287
|
className: "taro-picker__group",
|
|
546
288
|
children: [/*#__PURE__*/jsx(View, {
|
|
@@ -559,11 +301,8 @@ function PickerGroupTime(props) {
|
|
|
559
301
|
height: PICKER_LINE_HEIGHT * PICKER_VISIBLE_ITEMS
|
|
560
302
|
},
|
|
561
303
|
scrollTop: targetScrollTop,
|
|
562
|
-
...clickScrollViewProps,
|
|
563
304
|
onScroll: handleScroll,
|
|
564
|
-
onTouchStart: () =>
|
|
565
|
-
isTouchingRef.current = true;
|
|
566
|
-
},
|
|
305
|
+
onTouchStart: () => setIsTouching(true),
|
|
567
306
|
onScrollEnd: handleScrollEnd,
|
|
568
307
|
scrollWithAnimation: true,
|
|
569
308
|
children: realPickerItems
|
|
@@ -577,73 +316,53 @@ function PickerGroupDate(props) {
|
|
|
577
316
|
columnId,
|
|
578
317
|
updateDay,
|
|
579
318
|
selectedIndex = 0,
|
|
580
|
-
colors = {}
|
|
581
|
-
enableClickItemScroll = true
|
|
319
|
+
colors = {}
|
|
582
320
|
} = props;
|
|
583
321
|
const indicatorStyle = colors.lineColor ? getIndicatorStyle(colors.lineColor) : null;
|
|
584
322
|
const [targetScrollTop, setTargetScrollTop] = React.useState(0);
|
|
585
|
-
const [scrollIntoView, scrollToItemId] = usePickerItemScrollIntoView();
|
|
586
323
|
const scrollViewRef = React.useRef(null);
|
|
587
|
-
const itemRefs = React.useRef([]);
|
|
588
|
-
const selectedIndexPropRef = React.useRef(selectedIndex);
|
|
589
|
-
selectedIndexPropRef.current = selectedIndex;
|
|
590
|
-
const syncScrollFromPropsRef = React.useRef(false);
|
|
591
|
-
const pendingScrollSettleFocusRef = React.useRef(false);
|
|
592
324
|
const [currentIndex, setCurrentIndex] = React.useState(selectedIndex);
|
|
593
|
-
const
|
|
594
|
-
const lengthScaleRatioRef = React.useRef(1);
|
|
595
|
-
const useMeasuredScaleRef = React.useRef(false);
|
|
325
|
+
const [isTouching, setIsTouching] = React.useState(false);
|
|
596
326
|
const itemHeightRef = React.useRef(PICKER_LINE_HEIGHT);
|
|
597
|
-
// 初始化时计算 lengthScaleRatio 并判定缩放模式
|
|
598
327
|
React.useEffect(() => {
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
fail: () => {
|
|
606
|
-
lengthScaleRatioRef.current = 1;
|
|
607
|
-
useMeasuredScaleRef.current = false;
|
|
328
|
+
var _a;
|
|
329
|
+
if (process.env.TARO_PLATFORM !== 'harmony') {
|
|
330
|
+
if (scrollViewRef.current && ((_a = scrollViewRef.current) === null || _a === void 0 ? void 0 : _a.scrollHeight)) {
|
|
331
|
+
itemHeightRef.current = scrollViewRef.current.scrollHeight / scrollViewRef.current.childNodes.length;
|
|
332
|
+
} else {
|
|
333
|
+
console.warn('Height measurement anomaly');
|
|
608
334
|
}
|
|
609
|
-
}
|
|
610
|
-
}, []);
|
|
611
|
-
React.useEffect(() => {
|
|
612
|
-
itemHeightRef.current = calculateItemHeight(scrollViewRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
|
|
335
|
+
}
|
|
613
336
|
}, [range.length]); // 只在range长度变化时重新计算
|
|
614
|
-
|
|
337
|
+
const getSelectedIndex = scrollTop => {
|
|
338
|
+
return Math.round(scrollTop / itemHeightRef.current);
|
|
339
|
+
};
|
|
340
|
+
// 当selectedIndex变化时,调整滚动位置
|
|
615
341
|
React.useEffect(() => {
|
|
616
|
-
if (scrollViewRef.current && range.length > 0 && !
|
|
617
|
-
syncScrollFromPropsRef.current = true;
|
|
342
|
+
if (scrollViewRef.current && range.length > 0 && !isTouching) {
|
|
618
343
|
const baseValue = selectedIndex * itemHeightRef.current;
|
|
619
|
-
setTargetScrollTopWithScale(setTargetScrollTop, baseValue
|
|
344
|
+
setTargetScrollTopWithScale(setTargetScrollTop, baseValue);
|
|
620
345
|
setCurrentIndex(selectedIndex);
|
|
621
|
-
const tid = setTimeout(() => {
|
|
622
|
-
syncScrollFromPropsRef.current = false;
|
|
623
|
-
}, 400);
|
|
624
|
-
return () => clearTimeout(tid);
|
|
625
346
|
}
|
|
626
347
|
}, [selectedIndex, range]);
|
|
627
348
|
// 是否处于归中状态
|
|
628
349
|
const isCenterTimerId = React.useRef(null);
|
|
629
|
-
//
|
|
350
|
+
// 简化为直接在滚动结束时通知父组件
|
|
630
351
|
const handleScrollEnd = () => {
|
|
631
352
|
if (!scrollViewRef.current) return;
|
|
632
353
|
if (isCenterTimerId.current) {
|
|
633
354
|
clearTimeout(isCenterTimerId.current);
|
|
634
355
|
isCenterTimerId.current = null;
|
|
635
356
|
}
|
|
636
|
-
//
|
|
357
|
+
// 做一个0.1s延时 0.1s之内没有新的滑动 则把选项归到中间 然后更新选中项
|
|
637
358
|
isCenterTimerId.current = setTimeout(() => {
|
|
638
359
|
if (!scrollViewRef.current) return;
|
|
639
360
|
const scrollTop = scrollViewRef.current.scrollTop;
|
|
640
|
-
const newIndex = getSelectedIndex(scrollTop
|
|
641
|
-
|
|
642
|
-
const shouldFocusOnScrollSettle = pendingScrollSettleFocusRef.current;
|
|
643
|
-
isTouchingRef.current = false;
|
|
361
|
+
const newIndex = getSelectedIndex(scrollTop);
|
|
362
|
+
setIsTouching(false);
|
|
644
363
|
const baseValue = newIndex * itemHeightRef.current;
|
|
645
364
|
const randomOffset = Math.random() * 0.001; // 随机数为了在一个项内滚动时强制刷新
|
|
646
|
-
setTargetScrollTopWithScale(setTargetScrollTop, baseValue, randomOffset
|
|
365
|
+
setTargetScrollTopWithScale(setTargetScrollTop, baseValue, randomOffset);
|
|
647
366
|
// 更新日期值
|
|
648
367
|
if (updateDay) {
|
|
649
368
|
// 解析文本中的数字(移除年、月、日等后缀)
|
|
@@ -651,15 +370,10 @@ function PickerGroupDate(props) {
|
|
|
651
370
|
const numericValue = parseInt(valueText.replace(/[^0-9]/g, ''));
|
|
652
371
|
updateDay(isNaN(numericValue) ? 0 : numericValue, parseInt(columnId));
|
|
653
372
|
}
|
|
654
|
-
pendingScrollSettleFocusRef.current = false;
|
|
655
|
-
if (allowA11yFocus && shouldFocusOnScrollSettle) {
|
|
656
|
-
requestAccessibilityFocusOnView(itemRefs.current[newIndex]);
|
|
657
|
-
}
|
|
658
|
-
syncScrollFromPropsRef.current = false;
|
|
659
373
|
isCenterTimerId.current = null;
|
|
660
374
|
}, 100);
|
|
661
375
|
};
|
|
662
|
-
//
|
|
376
|
+
// 滚动处理
|
|
663
377
|
const handleScroll = () => {
|
|
664
378
|
if (!scrollViewRef.current) return;
|
|
665
379
|
if (isCenterTimerId.current) {
|
|
@@ -667,17 +381,7 @@ function PickerGroupDate(props) {
|
|
|
667
381
|
isCenterTimerId.current = null;
|
|
668
382
|
}
|
|
669
383
|
const scrollTop = scrollViewRef.current.scrollTop;
|
|
670
|
-
const
|
|
671
|
-
const newIndex = getSelectedIndex(scrollTop, ih, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
|
|
672
|
-
const spi = selectedIndexPropRef.current;
|
|
673
|
-
if (newIndex !== spi) {
|
|
674
|
-
if (!syncScrollFromPropsRef.current || isTouchingRef.current) {
|
|
675
|
-
pendingScrollSettleFocusRef.current = true;
|
|
676
|
-
}
|
|
677
|
-
if (isTouchingRef.current) {
|
|
678
|
-
syncScrollFromPropsRef.current = false;
|
|
679
|
-
}
|
|
680
|
-
}
|
|
384
|
+
const newIndex = getSelectedIndex(scrollTop);
|
|
681
385
|
if (newIndex !== currentIndex) {
|
|
682
386
|
setCurrentIndex(newIndex);
|
|
683
387
|
}
|
|
@@ -686,11 +390,7 @@ function PickerGroupDate(props) {
|
|
|
686
390
|
const pickerItem = range.map((item, index) => {
|
|
687
391
|
return /*#__PURE__*/jsx(View, {
|
|
688
392
|
id: `picker-item-${columnId}-${index}`,
|
|
689
|
-
ref: el => itemRefs.current[index] = el,
|
|
690
393
|
className: `taro-picker__item${index === currentIndex ? ' taro-picker__item--selected' : ''}`,
|
|
691
|
-
...(enableClickItemScroll ? {
|
|
692
|
-
onClick: () => scrollToItemId(`picker-item-${columnId}-${index}`)
|
|
693
|
-
} : {}),
|
|
694
394
|
style: {
|
|
695
395
|
height: PICKER_LINE_HEIGHT,
|
|
696
396
|
color: index === currentIndex ? colors.itemSelectedColor || undefined : colors.itemDefaultColor || undefined
|
|
@@ -709,10 +409,6 @@ function PickerGroupDate(props) {
|
|
|
709
409
|
height: PICKER_LINE_HEIGHT
|
|
710
410
|
}
|
|
711
411
|
}, `blank-bottom-${idx}`))];
|
|
712
|
-
const clickScrollViewProps = enableClickItemScroll ? {
|
|
713
|
-
scrollIntoView,
|
|
714
|
-
scrollIntoViewAlignment: 'center'
|
|
715
|
-
} : {};
|
|
716
412
|
return /*#__PURE__*/jsxs(View, {
|
|
717
413
|
className: "taro-picker__group",
|
|
718
414
|
children: [/*#__PURE__*/jsx(View, {
|
|
@@ -731,11 +427,8 @@ function PickerGroupDate(props) {
|
|
|
731
427
|
height: PICKER_LINE_HEIGHT * PICKER_VISIBLE_ITEMS
|
|
732
428
|
},
|
|
733
429
|
scrollTop: targetScrollTop,
|
|
734
|
-
...clickScrollViewProps,
|
|
735
430
|
onScroll: handleScroll,
|
|
736
|
-
onTouchStart: () =>
|
|
737
|
-
isTouchingRef.current = true;
|
|
738
|
-
},
|
|
431
|
+
onTouchStart: () => setIsTouching(true),
|
|
739
432
|
onScrollEnd: handleScrollEnd,
|
|
740
433
|
scrollWithAnimation: true,
|
|
741
434
|
children: realPickerItems
|
|
@@ -751,54 +444,37 @@ function PickerGroupRegion(props) {
|
|
|
751
444
|
updateIndex,
|
|
752
445
|
selectedIndex = 0,
|
|
753
446
|
// 使用selectedIndex参数,默认为0
|
|
754
|
-
colors = {}
|
|
755
|
-
enableClickItemScroll = true
|
|
447
|
+
colors = {}
|
|
756
448
|
} = props;
|
|
757
449
|
const indicatorStyle = colors.lineColor ? getIndicatorStyle(colors.lineColor) : null;
|
|
758
450
|
const scrollViewRef = React.useRef(null);
|
|
759
451
|
const [targetScrollTop, setTargetScrollTop] = React.useState(0);
|
|
760
|
-
const [scrollIntoView, scrollToItemId] = usePickerItemScrollIntoView();
|
|
761
452
|
const [currentIndex, setCurrentIndex] = React.useState(selectedIndex);
|
|
762
|
-
const
|
|
763
|
-
const lengthScaleRatioRef = React.useRef(1);
|
|
764
|
-
const useMeasuredScaleRef = React.useRef(false);
|
|
453
|
+
const [isTouching, setIsTouching] = React.useState(false);
|
|
765
454
|
const itemHeightRef = React.useRef(PICKER_LINE_HEIGHT);
|
|
766
|
-
const
|
|
767
|
-
const selectedIndexPropRef = React.useRef(selectedIndex);
|
|
768
|
-
selectedIndexPropRef.current = selectedIndex;
|
|
769
|
-
const syncScrollFromPropsRef = React.useRef(false);
|
|
770
|
-
const pendingScrollSettleFocusRef = React.useRef(false);
|
|
771
|
-
// 初始化时计算 lengthScaleRatio 并判定缩放模式
|
|
455
|
+
const isUserBeginScrollRef = React.useRef(false);
|
|
772
456
|
React.useEffect(() => {
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
fail: () => {
|
|
780
|
-
lengthScaleRatioRef.current = 1;
|
|
781
|
-
useMeasuredScaleRef.current = false;
|
|
457
|
+
var _a;
|
|
458
|
+
if (process.env.TARO_PLATFORM !== 'harmony') {
|
|
459
|
+
if (scrollViewRef.current && ((_a = scrollViewRef.current) === null || _a === void 0 ? void 0 : _a.scrollHeight)) {
|
|
460
|
+
itemHeightRef.current = scrollViewRef.current.scrollHeight / scrollViewRef.current.childNodes.length;
|
|
461
|
+
} else {
|
|
462
|
+
console.warn('Height measurement anomaly');
|
|
782
463
|
}
|
|
783
|
-
}
|
|
784
|
-
}, []);
|
|
785
|
-
React.useEffect(() => {
|
|
786
|
-
itemHeightRef.current = calculateItemHeight(scrollViewRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
|
|
464
|
+
}
|
|
787
465
|
}, [range.length]); // 只在range长度变化时重新计算
|
|
788
|
-
|
|
466
|
+
const getSelectedIndex = scrollTop => {
|
|
467
|
+
return Math.round(scrollTop / itemHeightRef.current);
|
|
468
|
+
};
|
|
469
|
+
// 当selectedIndex变化时,调整滚动位置
|
|
789
470
|
React.useEffect(() => {
|
|
790
|
-
if (scrollViewRef.current && range.length > 0 && !
|
|
791
|
-
syncScrollFromPropsRef.current = true;
|
|
471
|
+
if (scrollViewRef.current && range.length > 0 && !isTouching) {
|
|
792
472
|
const baseValue = selectedIndex * itemHeightRef.current;
|
|
793
|
-
setTargetScrollTopWithScale(setTargetScrollTop, baseValue
|
|
473
|
+
setTargetScrollTopWithScale(setTargetScrollTop, baseValue);
|
|
794
474
|
setCurrentIndex(selectedIndex);
|
|
795
|
-
const tid = setTimeout(() => {
|
|
796
|
-
syncScrollFromPropsRef.current = false;
|
|
797
|
-
}, 400);
|
|
798
|
-
return () => clearTimeout(tid);
|
|
799
475
|
}
|
|
800
476
|
}, [selectedIndex, range]);
|
|
801
|
-
//
|
|
477
|
+
// 滚动结束处理
|
|
802
478
|
const isCenterTimerId = React.useRef(null);
|
|
803
479
|
const handleScrollEnd = () => {
|
|
804
480
|
if (!scrollViewRef.current) return;
|
|
@@ -806,27 +482,19 @@ function PickerGroupRegion(props) {
|
|
|
806
482
|
clearTimeout(isCenterTimerId.current);
|
|
807
483
|
isCenterTimerId.current = null;
|
|
808
484
|
}
|
|
809
|
-
//
|
|
485
|
+
// 做一个0.1s延时 0.1s之内没有新的滑动 则把选项归到中间 然后更新选中项
|
|
810
486
|
isCenterTimerId.current = setTimeout(() => {
|
|
811
487
|
if (!scrollViewRef.current) return;
|
|
812
488
|
const scrollTop = scrollViewRef.current.scrollTop;
|
|
813
|
-
const newIndex = getSelectedIndex(scrollTop
|
|
814
|
-
|
|
815
|
-
const shouldFocusOnScrollSettle = pendingScrollSettleFocusRef.current;
|
|
816
|
-
isTouchingRef.current = false;
|
|
489
|
+
const newIndex = getSelectedIndex(scrollTop);
|
|
490
|
+
setIsTouching(false);
|
|
817
491
|
const baseValue = newIndex * itemHeightRef.current;
|
|
818
492
|
const randomOffset = Math.random() * 0.001; // 随机数为了在一个项内滚动时强制刷新
|
|
819
|
-
setTargetScrollTopWithScale(setTargetScrollTop, baseValue, randomOffset
|
|
820
|
-
updateIndex(newIndex, columnId, false,
|
|
821
|
-
pendingScrollSettleFocusRef.current = false;
|
|
822
|
-
if (allowA11yFocus && shouldFocusOnScrollSettle) {
|
|
823
|
-
requestAccessibilityFocusOnView(itemRefs.current[newIndex]);
|
|
824
|
-
}
|
|
825
|
-
syncScrollFromPropsRef.current = false;
|
|
826
|
-
isCenterTimerId.current = null;
|
|
493
|
+
setTargetScrollTopWithScale(setTargetScrollTop, baseValue, randomOffset);
|
|
494
|
+
updateIndex(newIndex, columnId, false, isUserBeginScrollRef.current);
|
|
827
495
|
}, 100);
|
|
828
496
|
};
|
|
829
|
-
//
|
|
497
|
+
// 滚动处理 - 在滚动时计算索引
|
|
830
498
|
const handleScroll = () => {
|
|
831
499
|
if (!scrollViewRef.current) return;
|
|
832
500
|
if (isCenterTimerId.current) {
|
|
@@ -834,17 +502,7 @@ function PickerGroupRegion(props) {
|
|
|
834
502
|
isCenterTimerId.current = null;
|
|
835
503
|
}
|
|
836
504
|
const scrollTop = scrollViewRef.current.scrollTop;
|
|
837
|
-
const
|
|
838
|
-
const newIndex = getSelectedIndex(scrollTop, ih, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
|
|
839
|
-
const spi = selectedIndexPropRef.current;
|
|
840
|
-
if (newIndex !== spi) {
|
|
841
|
-
if (!syncScrollFromPropsRef.current || isTouchingRef.current) {
|
|
842
|
-
pendingScrollSettleFocusRef.current = true;
|
|
843
|
-
}
|
|
844
|
-
if (isTouchingRef.current) {
|
|
845
|
-
syncScrollFromPropsRef.current = false;
|
|
846
|
-
}
|
|
847
|
-
}
|
|
505
|
+
const newIndex = getSelectedIndex(scrollTop);
|
|
848
506
|
if (newIndex !== currentIndex) {
|
|
849
507
|
setCurrentIndex(newIndex);
|
|
850
508
|
}
|
|
@@ -854,11 +512,7 @@ function PickerGroupRegion(props) {
|
|
|
854
512
|
const content = rangeKey && item && typeof item === 'object' ? item[rangeKey] : item;
|
|
855
513
|
return /*#__PURE__*/jsx(View, {
|
|
856
514
|
id: `picker-item-${columnId}-${index}`,
|
|
857
|
-
ref: el => itemRefs.current[index] = el,
|
|
858
515
|
className: `taro-picker__item${index === currentIndex ? ' taro-picker__item--selected' : ''}`,
|
|
859
|
-
...(enableClickItemScroll ? {
|
|
860
|
-
onClick: () => scrollToItemId(`picker-item-${columnId}-${index}`)
|
|
861
|
-
} : {}),
|
|
862
516
|
style: {
|
|
863
517
|
height: PICKER_LINE_HEIGHT,
|
|
864
518
|
color: index === currentIndex ? colors.itemSelectedColor || undefined : colors.itemDefaultColor || undefined
|
|
@@ -877,10 +531,6 @@ function PickerGroupRegion(props) {
|
|
|
877
531
|
height: PICKER_LINE_HEIGHT
|
|
878
532
|
}
|
|
879
533
|
}, `blank-bottom-${idx}`))];
|
|
880
|
-
const clickScrollViewProps = enableClickItemScroll ? {
|
|
881
|
-
scrollIntoView,
|
|
882
|
-
scrollIntoViewAlignment: 'center'
|
|
883
|
-
} : {};
|
|
884
534
|
return /*#__PURE__*/jsxs(View, {
|
|
885
535
|
className: "taro-picker__group",
|
|
886
536
|
children: [/*#__PURE__*/jsx(View, {
|
|
@@ -899,10 +549,10 @@ function PickerGroupRegion(props) {
|
|
|
899
549
|
height: PICKER_LINE_HEIGHT * PICKER_VISIBLE_ITEMS
|
|
900
550
|
},
|
|
901
551
|
scrollTop: targetScrollTop,
|
|
902
|
-
...clickScrollViewProps,
|
|
903
552
|
onScroll: handleScroll,
|
|
904
553
|
onTouchStart: () => {
|
|
905
|
-
|
|
554
|
+
setIsTouching(true);
|
|
555
|
+
isUserBeginScrollRef.current = true;
|
|
906
556
|
},
|
|
907
557
|
onScrollEnd: handleScrollEnd,
|
|
908
558
|
scrollWithAnimation: true,
|