@tarojs/components-react 4.1.9-beta.0 → 4.1.9-beta.1-patch.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 (32) hide show
  1. package/dist/components/picker/index.js +22 -3
  2. package/dist/components/picker/index.js.map +1 -1
  3. package/dist/components/picker/picker-group.js +246 -65
  4. package/dist/components/picker/picker-group.js.map +1 -1
  5. package/dist/components/scroll-view/index.js +104 -30
  6. package/dist/components/scroll-view/index.js.map +1 -1
  7. package/dist/contexts/ScrollElementContext.js +6 -0
  8. package/dist/contexts/ScrollElementContext.js.map +1 -0
  9. package/dist/index.css +1 -1
  10. package/dist/index.js +1 -0
  11. package/dist/index.js.map +1 -1
  12. package/dist/original/components/picker/index.js +22 -3
  13. package/dist/original/components/picker/index.js.map +1 -1
  14. package/dist/original/components/picker/picker-group.js +246 -65
  15. package/dist/original/components/picker/picker-group.js.map +1 -1
  16. package/dist/original/components/picker/style/index.scss +146 -46
  17. package/dist/original/components/scroll-view/index.js +104 -30
  18. package/dist/original/components/scroll-view/index.js.map +1 -1
  19. package/dist/original/contexts/ScrollElementContext.js +6 -0
  20. package/dist/original/contexts/ScrollElementContext.js.map +1 -0
  21. package/dist/original/index.js +1 -0
  22. package/dist/original/index.js.map +1 -1
  23. package/dist/solid/components/picker/index.js +33 -14
  24. package/dist/solid/components/picker/index.js.map +1 -1
  25. package/dist/solid/components/picker/picker-group.js +247 -70
  26. package/dist/solid/components/picker/picker-group.js.map +1 -1
  27. package/dist/solid/components/scroll-view/index.js +109 -35
  28. package/dist/solid/components/scroll-view/index.js.map +1 -1
  29. package/dist/solid/contexts/ScrollElementContext.js +6 -0
  30. package/dist/solid/contexts/ScrollElementContext.js.map +1 -0
  31. package/dist/solid/index.css +1 -1
  32. package/package.json +6 -6
@@ -6,27 +6,146 @@ import { jsx, jsxs } from 'react/jsx-runtime';
6
6
  const PICKER_LINE_HEIGHT = 34; // px
7
7
  const PICKER_VISIBLE_ITEMS = 7; // 可见行数
8
8
  const PICKER_BLANK_ITEMS = 3; // 空白行数
9
- // 辅助函数:获取系统信息的 lengthScaleRatio 并设置 targetScrollTop
10
- const setTargetScrollTopWithScale = (setTargetScrollTop, baseValue, randomOffset) => {
11
- Taro.getSystemInfo({
12
- success: res => {
13
- var _a;
14
- // 使用类型断言访问可能不存在的 lengthScaleRatio 属性
15
- const lengthScaleRatio = (_a = res.lengthScaleRatio) !== null && _a !== void 0 ? _a : 1;
16
- if (!res.lengthScaleRatio) {
17
- console.warn('Taro.getSystemInfo: lengthScaleRatio 不存在,使用默认值 1');
18
- }
19
- const scaledValue = baseValue * lengthScaleRatio;
20
- const finalValue = randomOffset !== undefined ? scaledValue + randomOffset : scaledValue;
21
- setTargetScrollTop(finalValue);
22
- },
23
- fail: err => {
24
- console.error('获取系统信息失败:', err);
25
- // 失败时使用默认值 1
26
- const finalValue = randomOffset !== undefined ? baseValue + randomOffset : baseValue;
27
- setTargetScrollTop(finalValue);
9
+ const getIndicatorStyle = lineColor => {
10
+ return {
11
+ borderTopColor: lineColor,
12
+ borderBottomColor: lineColor
13
+ };
14
+ };
15
+ // 大屏方案版本要求
16
+ const MIN_DESIGN_APP_VERSION = 16;
17
+ const MIN_APP_VERSION = '15.7.0';
18
+ // semver 版本比较
19
+ const isAppVersionAtLeast = (version, min) => {
20
+ var _a, _b;
21
+ if (!version || typeof version !== 'string') return false;
22
+ const parts = v => {
23
+ const m = String(v).trim().match(/^(\d+)(?:\.(\d+))?(?:\.(\d+))?/);
24
+ if (!m) return [];
25
+ return [parseInt(m[1], 10) || 0, parseInt(m[2] || '0', 10) || 0, parseInt(m[3] || '0', 10) || 0];
26
+ };
27
+ const a = parts(version);
28
+ const b = parts(min);
29
+ if (a.length === 0) return false;
30
+ if (b.length === 0) return true;
31
+ for (let i = 0; i < Math.max(a.length, b.length); i++) {
32
+ const da = (_a = a[i]) !== null && _a !== void 0 ? _a : 0;
33
+ const db = (_b = b[i]) !== null && _b !== void 0 ? _b : 0;
34
+ if (da > db) return true;
35
+ if (da < db) return false;
36
+ }
37
+ return true;
38
+ };
39
+ // 读取 JDMobileConfig,异常时返回 undefined
40
+ const tryGetMobileConfigSync = opt => {
41
+ var _a;
42
+ try {
43
+ const fn = (_a = Taro.JDMobileConfig) === null || _a === void 0 ? void 0 : _a.getMobileConfigSync;
44
+ if (typeof fn !== 'function') return undefined;
45
+ return fn(opt);
46
+ } catch (_b) {
47
+ return undefined;
48
+ }
49
+ };
50
+ // 判断是否启用测量值缩放适配(true=启用, false=使用系统侧缩放)
51
+ const resolveUseMeasuredScale = res => {
52
+ // H5/weapp 不参与大屏系数
53
+ if (process.env.TARO_ENV === 'h5' || process.env.TARO_ENV === 'weapp') {
54
+ return false;
55
+ }
56
+ // 条件1: designAppVersion < 16,不满足则使用系统侧缩放
57
+ const designAppVersionRaw = res.designAppVersion;
58
+ const designAppVersionMajor = designAppVersionRaw != null ? parseInt(String(designAppVersionRaw).trim(), 10) : Number.NaN;
59
+ if (!Number.isFinite(designAppVersionMajor) || designAppVersionMajor < MIN_DESIGN_APP_VERSION) {
60
+ return false;
61
+ }
62
+ // 条件2: appVersion < 15.7.0,不满足则使用系统侧缩放
63
+ if (!isAppVersionAtLeast(res.version, MIN_APP_VERSION)) {
64
+ return false;
65
+ }
66
+ // 条件3: 平台判断
67
+ const platform = String(res.platform || '').toLowerCase();
68
+ if (platform === 'harmony') {
69
+ return true;
70
+ }
71
+ if (platform === 'android') {
72
+ const raw = tryGetMobileConfigSync({
73
+ space: 'taro',
74
+ configName: 'config',
75
+ key: 'disableFixBoundingScaleRatio'
76
+ });
77
+ return raw !== 1 && raw !== '1';
78
+ }
79
+ if (platform === 'ios') {
80
+ const raw = tryGetMobileConfigSync({
81
+ space: 'Taro',
82
+ configName: 'excutor',
83
+ key: 'disableBoundingScaleRatio'
84
+ });
85
+ return raw !== 1 && raw !== '1';
86
+ }
87
+ return false;
88
+ };
89
+ // 辅助函数:计算 lengthScaleRatio
90
+ const calculateLengthScaleRatio = res => {
91
+ let lengthScaleRatio = res === null || res === void 0 ? void 0 : res.lengthScaleRatio;
92
+ if (lengthScaleRatio == null || lengthScaleRatio === 0) {
93
+ console.warn('Taro.getSystemInfo: lengthScaleRatio 不存在,使用计算值');
94
+ lengthScaleRatio = 1;
95
+ if (res.windowWidth < 320) {
96
+ lengthScaleRatio = res.windowWidth / 320;
97
+ } else if (res.windowWidth >= 400 && res.windowWidth < 600) {
98
+ lengthScaleRatio = res.windowWidth / 400;
28
99
  }
29
- });
100
+ const shortSide = res.windowWidth < res.windowHeight ? res.windowWidth : res.windowHeight;
101
+ const isBigScreen = shortSide >= 600;
102
+ if (isBigScreen) {
103
+ lengthScaleRatio = shortSide / 720;
104
+ }
105
+ }
106
+ return lengthScaleRatio;
107
+ };
108
+ // 辅助函数:获取系统信息的 lengthScaleRatio 并设置 targetScrollTop
109
+ const setTargetScrollTopWithScale = function (setTargetScrollTop, baseValue, randomOffset) {
110
+ let lengthScaleRatio = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1;
111
+ // H5 和 weapp 不参与放大计算,直接使用 baseValue
112
+ if (process.env.TARO_ENV === 'h5' || process.env.TARO_ENV === 'weapp') {
113
+ const finalValue = randomOffset !== undefined ? baseValue + randomOffset : baseValue;
114
+ setTargetScrollTop(finalValue);
115
+ return;
116
+ }
117
+ if (process.env.TARO_PLATFORM === 'harmony') {
118
+ const scaledValue = baseValue;
119
+ const finalValue = randomOffset !== undefined ? scaledValue + randomOffset : scaledValue;
120
+ setTargetScrollTop(finalValue);
121
+ } else {
122
+ const scaledValue = baseValue * lengthScaleRatio;
123
+ const finalValue = randomOffset !== undefined ? scaledValue + randomOffset : scaledValue;
124
+ setTargetScrollTop(finalValue);
125
+ }
126
+ };
127
+ // 根据 scrollTop 计算选中索引
128
+ // 系统侧缩放模式:scrollHeight 已被系统缩放,直接相除即可
129
+ // 自行缩放模式:需要除以 ratio 换算(harmony 特殊处理,ratio 已内嵌在 itemHeight 中)
130
+ const getSelectedIndex = function (scrollTop, itemHeight) {
131
+ let lengthScaleRatio = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
132
+ let useMeasuredScale = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
133
+ if (!useMeasuredScale || process.env.TARO_PLATFORM === 'harmony') {
134
+ return Math.round(scrollTop / itemHeight);
135
+ }
136
+ return Math.round(scrollTop / lengthScaleRatio / itemHeight);
137
+ };
138
+ // 计算单项高度(返回设计稿值)
139
+ const calculateItemHeight = function (scrollView, lengthScaleRatio) {
140
+ let useMeasuredScale = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
141
+ if (process.env.TARO_PLATFORM === 'harmony') {
142
+ return useMeasuredScale ? PICKER_LINE_HEIGHT * lengthScaleRatio : PICKER_LINE_HEIGHT;
143
+ }
144
+ if (scrollView && (scrollView === null || scrollView === void 0 ? void 0 : scrollView.scrollHeight)) {
145
+ return useMeasuredScale ? scrollView.scrollHeight / lengthScaleRatio / scrollView.childNodes.length : scrollView.scrollHeight / scrollView.childNodes.length;
146
+ }
147
+ console.warn('Height measurement anomaly');
148
+ return PICKER_LINE_HEIGHT;
30
149
  };
31
150
  function PickerGroupBasic(props) {
32
151
  const {
@@ -39,6 +158,7 @@ function PickerGroupBasic(props) {
39
158
  // 使用selectedIndex参数,默认为0
40
159
  colors = {}
41
160
  } = props;
161
+ const indicatorStyle = colors.lineColor ? getIndicatorStyle(colors.lineColor) : null;
42
162
  const [targetScrollTop, setTargetScrollTop] = React.useState(0);
43
163
  const scrollViewRef = React.useRef(null);
44
164
  const itemRefs = React.useRef([]);
@@ -46,21 +166,31 @@ function PickerGroupBasic(props) {
46
166
  const [currentIndex, setCurrentIndex] = React.useState(selectedIndex);
47
167
  // 触摸状态用于优化用户体验
48
168
  const [isTouching, setIsTouching] = React.useState(false);
169
+ const lengthScaleRatioRef = React.useRef(1);
170
+ const useMeasuredScaleRef = React.useRef(false);
49
171
  const itemHeightRef = React.useRef(PICKER_LINE_HEIGHT);
172
+ // 初始化时计算 lengthScaleRatio 并判定缩放模式
50
173
  React.useEffect(() => {
51
- if (scrollViewRef.current) {
52
- itemHeightRef.current = scrollViewRef.current.scrollHeight / scrollViewRef.current.childNodes.length;
53
- }
174
+ Taro.getSystemInfo({
175
+ success: res => {
176
+ lengthScaleRatioRef.current = calculateLengthScaleRatio(res);
177
+ useMeasuredScaleRef.current = resolveUseMeasuredScale(res);
178
+ itemHeightRef.current = calculateItemHeight(scrollViewRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
179
+ },
180
+ fail: () => {
181
+ lengthScaleRatioRef.current = 1;
182
+ useMeasuredScaleRef.current = false;
183
+ }
184
+ });
185
+ }, []);
186
+ React.useEffect(() => {
187
+ itemHeightRef.current = calculateItemHeight(scrollViewRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
54
188
  }, [range.length]); // 只在range长度变化时重新计算
55
- // 获取选中的索引
56
- const getSelectedIndex = scrollTop => {
57
- return Math.round(scrollTop / itemHeightRef.current);
58
- };
59
189
  // 当selectedIndex变化时,调整滚动位置
60
190
  React.useEffect(() => {
61
191
  if (scrollViewRef.current && range.length > 0 && !isTouching) {
62
192
  const baseValue = selectedIndex * itemHeightRef.current;
63
- setTargetScrollTopWithScale(setTargetScrollTop, baseValue);
193
+ setTargetScrollTopWithScale(setTargetScrollTop, baseValue, undefined, lengthScaleRatioRef.current);
64
194
  setCurrentIndex(selectedIndex);
65
195
  }
66
196
  }, [selectedIndex, range]);
@@ -77,16 +207,17 @@ function PickerGroupBasic(props) {
77
207
  isCenterTimerId.current = setTimeout(() => {
78
208
  if (!scrollViewRef.current) return;
79
209
  const scrollTop = scrollViewRef.current.scrollTop;
80
- const newIndex = getSelectedIndex(scrollTop);
210
+ const newIndex = getSelectedIndex(scrollTop, itemHeightRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
81
211
  setIsTouching(false);
82
212
  const baseValue = newIndex * itemHeightRef.current;
83
213
  const randomOffset = Math.random() * 0.001; // 随机数为了在一个项内滚动时强制刷新
84
- setTargetScrollTopWithScale(setTargetScrollTop, baseValue, randomOffset);
214
+ setTargetScrollTopWithScale(setTargetScrollTop, baseValue, randomOffset, lengthScaleRatioRef.current);
85
215
  updateIndex(newIndex, columnId);
86
216
  onColumnChange === null || onColumnChange === void 0 ? void 0 : onColumnChange({
87
217
  columnId,
88
218
  index: newIndex
89
219
  });
220
+ isCenterTimerId.current = null;
90
221
  }, 100);
91
222
  };
92
223
  // 滚动处理 - 在滚动时计算索引然后更新选中项样式
@@ -97,7 +228,7 @@ function PickerGroupBasic(props) {
97
228
  isCenterTimerId.current = null;
98
229
  }
99
230
  const scrollTop = scrollViewRef.current.scrollTop;
100
- const newIndex = getSelectedIndex(scrollTop);
231
+ const newIndex = getSelectedIndex(scrollTop, itemHeightRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
101
232
  if (newIndex !== currentIndex) {
102
233
  setCurrentIndex(newIndex);
103
234
  }
@@ -132,7 +263,10 @@ function PickerGroupBasic(props) {
132
263
  children: [/*#__PURE__*/jsx(View, {
133
264
  className: "taro-picker__mask"
134
265
  }), /*#__PURE__*/jsx(View, {
135
- className: "taro-picker__indicator"
266
+ className: "taro-picker__indicator",
267
+ ...(indicatorStyle ? {
268
+ style: indicatorStyle
269
+ } : {})
136
270
  }), /*#__PURE__*/jsx(ScrollView, {
137
271
  ref: scrollViewRef,
138
272
  scrollY: true,
@@ -160,25 +294,37 @@ function PickerGroupTime(props) {
160
294
  selectedIndex = 0,
161
295
  colors = {}
162
296
  } = props;
297
+ const indicatorStyle = colors.lineColor ? getIndicatorStyle(colors.lineColor) : null;
163
298
  const [targetScrollTop, setTargetScrollTop] = React.useState(0);
164
299
  const scrollViewRef = React.useRef(null);
165
300
  const itemRefs = React.useRef([]);
166
301
  const [currentIndex, setCurrentIndex] = React.useState(selectedIndex);
167
302
  const [isTouching, setIsTouching] = React.useState(false);
303
+ const lengthScaleRatioRef = React.useRef(1);
304
+ const useMeasuredScaleRef = React.useRef(false);
168
305
  const itemHeightRef = React.useRef(PICKER_LINE_HEIGHT);
306
+ // 初始化时计算 lengthScaleRatio 并判定缩放模式
169
307
  React.useEffect(() => {
170
- if (scrollViewRef.current) {
171
- itemHeightRef.current = scrollViewRef.current.scrollHeight / scrollViewRef.current.childNodes.length;
172
- }
308
+ Taro.getSystemInfo({
309
+ success: res => {
310
+ lengthScaleRatioRef.current = calculateLengthScaleRatio(res);
311
+ useMeasuredScaleRef.current = resolveUseMeasuredScale(res);
312
+ itemHeightRef.current = calculateItemHeight(scrollViewRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
313
+ },
314
+ fail: () => {
315
+ lengthScaleRatioRef.current = 1;
316
+ useMeasuredScaleRef.current = false;
317
+ }
318
+ });
319
+ }, []);
320
+ React.useEffect(() => {
321
+ itemHeightRef.current = calculateItemHeight(scrollViewRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
173
322
  }, [range.length]); // 只在range长度变化时重新计算
174
- const getSelectedIndex = scrollTop => {
175
- return Math.round(scrollTop / itemHeightRef.current);
176
- };
177
323
  // 当selectedIndex变化时,调整滚动位置
178
324
  React.useEffect(() => {
179
325
  if (scrollViewRef.current && range.length > 0 && !isTouching) {
180
326
  const baseValue = selectedIndex * itemHeightRef.current;
181
- setTargetScrollTopWithScale(setTargetScrollTop, baseValue);
327
+ setTargetScrollTopWithScale(setTargetScrollTop, baseValue, undefined, lengthScaleRatioRef.current);
182
328
  setCurrentIndex(selectedIndex);
183
329
  }
184
330
  }, [selectedIndex, range]);
@@ -195,7 +341,7 @@ function PickerGroupTime(props) {
195
341
  isCenterTimerId.current = setTimeout(() => {
196
342
  if (!scrollViewRef.current) return;
197
343
  const scrollTop = scrollViewRef.current.scrollTop;
198
- const newIndex = getSelectedIndex(scrollTop);
344
+ const newIndex = getSelectedIndex(scrollTop, itemHeightRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
199
345
  setIsTouching(false);
200
346
  // 调用updateIndex执行限位逻辑,获取是否触发了限位
201
347
  const isLimited = Boolean(updateIndex(newIndex, columnId, true));
@@ -203,8 +349,9 @@ function PickerGroupTime(props) {
203
349
  if (!isLimited) {
204
350
  const baseValue = newIndex * itemHeightRef.current;
205
351
  const randomOffset = Math.random() * 0.001;
206
- setTargetScrollTopWithScale(setTargetScrollTop, baseValue, randomOffset);
352
+ setTargetScrollTopWithScale(setTargetScrollTop, baseValue, randomOffset, lengthScaleRatioRef.current);
207
353
  }
354
+ isCenterTimerId.current = null;
208
355
  }, 100);
209
356
  };
210
357
  // 滚动处理
@@ -215,7 +362,7 @@ function PickerGroupTime(props) {
215
362
  isCenterTimerId.current = null;
216
363
  }
217
364
  const scrollTop = scrollViewRef.current.scrollTop;
218
- const newIndex = getSelectedIndex(scrollTop);
365
+ const newIndex = getSelectedIndex(scrollTop, itemHeightRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
219
366
  if (newIndex !== currentIndex) {
220
367
  setCurrentIndex(newIndex);
221
368
  }
@@ -250,7 +397,10 @@ function PickerGroupTime(props) {
250
397
  children: [/*#__PURE__*/jsx(View, {
251
398
  className: "taro-picker__mask"
252
399
  }), /*#__PURE__*/jsx(View, {
253
- className: "taro-picker__indicator"
400
+ className: "taro-picker__indicator",
401
+ ...(indicatorStyle ? {
402
+ style: indicatorStyle
403
+ } : {})
254
404
  }), /*#__PURE__*/jsx(ScrollView, {
255
405
  ref: scrollViewRef,
256
406
  scrollY: true,
@@ -277,24 +427,36 @@ function PickerGroupDate(props) {
277
427
  selectedIndex = 0,
278
428
  colors = {}
279
429
  } = props;
430
+ const indicatorStyle = colors.lineColor ? getIndicatorStyle(colors.lineColor) : null;
280
431
  const [targetScrollTop, setTargetScrollTop] = React.useState(0);
281
432
  const scrollViewRef = React.useRef(null);
282
433
  const [currentIndex, setCurrentIndex] = React.useState(selectedIndex);
283
434
  const [isTouching, setIsTouching] = React.useState(false);
435
+ const lengthScaleRatioRef = React.useRef(1);
436
+ const useMeasuredScaleRef = React.useRef(false);
284
437
  const itemHeightRef = React.useRef(PICKER_LINE_HEIGHT);
438
+ // 初始化时计算 lengthScaleRatio 并判定缩放模式
285
439
  React.useEffect(() => {
286
- if (scrollViewRef.current) {
287
- itemHeightRef.current = scrollViewRef.current.scrollHeight / scrollViewRef.current.childNodes.length;
288
- }
440
+ Taro.getSystemInfo({
441
+ success: res => {
442
+ lengthScaleRatioRef.current = calculateLengthScaleRatio(res);
443
+ useMeasuredScaleRef.current = resolveUseMeasuredScale(res);
444
+ itemHeightRef.current = calculateItemHeight(scrollViewRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
445
+ },
446
+ fail: () => {
447
+ lengthScaleRatioRef.current = 1;
448
+ useMeasuredScaleRef.current = false;
449
+ }
450
+ });
451
+ }, []);
452
+ React.useEffect(() => {
453
+ itemHeightRef.current = calculateItemHeight(scrollViewRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
289
454
  }, [range.length]); // 只在range长度变化时重新计算
290
- const getSelectedIndex = scrollTop => {
291
- return Math.round(scrollTop / itemHeightRef.current);
292
- };
293
455
  // 当selectedIndex变化时,调整滚动位置
294
456
  React.useEffect(() => {
295
457
  if (scrollViewRef.current && range.length > 0 && !isTouching) {
296
458
  const baseValue = selectedIndex * itemHeightRef.current;
297
- setTargetScrollTopWithScale(setTargetScrollTop, baseValue);
459
+ setTargetScrollTopWithScale(setTargetScrollTop, baseValue, undefined, lengthScaleRatioRef.current);
298
460
  setCurrentIndex(selectedIndex);
299
461
  }
300
462
  }, [selectedIndex, range]);
@@ -311,11 +473,11 @@ function PickerGroupDate(props) {
311
473
  isCenterTimerId.current = setTimeout(() => {
312
474
  if (!scrollViewRef.current) return;
313
475
  const scrollTop = scrollViewRef.current.scrollTop;
314
- const newIndex = getSelectedIndex(scrollTop);
476
+ const newIndex = getSelectedIndex(scrollTop, itemHeightRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
315
477
  setIsTouching(false);
316
478
  const baseValue = newIndex * itemHeightRef.current;
317
479
  const randomOffset = Math.random() * 0.001; // 随机数为了在一个项内滚动时强制刷新
318
- setTargetScrollTopWithScale(setTargetScrollTop, baseValue, randomOffset);
480
+ setTargetScrollTopWithScale(setTargetScrollTop, baseValue, randomOffset, lengthScaleRatioRef.current);
319
481
  // 更新日期值
320
482
  if (updateDay) {
321
483
  // 解析文本中的数字(移除年、月、日等后缀)
@@ -323,6 +485,7 @@ function PickerGroupDate(props) {
323
485
  const numericValue = parseInt(valueText.replace(/[^0-9]/g, ''));
324
486
  updateDay(isNaN(numericValue) ? 0 : numericValue, parseInt(columnId));
325
487
  }
488
+ isCenterTimerId.current = null;
326
489
  }, 100);
327
490
  };
328
491
  // 滚动处理
@@ -333,7 +496,7 @@ function PickerGroupDate(props) {
333
496
  isCenterTimerId.current = null;
334
497
  }
335
498
  const scrollTop = scrollViewRef.current.scrollTop;
336
- const newIndex = getSelectedIndex(scrollTop);
499
+ const newIndex = getSelectedIndex(scrollTop, itemHeightRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
337
500
  if (newIndex !== currentIndex) {
338
501
  setCurrentIndex(newIndex);
339
502
  }
@@ -366,7 +529,10 @@ function PickerGroupDate(props) {
366
529
  children: [/*#__PURE__*/jsx(View, {
367
530
  className: "taro-picker__mask"
368
531
  }), /*#__PURE__*/jsx(View, {
369
- className: "taro-picker__indicator"
532
+ className: "taro-picker__indicator",
533
+ ...(indicatorStyle ? {
534
+ style: indicatorStyle
535
+ } : {})
370
536
  }), /*#__PURE__*/jsx(ScrollView, {
371
537
  ref: scrollViewRef,
372
538
  scrollY: true,
@@ -395,25 +561,37 @@ function PickerGroupRegion(props) {
395
561
  // 使用selectedIndex参数,默认为0
396
562
  colors = {}
397
563
  } = props;
564
+ const indicatorStyle = colors.lineColor ? getIndicatorStyle(colors.lineColor) : null;
398
565
  const scrollViewRef = React.useRef(null);
399
566
  const [targetScrollTop, setTargetScrollTop] = React.useState(0);
400
567
  const [currentIndex, setCurrentIndex] = React.useState(selectedIndex);
401
568
  const [isTouching, setIsTouching] = React.useState(false);
569
+ const lengthScaleRatioRef = React.useRef(1);
570
+ const useMeasuredScaleRef = React.useRef(false);
402
571
  const itemHeightRef = React.useRef(PICKER_LINE_HEIGHT);
403
572
  const isUserBeginScrollRef = React.useRef(false);
573
+ // 初始化时计算 lengthScaleRatio 并判定缩放模式
404
574
  React.useEffect(() => {
405
- if (scrollViewRef.current) {
406
- itemHeightRef.current = scrollViewRef.current.scrollHeight / scrollViewRef.current.childNodes.length;
407
- }
575
+ Taro.getSystemInfo({
576
+ success: res => {
577
+ lengthScaleRatioRef.current = calculateLengthScaleRatio(res);
578
+ useMeasuredScaleRef.current = resolveUseMeasuredScale(res);
579
+ itemHeightRef.current = calculateItemHeight(scrollViewRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
580
+ },
581
+ fail: () => {
582
+ lengthScaleRatioRef.current = 1;
583
+ useMeasuredScaleRef.current = false;
584
+ }
585
+ });
586
+ }, []);
587
+ React.useEffect(() => {
588
+ itemHeightRef.current = calculateItemHeight(scrollViewRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
408
589
  }, [range.length]); // 只在range长度变化时重新计算
409
- const getSelectedIndex = scrollTop => {
410
- return Math.round(scrollTop / itemHeightRef.current);
411
- };
412
590
  // 当selectedIndex变化时,调整滚动位置
413
591
  React.useEffect(() => {
414
592
  if (scrollViewRef.current && range.length > 0 && !isTouching) {
415
593
  const baseValue = selectedIndex * itemHeightRef.current;
416
- setTargetScrollTopWithScale(setTargetScrollTop, baseValue);
594
+ setTargetScrollTopWithScale(setTargetScrollTop, baseValue, undefined, lengthScaleRatioRef.current);
417
595
  setCurrentIndex(selectedIndex);
418
596
  }
419
597
  }, [selectedIndex, range]);
@@ -429,11 +607,11 @@ function PickerGroupRegion(props) {
429
607
  isCenterTimerId.current = setTimeout(() => {
430
608
  if (!scrollViewRef.current) return;
431
609
  const scrollTop = scrollViewRef.current.scrollTop;
432
- const newIndex = getSelectedIndex(scrollTop);
610
+ const newIndex = getSelectedIndex(scrollTop, itemHeightRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
433
611
  setIsTouching(false);
434
612
  const baseValue = newIndex * itemHeightRef.current;
435
613
  const randomOffset = Math.random() * 0.001; // 随机数为了在一个项内滚动时强制刷新
436
- setTargetScrollTopWithScale(setTargetScrollTop, baseValue, randomOffset);
614
+ setTargetScrollTopWithScale(setTargetScrollTop, baseValue, randomOffset, lengthScaleRatioRef.current);
437
615
  updateIndex(newIndex, columnId, false, isUserBeginScrollRef.current);
438
616
  }, 100);
439
617
  };
@@ -445,7 +623,7 @@ function PickerGroupRegion(props) {
445
623
  isCenterTimerId.current = null;
446
624
  }
447
625
  const scrollTop = scrollViewRef.current.scrollTop;
448
- const newIndex = getSelectedIndex(scrollTop);
626
+ const newIndex = getSelectedIndex(scrollTop, itemHeightRef.current, lengthScaleRatioRef.current, useMeasuredScaleRef.current);
449
627
  if (newIndex !== currentIndex) {
450
628
  setCurrentIndex(newIndex);
451
629
  }
@@ -479,7 +657,10 @@ function PickerGroupRegion(props) {
479
657
  children: [/*#__PURE__*/jsx(View, {
480
658
  className: "taro-picker__mask"
481
659
  }), /*#__PURE__*/jsx(View, {
482
- className: "taro-picker__indicator"
660
+ className: "taro-picker__indicator",
661
+ ...(indicatorStyle ? {
662
+ style: indicatorStyle
663
+ } : {})
483
664
  }), /*#__PURE__*/jsx(ScrollView, {
484
665
  ref: scrollViewRef,
485
666
  scrollY: true,