@tarojs/components-react 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.
Files changed (77) hide show
  1. package/dist/components/image/index.js +3 -5
  2. package/dist/components/image/index.js.map +1 -1
  3. package/dist/components/picker/index.js +38 -110
  4. package/dist/components/picker/index.js.map +1 -1
  5. package/dist/components/picker/picker-group.js +127 -477
  6. package/dist/components/picker/picker-group.js.map +1 -1
  7. package/dist/components/refresher/index.js +5 -5
  8. package/dist/components/refresher/index.js.map +1 -1
  9. package/dist/components/scroll-view/index.js +36 -80
  10. package/dist/components/scroll-view/index.js.map +1 -1
  11. package/dist/index.css +1 -1
  12. package/dist/index.js +2 -6
  13. package/dist/index.js.map +1 -1
  14. package/dist/original/components/image/index.js +3 -5
  15. package/dist/original/components/image/index.js.map +1 -1
  16. package/dist/original/components/image/style/index.scss +1 -5
  17. package/dist/original/components/picker/index.js +38 -110
  18. package/dist/original/components/picker/index.js.map +1 -1
  19. package/dist/original/components/picker/picker-group.js +127 -477
  20. package/dist/original/components/picker/picker-group.js.map +1 -1
  21. package/dist/original/components/picker/style/index.scss +8 -9
  22. package/dist/original/components/refresher/index.js +5 -5
  23. package/dist/original/components/refresher/index.js.map +1 -1
  24. package/dist/original/components/scroll-view/index.js +36 -80
  25. package/dist/original/components/scroll-view/index.js.map +1 -1
  26. package/dist/original/index.js +2 -6
  27. package/dist/original/index.js.map +1 -1
  28. package/dist/solid/components/image/index.js +3 -5
  29. package/dist/solid/components/image/index.js.map +1 -1
  30. package/dist/solid/components/picker/index.js +45 -121
  31. package/dist/solid/components/picker/index.js.map +1 -1
  32. package/dist/solid/components/picker/picker-group.js +151 -500
  33. package/dist/solid/components/picker/picker-group.js.map +1 -1
  34. package/dist/solid/components/refresher/index.js +5 -5
  35. package/dist/solid/components/refresher/index.js.map +1 -1
  36. package/dist/solid/components/scroll-view/index.js +40 -84
  37. package/dist/solid/components/scroll-view/index.js.map +1 -1
  38. package/dist/solid/index.css +1 -1
  39. package/dist/solid/index.js +1 -1
  40. package/package.json +6 -8
  41. package/dist/components/map/MapContext.js +0 -628
  42. package/dist/components/map/MapContext.js.map +0 -1
  43. package/dist/components/map/MapCustomCallout.js +0 -91
  44. package/dist/components/map/MapCustomCallout.js.map +0 -1
  45. package/dist/components/map/common.js +0 -4
  46. package/dist/components/map/common.js.map +0 -1
  47. package/dist/components/map/createMapContext.js +0 -34
  48. package/dist/components/map/createMapContext.js.map +0 -1
  49. package/dist/components/map/handler.js +0 -50
  50. package/dist/components/map/handler.js.map +0 -1
  51. package/dist/components/map/index.js +0 -329
  52. package/dist/components/map/index.js.map +0 -1
  53. package/dist/components/switch/index.js +0 -125
  54. package/dist/components/switch/index.js.map +0 -1
  55. package/dist/components/switch/style/index.scss.js +0 -4
  56. package/dist/components/switch/style/index.scss.js.map +0 -1
  57. package/dist/contexts/ScrollElementContext.js +0 -6
  58. package/dist/contexts/ScrollElementContext.js.map +0 -1
  59. package/dist/original/components/map/MapContext.js +0 -628
  60. package/dist/original/components/map/MapContext.js.map +0 -1
  61. package/dist/original/components/map/MapCustomCallout.js +0 -91
  62. package/dist/original/components/map/MapCustomCallout.js.map +0 -1
  63. package/dist/original/components/map/common.js +0 -4
  64. package/dist/original/components/map/common.js.map +0 -1
  65. package/dist/original/components/map/createMapContext.js +0 -34
  66. package/dist/original/components/map/createMapContext.js.map +0 -1
  67. package/dist/original/components/map/handler.js +0 -50
  68. package/dist/original/components/map/handler.js.map +0 -1
  69. package/dist/original/components/map/index.js +0 -329
  70. package/dist/original/components/map/index.js.map +0 -1
  71. package/dist/original/components/switch/index.js +0 -125
  72. package/dist/original/components/switch/index.js.map +0 -1
  73. package/dist/original/components/switch/style/index.scss +0 -35
  74. package/dist/original/contexts/ScrollElementContext.js +0 -6
  75. package/dist/original/contexts/ScrollElementContext.js.map +0 -1
  76. package/dist/solid/contexts/ScrollElementContext.js +0 -6
  77. 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 = function (setTargetScrollTop, baseValue, randomOffset) {
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
- if (process.env.TARO_PLATFORM === 'harmony') {
89
- const scaledValue = baseValue;
90
- const finalValue = randomOffset !== undefined ? scaledValue + randomOffset : scaledValue;
91
- setTargetScrollTop(finalValue);
92
- } else {
93
- const scaledValue = baseValue * lengthScaleRatio;
94
- const finalValue = randomOffset !== undefined ? scaledValue + randomOffset : scaledValue;
95
- setTargetScrollTop(finalValue);
96
- }
97
- };
98
- // 根据 scrollTop 计算选中索引
99
- // 系统侧缩放模式:scrollHeight 已被系统缩放,直接相除即可
100
- // 自行缩放模式:需要除以 ratio 换算(harmony 特殊处理,ratio 已内嵌在 itemHeight 中)
101
- const getSelectedIndex = function (scrollTop, itemHeight) {
102
- let lengthScaleRatio = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
103
- let useMeasuredScale = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
104
- if (!useMeasuredScale || process.env.TARO_PLATFORM === 'harmony') {
105
- return Math.round(scrollTop / itemHeight);
106
- }
107
- return Math.round(scrollTop / lengthScaleRatio / itemHeight);
108
- };
109
- // 计算单项高度(返回设计稿值)
110
- const calculateItemHeight = function (scrollView, lengthScaleRatio) {
111
- let useMeasuredScale = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
112
- if (process.env.TARO_PLATFORM === 'harmony') {
113
- return useMeasuredScale ? PICKER_LINE_HEIGHT * lengthScaleRatio : PICKER_LINE_HEIGHT;
114
- }
115
- if (scrollView && (scrollView === null || scrollView === void 0 ? void 0 : scrollView.scrollHeight)) {
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 isTouchingRef = React.useRef(false);
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
- Taro.getSystemInfo({
152
- success: res => {
153
- lengthScaleRatioRef.current = calculateLengthScaleRatio(res);
154
- useMeasuredScaleRef.current = resolveUseMeasuredScale(res);
155
- itemHeightRef.current = calculateItemHeight(scrollViewRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
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
- // props 的 selectedIndex 变化:滚至对应项并短时标记程序化滚动(syncScrollFromPropsRef)
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 && !isTouchingRef.current) {
169
- syncScrollFromPropsRef.current = true;
88
+ if (scrollViewRef.current && range.length > 0 && !isTouching) {
170
89
  const baseValue = selectedIndex * itemHeightRef.current;
171
- setTargetScrollTopWithScale(setTargetScrollTop, baseValue, undefined, lengthScaleRatioRef.current);
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
- // 100ms 内无新滚动则归中并提交索引
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, itemHeightRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
193
- const allowA11yFocus = !syncScrollFromPropsRef.current;
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, lengthScaleRatioRef.current);
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
- // 滚动中:按 scrollTop 更新高亮索引
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 ih = itemHeightRef.current;
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 isTouchingRef = React.useRef(false);
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
- Taro.getSystemInfo({
376
- success: res => {
377
- lengthScaleRatioRef.current = calculateLengthScaleRatio(res);
378
- useMeasuredScaleRef.current = resolveUseMeasuredScale(res);
379
- itemHeightRef.current = calculateItemHeight(scrollViewRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
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
- // props selectedIndex 变化:滚至对应项并短时标记程序化滚动(syncScrollFromPropsRef)
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 && !isTouchingRef.current) {
393
- syncScrollFromPropsRef.current = true;
216
+ if (scrollViewRef.current && range.length > 0 && !isTouching) {
394
217
  const baseValue = selectedIndex * itemHeightRef.current;
395
- setTargetScrollTopWithScale(setTargetScrollTop, baseValue, undefined, lengthScaleRatioRef.current);
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
- // 100ms 内无新滚动则归中并提交索引
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, itemHeightRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
452
- const allowA11yFocus = !syncScrollFromPropsRef.current;
453
- const shouldFocusOnScrollSettle = pendingScrollSettleFocusRef.current;
454
- isTouchingRef.current = false;
235
+ const newIndex = getSelectedIndex(scrollTop);
236
+ setIsTouching(false);
237
+ // 调用updateIndex执行限位逻辑,获取是否触发了限位
455
238
  const isLimited = Boolean(updateIndex(newIndex, columnId, true));
456
- const hasPendingLimitFocus = pendingLimitFocusRef.current != null;
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, lengthScaleRatioRef.current);
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
- // 滚动中:按 scrollTop 更新高亮索引
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 ih = itemHeightRef.current;
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 isTouchingRef = React.useRef(false);
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
- Taro.getSystemInfo({
600
- success: res => {
601
- lengthScaleRatioRef.current = calculateLengthScaleRatio(res);
602
- useMeasuredScaleRef.current = resolveUseMeasuredScale(res);
603
- itemHeightRef.current = calculateItemHeight(scrollViewRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
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
- // props selectedIndex 变化:滚至对应项并短时标记程序化滚动(syncScrollFromPropsRef)
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 && !isTouchingRef.current) {
617
- syncScrollFromPropsRef.current = true;
342
+ if (scrollViewRef.current && range.length > 0 && !isTouching) {
618
343
  const baseValue = selectedIndex * itemHeightRef.current;
619
- setTargetScrollTopWithScale(setTargetScrollTop, baseValue, undefined, lengthScaleRatioRef.current);
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
- // 100ms 内无新滚动则归中并提交索引
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, itemHeightRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
641
- const allowA11yFocus = !syncScrollFromPropsRef.current;
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, lengthScaleRatioRef.current);
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
- // 滚动中:按 scrollTop 更新高亮索引
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 ih = itemHeightRef.current;
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 isTouchingRef = React.useRef(false);
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 itemRefs = React.useRef([]);
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
- Taro.getSystemInfo({
774
- success: res => {
775
- lengthScaleRatioRef.current = calculateLengthScaleRatio(res);
776
- useMeasuredScaleRef.current = resolveUseMeasuredScale(res);
777
- itemHeightRef.current = calculateItemHeight(scrollViewRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
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
- // props selectedIndex 变化:滚至对应项并短时标记程序化滚动(syncScrollFromPropsRef)
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 && !isTouchingRef.current) {
791
- syncScrollFromPropsRef.current = true;
471
+ if (scrollViewRef.current && range.length > 0 && !isTouching) {
792
472
  const baseValue = selectedIndex * itemHeightRef.current;
793
- setTargetScrollTopWithScale(setTargetScrollTop, baseValue, undefined, lengthScaleRatioRef.current);
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
- // 滚动静止后归中(debounce)
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
- // 100ms 内无新滚动则归中并提交索引
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, itemHeightRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
814
- const allowA11yFocus = !syncScrollFromPropsRef.current;
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, lengthScaleRatioRef.current);
820
- updateIndex(newIndex, columnId, false, allowA11yFocus);
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
- // 滚动中:按 scrollTop 更新高亮索引
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 ih = itemHeightRef.current;
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
- isTouchingRef.current = true;
554
+ setIsTouching(true);
555
+ isUserBeginScrollRef.current = true;
906
556
  },
907
557
  onScrollEnd: handleScrollEnd,
908
558
  scrollWithAnimation: true,