@tuya-miniapp/smart-ui 2.6.4-beta-6 → 2.6.4-beta-8
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/common/utils.d.ts +1 -0
- package/dist/common/utils.js +7 -0
- package/dist/picker-column/index.css +1 -1
- package/dist/picker-column/index.js +85 -264
- package/dist/picker-column/index.wxml +63 -25
- package/dist/picker-column/index.wxs +453 -26
- package/dist/picker-column/index.wxss +1 -1
- package/dist/wxs/strToStyleObject.wxs +10 -0
- package/lib/common/utils.d.ts +1 -0
- package/lib/common/utils.js +9 -1
- package/lib/picker-column/index.css +1 -1
- package/lib/picker-column/index.js +80 -297
- package/lib/picker-column/index.wxml +63 -25
- package/lib/picker-column/index.wxs +453 -26
- package/lib/picker-column/index.wxss +1 -1
- package/lib/wxs/strToStyleObject.wxs +10 -0
- package/package.json +1 -1
|
@@ -3,6 +3,53 @@ var style = require('../wxs/style.wxs');
|
|
|
3
3
|
var addUnit = require('../wxs/add-unit.wxs');
|
|
4
4
|
var wxUtils = require('../wxs/utils.wxs');
|
|
5
5
|
|
|
6
|
+
let startPo = { y: 0 }; // 记录当前拖动元素的开始的位置
|
|
7
|
+
|
|
8
|
+
const setStyle = (ownerInstance, style, selector) => {
|
|
9
|
+
const dom = queryComponent(ownerInstance, selector);
|
|
10
|
+
if (!dom) {
|
|
11
|
+
console.log(selector, '--selector 无法获取');
|
|
12
|
+
return
|
|
13
|
+
}
|
|
14
|
+
dom.setStyle(style);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function range(num, min, max) {
|
|
18
|
+
return Math.min(Math.max(num, min), max);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function adjustIndex(index, options) {
|
|
22
|
+
const count = options.length;
|
|
23
|
+
index = range(index, 0, count);
|
|
24
|
+
for (let i = index; i < count; i++) {
|
|
25
|
+
if (!isDisabled(options[i])) return i;
|
|
26
|
+
}
|
|
27
|
+
for (let i = index - 1; i >= 0; i--) {
|
|
28
|
+
if (!isDisabled(options[i])) return i;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isDisabled(option) {
|
|
33
|
+
return typeof option === 'object' && option.disabled;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function generateRangeArray(start, end) {
|
|
37
|
+
const resultArray = [];
|
|
38
|
+
for (let i = start; i < end; i++) {
|
|
39
|
+
resultArray.push(i);
|
|
40
|
+
}
|
|
41
|
+
return resultArray;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const queryComponent = function (ownerInstance, selector) {
|
|
45
|
+
const instance = ownerInstance?.selectComponent(selector);
|
|
46
|
+
return instance;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
function sliceArray(list, start, end) {
|
|
50
|
+
return list.slice(start, end);
|
|
51
|
+
}
|
|
52
|
+
|
|
6
53
|
function isObj(x) {
|
|
7
54
|
var type = typeof x;
|
|
8
55
|
return x !== null && (type === 'object' || type === 'function');
|
|
@@ -27,53 +74,433 @@ function wrapperStyle(data) {
|
|
|
27
74
|
'text-indent': data.unit ? '-8rpx' : '0',
|
|
28
75
|
transition: 'transform ' + data.duration + 'ms ease-out',
|
|
29
76
|
'line-height': addUnit(data.itemHeight),
|
|
30
|
-
transform: 'translate3d(0, ' + offset + ', 0)',
|
|
31
77
|
});
|
|
32
78
|
}
|
|
33
79
|
return style({
|
|
34
80
|
'text-indent': data.unit ? '-8rpx' : '0',
|
|
35
81
|
'line-height': addUnit(data.itemHeight),
|
|
36
|
-
transform: 'translate3d(0, ' + offset + ', 0)',
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function wrapperInterStyle(data) {
|
|
41
|
-
var offset = data.renderStart * data.itemHeight;
|
|
42
|
-
offset = addUnit(offset);
|
|
43
|
-
return style({
|
|
44
|
-
'padding-top': offset,
|
|
45
82
|
});
|
|
46
83
|
}
|
|
47
84
|
|
|
48
85
|
function wrapperItemStyle(data) {
|
|
49
86
|
var heightStyleStr = "height: " + data.itemHeight + 'px;'
|
|
50
|
-
var
|
|
51
|
-
var
|
|
87
|
+
var maxSideShow = data.visibleItemCount + 2;
|
|
88
|
+
var offsetIndex = data.animationIndex - data.index;
|
|
89
|
+
if (Math.abs(offsetIndex) > maxSideShow) heightStyleStr
|
|
90
|
+
const finOffsetIndex = offsetIndex > 0 ? Math.min(offsetIndex, maxSideShow) : Math.max(offsetIndex, -maxSideShow);
|
|
91
|
+
var scale = 1 - Math.abs(finOffsetIndex * 0.15);
|
|
92
|
+
var rotateX = rotateX = Math.abs(finOffsetIndex * 10);
|
|
93
|
+
var direction = offsetIndex > 0 ? 1 : -1;
|
|
94
|
+
var translateYIndex = Math.abs(finOffsetIndex);
|
|
95
|
+
var translateYOffset = translateYIndex * translateYIndex * direction * state.itemHeight * 0.1
|
|
96
|
+
const transStyle = style({
|
|
97
|
+
transform: `rotateX(${rotateX}deg) scale(${scale}) translateY(${translateYOffset}px) translateZ(0)`,
|
|
98
|
+
});
|
|
99
|
+
return transStyle + ';' + heightStyleStr
|
|
100
|
+
}
|
|
52
101
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
// const transStyle = style({
|
|
59
|
-
// transform: `rotateX(${rotateX}deg) scale(${1 - scale}) translateY(${translateYIndex * Math.abs(translateYIndex) * Math.abs(translateYIndex) * data.itemHeight * 0.1}px) translateZ(0)`,
|
|
60
|
-
// });
|
|
61
|
-
// return transStyle + ';' + heightStyleStr + (fontStyleStr ? fontStyleStr + ';' : fontStyleStr) + activeStyleStr
|
|
62
|
-
return heightStyleStr + (fontStyleStr ? fontStyleStr + ';' : fontStyleStr) + activeStyleStr
|
|
102
|
+
function wrapperItemTextStyle(data) {
|
|
103
|
+
var fontStyle = data.fontStyle;
|
|
104
|
+
var activeStyle = data.activeStyle;
|
|
105
|
+
var isActive = Math.abs(data.index - data.animationIndex) < 0.5;
|
|
106
|
+
return fontStyle ? fontStyle + ';' : '' + (isActive ? activeStyle + ';' : '')
|
|
63
107
|
}
|
|
64
108
|
|
|
65
109
|
function wrapperItemClass(data) {
|
|
66
110
|
var staticClass = 'smart-ellipsis';
|
|
67
111
|
var activeClass = 'active-class';
|
|
68
|
-
var isActive = Math.abs(data.
|
|
69
|
-
|
|
112
|
+
var isActive = Math.abs(data.index - data.animationIndex) < 0.5;
|
|
113
|
+
const currOption = data.options[data.index];
|
|
114
|
+
return staticClass + ' ' + wxUtils.bem('picker-column__item', { disabled: currOption && currOption.disabled, selected: isActive }) + ' ' + (isActive ? activeClass : '');
|
|
70
115
|
}
|
|
71
116
|
|
|
117
|
+
var state = {}
|
|
118
|
+
|
|
119
|
+
var preStateObj = {}
|
|
120
|
+
|
|
121
|
+
function updateState(instanceId, key, value) {
|
|
122
|
+
if (!key) return;
|
|
123
|
+
state[instanceId] = state[instanceId] || {}
|
|
124
|
+
state[instanceId][key] = value
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function getCurrState(instanceId) {
|
|
128
|
+
return state[instanceId]
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function updatePreState(instanceId, state) {
|
|
132
|
+
const preStateStr = JSON.stringify(state)
|
|
133
|
+
preStateObj[instanceId] = preStateStr;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function getPreState(instanceId) {
|
|
137
|
+
return preStateObj[instanceId]
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function getDomState(ownerInstance) {
|
|
141
|
+
const dom = queryComponent(ownerInstance, '.smart-picker-column');
|
|
142
|
+
const state = dom.getDataset();
|
|
143
|
+
return state
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function initDomState(instanceId, ownerInstance) {
|
|
147
|
+
const state = getDomState(ownerInstance);
|
|
148
|
+
updateState(instanceId, 'options', state.options)
|
|
149
|
+
updateState(instanceId, 'valueKey', state.valuekey)
|
|
150
|
+
updateState(instanceId, 'itemHeight', state.itemheight)
|
|
151
|
+
updateState(instanceId, 'visibleItemCount', state.visibleitemcount)
|
|
152
|
+
updateState(instanceId, 'activeIndex', state.activeindex)
|
|
153
|
+
updateState(instanceId, 'loop', state.loop)
|
|
154
|
+
updateState(instanceId, 'animationTime', state.animationtime)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const updateValue = (instanceId, key) => (newOptions, oldOptions, ownerInstance) => {
|
|
158
|
+
if (!instanceId) return;
|
|
159
|
+
initDomState(instanceId, ownerInstance)
|
|
160
|
+
updateState(instanceId, key, newOptions)
|
|
161
|
+
updateOffset(instanceId, ownerInstance)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function updateOffset(instanceId, ownerInstance) {
|
|
165
|
+
const state = getCurrState(instanceId);
|
|
166
|
+
const domState = getDomState(ownerInstance);
|
|
167
|
+
if(getPreState(instanceId) === JSON.stringify(domState) || !state.itemHeight || !state.visibleItemCount || !Array.isArray(state.options) || state.animationTime === undefined) {
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
updatePreState(instanceId, domState)
|
|
171
|
+
const sideCount = Math.floor(state.visibleItemCount / 2)
|
|
172
|
+
const optionLength = state.options.length;
|
|
173
|
+
updateState(instanceId, 'sideCount', sideCount);
|
|
174
|
+
const currActiveIndex = state.activeIndex < 0 ? 0 : state.activeIndex >= optionLength ? optionLength - 1 : state.activeIndex;
|
|
175
|
+
const currList = getCurrList(instanceId, state.options, currActiveIndex, ownerInstance)
|
|
176
|
+
updateRenderPartOffset(instanceId, ownerInstance)
|
|
177
|
+
const textVarStyle = {}
|
|
178
|
+
currList.forEach((item, index) => {
|
|
179
|
+
textVarStyle['--picker-item-content_' + index] = "'" + optionText(item, state.valueKey) + "'"
|
|
180
|
+
})
|
|
181
|
+
const offset = state.itemHeight * (sideCount - currActiveIndex);
|
|
182
|
+
updateState(instanceId, 'offset', offset)
|
|
183
|
+
updateState(instanceId,'offsetActiveIndex', currActiveIndex);
|
|
184
|
+
setStyle(ownerInstance, {
|
|
185
|
+
transform: 'translateY(' + addUnit(offset) + ')',
|
|
186
|
+
...textVarStyle,
|
|
187
|
+
}, '.smart-picker-column__offset');
|
|
188
|
+
|
|
189
|
+
setTimeout(() => {
|
|
190
|
+
updateItemStyle(instanceId, ownerInstance);
|
|
191
|
+
}, 10)
|
|
192
|
+
}
|
|
193
|
+
/** 更新聚焦点位样式 */
|
|
194
|
+
const updateItemStyle = (instanceId, ownerInstance, time) => {
|
|
195
|
+
const state = getCurrState(instanceId);
|
|
196
|
+
const currActiveIndex = state.offsetActiveIndex;
|
|
197
|
+
state.viewIndexList.slice(0, 20).map((item, index) => {
|
|
198
|
+
const viewOptionsActiveIndex = item;
|
|
199
|
+
const maxSideShow = state.sideCount + 2;
|
|
200
|
+
const offsetIndex = currActiveIndex - viewOptionsActiveIndex;
|
|
201
|
+
if(Math.abs(offsetIndex) > maxSideShow) return;
|
|
202
|
+
const finOffsetIndex = offsetIndex > 0 ? Math.min(offsetIndex, maxSideShow) : Math.max(offsetIndex, -maxSideShow);
|
|
203
|
+
const scale = 1 - Math.abs(finOffsetIndex * 0.15);
|
|
204
|
+
const rotateX = Math.abs(finOffsetIndex * 10);
|
|
205
|
+
const direction = offsetIndex > 0 ? 1 : -1;
|
|
206
|
+
const translateYIndex = Math.abs(finOffsetIndex);
|
|
207
|
+
const translateYOffset = translateYIndex * translateYIndex * direction * state.itemHeight * 0.1
|
|
208
|
+
const className = `.smart-picker-column__item_${index}`;
|
|
209
|
+
setStyle(ownerInstance, {
|
|
210
|
+
transform: `rotateX(${rotateX}deg) scale(${scale}) translateY(${translateYOffset}px) translateZ(0)`,
|
|
211
|
+
transition: !time ? 'none' : 'transform ' + time + 'ms',
|
|
212
|
+
}, className);
|
|
213
|
+
})
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const getTwoPartOffset = (activeIndex) => {
|
|
217
|
+
const currActiveIndex = activeIndex < 0 ? 0 : activeIndex
|
|
218
|
+
let partNum = Math.floor((currActiveIndex) / 10);
|
|
219
|
+
const lastNum = activeIndex - partNum * 10;
|
|
220
|
+
if (lastNum < 5 && partNum > 0) {
|
|
221
|
+
partNum -= 1;
|
|
222
|
+
}
|
|
223
|
+
const part2Times = Math.floor(partNum / 2);
|
|
224
|
+
const part2Percent = partNum % 2;
|
|
225
|
+
const onePartOffset = part2Percent + part2Times;
|
|
226
|
+
const twoPartOffset = part2Times;
|
|
227
|
+
return { onePartOffset , twoPartOffset }
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const getCurrList = (instanceId, options, activeIndex, ownerInstance) => {
|
|
231
|
+
const { onePartOffset, twoPartOffset } = getTwoPartOffset(activeIndex);
|
|
232
|
+
const isReverse = onePartOffset > twoPartOffset;
|
|
233
|
+
updateState(instanceId, 'onePartOffset', onePartOffset)
|
|
234
|
+
updateState(instanceId, 'twoPartOffset', twoPartOffset)
|
|
235
|
+
const startPart = twoPartOffset + onePartOffset;
|
|
236
|
+
const viewIndexList = !isReverse ? generateRangeArray(startPart * 10, startPart * 10 + 20) : [...generateRangeArray(startPart * 10 + 10, startPart * 10 + 20), ...generateRangeArray(startPart * 10, startPart * 10 + 10)]
|
|
237
|
+
updateState(instanceId,'viewIndexList', viewIndexList)
|
|
238
|
+
// ownerInstance.callMethod('viewOptionsChange', viewIndexList);
|
|
239
|
+
if (!isReverse) return options.slice(startPart * 10, startPart * 10 + 20);
|
|
240
|
+
let firstList = options.slice(startPart * 10 + 10, startPart * 10 + 20);
|
|
241
|
+
const scendList = options.slice(startPart * 10, startPart * 10 + 10);
|
|
242
|
+
if (firstList.length < 10) {
|
|
243
|
+
// firstList = [...firstList, ...options.slice(0, 10 - firstList.length)];
|
|
244
|
+
firstList = [...firstList, ...new Array(10 - firstList.length).fill('')];
|
|
245
|
+
}
|
|
246
|
+
return [...firstList, ...scendList];
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const updateRenderPartOffset = (instanceId, ownerInstance, direction) => {
|
|
250
|
+
const state = getCurrState(instanceId);
|
|
251
|
+
const offsetDistance = 20 * state.itemHeight;
|
|
252
|
+
setStyle(ownerInstance, {
|
|
253
|
+
transform: 'translateY(' + addUnit(offsetDistance * state.onePartOffset) + ')',
|
|
254
|
+
}, '.smart-picker-column__visual__item_1');
|
|
255
|
+
setStyle(ownerInstance, {
|
|
256
|
+
transform: 'translateY(' + addUnit(offsetDistance * state.twoPartOffset) + ')',
|
|
257
|
+
}, '.smart-picker-column__visual__item_2');
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const checkNeedUpdateItemStyle = (instanceId, currActiveIndex) => {
|
|
261
|
+
const state = getCurrState(instanceId);
|
|
262
|
+
const { onePartOffset, twoPartOffset } = getTwoPartOffset(currActiveIndex);
|
|
263
|
+
return onePartOffset !== state.onePartOffset || twoPartOffset !== state.twoPartOffset;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const updateOptionsStyle = (instanceId, ownerInstance, style, time) => {
|
|
267
|
+
const state = getCurrState(instanceId);
|
|
268
|
+
const needUpdateListOption = checkNeedUpdateItemStyle(instanceId, state.offsetActiveIndex);
|
|
269
|
+
if (!needUpdateListOption) {
|
|
270
|
+
setStyle(ownerInstance, {
|
|
271
|
+
...style,
|
|
272
|
+
}, '.smart-picker-column__offset');
|
|
273
|
+
updateItemStyle(instanceId, ownerInstance, time);
|
|
274
|
+
return
|
|
275
|
+
}
|
|
276
|
+
const currList = getCurrList(instanceId, state.options, state.offsetActiveIndex, ownerInstance)
|
|
277
|
+
updateRenderPartOffset(instanceId, ownerInstance);
|
|
278
|
+
const textVarStyle = getCSSVarText(instanceId, currList)
|
|
279
|
+
setStyle(ownerInstance, {
|
|
280
|
+
...style,
|
|
281
|
+
...textVarStyle,
|
|
282
|
+
}, '.smart-picker-column__offset');
|
|
283
|
+
updateItemStyle(instanceId, ownerInstance, time);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const getCSSVarText = (instanceId, currList) => {
|
|
287
|
+
const state = getCurrState(instanceId);
|
|
288
|
+
const textVarStyle = {}
|
|
289
|
+
currList.forEach((item, index) => {
|
|
290
|
+
textVarStyle['--picker-item-content_' + index] = "'" + optionText(item, state.valueKey) + "'"
|
|
291
|
+
})
|
|
292
|
+
return textVarStyle;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const touchStart = (instanceId) => (e, ownerInstance) => {
|
|
296
|
+
const state = getCurrState(instanceId);
|
|
297
|
+
if(state.endTimer) {
|
|
298
|
+
clearInterval(state.endTimer);
|
|
299
|
+
updateState(instanceId, 'endTimer', null);
|
|
300
|
+
updateState(instanceId, 'offset', state.offsetting);
|
|
301
|
+
}
|
|
302
|
+
const { pageY } = e.touches[0];
|
|
303
|
+
startPo.y = pageY;
|
|
304
|
+
updateState(instanceId, 'offsetList', []);
|
|
305
|
+
updateState(instanceId, 'moving', false);
|
|
306
|
+
updateState(instanceId, 'offsetting', state.offset);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
// 滚动期间:1.更新滚动位置 2.更新聚焦点位样式 3.更新列表渲染起始位置 4.更新列表文字CSS 变量
|
|
311
|
+
const touchMove = (instanceId) => (e, ownerInstance) => {
|
|
312
|
+
const state = getCurrState(instanceId);
|
|
313
|
+
updateState(instanceId, 'moving', true);
|
|
314
|
+
const { pageY } = e.touches[0];
|
|
315
|
+
const offsetY = pageY - startPo.y;
|
|
316
|
+
const offset = state.offset + offsetY;
|
|
317
|
+
const newOffsetList = [...state.offsetList, offset];
|
|
318
|
+
const currActiveIndex = -offset / state.itemHeight + state.sideCount;
|
|
319
|
+
const preIndexLast = Math.abs(state.offsetActiveIndex % 1);
|
|
320
|
+
const curIndexLast = Math.abs(currActiveIndex % 1);
|
|
321
|
+
const offsetCompare = offset - state.offsetting;
|
|
322
|
+
const direction = offsetCompare < 0 ? 'down' : offsetCompare > 0 ? 'up' : state.movingDirection || 'down';
|
|
323
|
+
updateState(instanceId, 'offsetActiveIndex', currActiveIndex);
|
|
324
|
+
updateState(instanceId, 'offsetting', offset);
|
|
325
|
+
updateState(instanceId, 'offsetList', newOffsetList);
|
|
326
|
+
updateState(instanceId, 'movingDirection', direction);
|
|
327
|
+
updateOptionsStyle(instanceId, ownerInstance, {
|
|
328
|
+
transform: 'translateY(' + addUnit(offset) + ')',
|
|
329
|
+
transition: 'none',
|
|
330
|
+
});
|
|
331
|
+
if((direction === 'down' && preIndexLast <= 0.5 && curIndexLast > 0.5) || (direction === 'up' && preIndexLast >= 0.5 && curIndexLast < 0.5)) {
|
|
332
|
+
ownerInstance.callMethod('animationIndexChange', currActiveIndex);
|
|
333
|
+
ownerInstance.callMethod('vibrateShort');
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
const touchEnd = (instanceId) => function (e, ownerInstance) {
|
|
339
|
+
const state = getCurrState(instanceId);
|
|
340
|
+
if(!state.moving) return;
|
|
341
|
+
const preOffsetList = state.offsetList;
|
|
342
|
+
|
|
343
|
+
const maxUpOptionsDistance = state.loop ? state.itemHeight * 500 : state.sideCount * state.itemHeight;
|
|
344
|
+
const maxDownOptionsDistance = state.loop ? -state.itemHeight * 500 : -Math.max((state.options.length - state.sideCount - 1) * state.itemHeight, 0);
|
|
345
|
+
// 计算最后几帧的平均速度,用于惯性滚动
|
|
346
|
+
let recentVelocity = 0;
|
|
347
|
+
/** -1: 向下, 1: 向上, 0: 无滚动 */
|
|
348
|
+
let scrollDirection = 0;
|
|
349
|
+
|
|
350
|
+
if (preOffsetList.length >= 2) {
|
|
351
|
+
// 计算速度,优先使用最后几帧的数据
|
|
352
|
+
let recentOffset = 0;
|
|
353
|
+
let recentTime = 0;
|
|
354
|
+
|
|
355
|
+
if (preOffsetList.length >= 3) {
|
|
356
|
+
// 有3个或以上数据点,使用最后3个点计算速度
|
|
357
|
+
recentOffset = preOffsetList[preOffsetList.length - 1] - preOffsetList[preOffsetList.length - 3];
|
|
358
|
+
recentTime = 2; // 2帧间隔
|
|
359
|
+
} else if (preOffsetList.length === 2) {
|
|
360
|
+
// 只有2个数据点,使用这2个点计算速度
|
|
361
|
+
recentOffset = preOffsetList[1] - preOffsetList[0];
|
|
362
|
+
recentTime = 1; // 1帧间隔
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// 计算速度 (px/ms)
|
|
366
|
+
recentVelocity = Math.abs(recentOffset) / (recentTime * 16);
|
|
367
|
+
|
|
368
|
+
// 确定滚动方向
|
|
369
|
+
if (recentOffset > 0) {
|
|
370
|
+
scrollDirection = 1; // 向上滚动
|
|
371
|
+
} else if (recentOffset < 0) {
|
|
372
|
+
scrollDirection = -1; // 向下滚动
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// 惯性滚动参数配置
|
|
377
|
+
const minVelocity = 0.1; // 最小速度阈值,低于此值停止滚动
|
|
378
|
+
const maxInertiaDistance = state.itemHeight * 8; // 最大惯性滚动距离
|
|
379
|
+
|
|
380
|
+
// 计算惯性滚动距离
|
|
381
|
+
let inertiaDistance = 0;
|
|
382
|
+
if (recentVelocity > minVelocity) {
|
|
383
|
+
// 使用物理公式计算惯性距离:distance = velocity^2 / (2 * friction)
|
|
384
|
+
// 这里简化处理,直接使用速度乘以一个系数
|
|
385
|
+
inertiaDistance = recentVelocity * 200; // 200ms的惯性时间
|
|
386
|
+
|
|
387
|
+
// 限制最大滚动距离
|
|
388
|
+
if (inertiaDistance > maxInertiaDistance) {
|
|
389
|
+
inertiaDistance = maxInertiaDistance;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// 根据滚动方向确定正负值
|
|
393
|
+
inertiaDistance = inertiaDistance * scrollDirection;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// 计算最终目标位置 和 index
|
|
397
|
+
let targetOffset = Math.round((state.offsetting + inertiaDistance) / state.itemHeight) * state.itemHeight;
|
|
398
|
+
let currTargetActiveIndex = -targetOffset / state.itemHeight + state.sideCount;
|
|
399
|
+
currTargetActiveIndex = adjustIndex(currTargetActiveIndex, state.options);
|
|
400
|
+
targetOffset = -(currTargetActiveIndex - state.sideCount) * state.itemHeight;
|
|
401
|
+
|
|
402
|
+
const isNeedTransition = Math.abs(targetOffset - state.offsetting) > 1;
|
|
403
|
+
const time = isNeedTransition ? state.animationTime : 0;
|
|
404
|
+
const animationOffset = Math.abs(targetOffset - state.offsetting);
|
|
405
|
+
const offsetCount = Math.floor(Math.abs(currTargetActiveIndex - state.offsetActiveIndex));
|
|
406
|
+
if (time > 150 && animationOffset > state.itemHeight) {
|
|
407
|
+
const midTime = 16;
|
|
408
|
+
const count = Math.floor((time - 150) / midTime);
|
|
409
|
+
const midOffset = (targetOffset - state.offsetting)/ count;
|
|
410
|
+
let startCount = 0
|
|
411
|
+
const endTimer = setInterval(() => {
|
|
412
|
+
startCount++;
|
|
413
|
+
const currOffset = state.offsetting + midOffset;
|
|
414
|
+
const currIndex = -currOffset / state.itemHeight + state.sideCount;
|
|
415
|
+
if (startCount >= count) {
|
|
416
|
+
// 动画结束,设置最终状态
|
|
417
|
+
updateState(instanceId, 'offsetActiveIndex', currTargetActiveIndex);
|
|
418
|
+
clearInterval(endTimer);
|
|
419
|
+
updateState(instanceId, 'offsetting', targetOffset);
|
|
420
|
+
updateState(instanceId, 'offset', targetOffset);
|
|
421
|
+
updateState(instanceId, 'moving', false);
|
|
422
|
+
updateOptionsStyle(instanceId, ownerInstance, {
|
|
423
|
+
transform: 'translateY(' + addUnit(Math.round(targetOffset)) + ')',
|
|
424
|
+
transition: 'transform ' + (time ? time + 100 : time) + 'ms',
|
|
425
|
+
});
|
|
426
|
+
if(currTargetActiveIndex !== state.activeIndex) {
|
|
427
|
+
ownerInstance.callMethod('activeIndexChange', currTargetActiveIndex);
|
|
428
|
+
} else {
|
|
429
|
+
ownerInstance.callMethod('animationIndexChange', currTargetActiveIndex);
|
|
430
|
+
}
|
|
431
|
+
return
|
|
432
|
+
};
|
|
433
|
+
updateState(instanceId, 'offsetActiveIndex', currIndex);
|
|
434
|
+
updateState(instanceId, 'offsetting', currOffset);
|
|
435
|
+
updateOptionsStyle(instanceId, ownerInstance, {
|
|
436
|
+
transform: 'translateY(' + addUnit(Math.round(targetOffset)) + ')',
|
|
437
|
+
transition: 'transform ' + (time ? time + 100 : time) + 'ms',
|
|
438
|
+
});
|
|
439
|
+
}, midTime);
|
|
440
|
+
updateState(instanceId, 'endTimer', endTimer);
|
|
441
|
+
ownerInstance.callMethod('vibrateShort', offsetCount);
|
|
442
|
+
} else {
|
|
443
|
+
Math.abs(currTargetActiveIndex - state.offsetActiveIndex) >= 1 && ownerInstance.callMethod('vibrateShort');
|
|
444
|
+
updateState(instanceId, 'offsetActiveIndex', currTargetActiveIndex);
|
|
445
|
+
updateState(instanceId, 'offsetting', targetOffset);
|
|
446
|
+
updateState(instanceId, 'offset', targetOffset);
|
|
447
|
+
updateState(instanceId, 'moving', false);
|
|
448
|
+
updateOptionsStyle(instanceId, ownerInstance, {
|
|
449
|
+
transform: 'translateY(' + addUnit(Math.round(targetOffset)) + ')',
|
|
450
|
+
transition: 'transform ' + (time ? time + 100 : time) + 'ms',
|
|
451
|
+
});
|
|
452
|
+
if(currTargetActiveIndex !== state.activeIndex) {
|
|
453
|
+
ownerInstance.callMethod('activeIndexChange', currTargetActiveIndex);
|
|
454
|
+
} else {
|
|
455
|
+
ownerInstance.callMethod('animationIndexChange', currTargetActiveIndex);
|
|
456
|
+
}
|
|
457
|
+
return
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const tapItem = (instanceId) => (e, ownerInstance) => {
|
|
462
|
+
const state = getCurrState(instanceId);
|
|
463
|
+
const currTargetActiveIndex = e.currentTarget.dataset.index;
|
|
464
|
+
const option = state.options[currTargetActiveIndex];
|
|
465
|
+
if (option === undefined || option && typeof option === 'object' && option.disabled) return;
|
|
466
|
+
const targetOffset = -(currTargetActiveIndex - state.sideCount) * state.itemHeight;
|
|
467
|
+
if (state.startTimer) {
|
|
468
|
+
clearTimeout(state.startTimer);
|
|
469
|
+
updateState(instanceId, 'startTimer', null);
|
|
470
|
+
}
|
|
471
|
+
if (currTargetActiveIndex === state.offsetActiveIndex) return;
|
|
472
|
+
const offsetCount = Math.abs(currTargetActiveIndex - state.offsetActiveIndex);
|
|
473
|
+
if (state.tapTimer) {
|
|
474
|
+
clearTimeout(state.tapTimer);
|
|
475
|
+
updateState(instanceId, 'tapTimer', null);
|
|
476
|
+
}
|
|
477
|
+
updateState(instanceId, 'offsetActiveIndex', currTargetActiveIndex);
|
|
478
|
+
updateState(instanceId, 'offsetting', targetOffset);
|
|
479
|
+
updateState(instanceId, 'offset', targetOffset);
|
|
480
|
+
updateOptionsStyle(instanceId, ownerInstance, {
|
|
481
|
+
transform: 'translateY(' + addUnit(Math.round(targetOffset)) + ')',
|
|
482
|
+
transition: 'transform 200ms',
|
|
483
|
+
}, 200);
|
|
484
|
+
ownerInstance.callMethod('vibrateShort', offsetCount, 150);
|
|
485
|
+
const tapTimer = setTimeout(() => {
|
|
486
|
+
ownerInstance.callMethod('activeIndexChange', currTargetActiveIndex);
|
|
487
|
+
updateState(instanceId, 'tapTimer', null);
|
|
488
|
+
}, 150);
|
|
489
|
+
updateState(instanceId, 'tapTimer', tapTimer);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
|
|
72
493
|
module.exports = {
|
|
73
494
|
optionText: optionText,
|
|
74
495
|
rootStyle: rootStyle,
|
|
75
496
|
wrapperStyle: wrapperStyle,
|
|
76
|
-
wrapperInterStyle: wrapperInterStyle,
|
|
77
497
|
wrapperItemStyle: wrapperItemStyle,
|
|
78
|
-
wrapperItemClass: wrapperItemClass
|
|
498
|
+
wrapperItemClass: wrapperItemClass,
|
|
499
|
+
updateValue: updateValue,
|
|
500
|
+
touchStart: touchStart,
|
|
501
|
+
touchMove: touchMove,
|
|
502
|
+
touchEnd: touchEnd,
|
|
503
|
+
sliceArray: sliceArray,
|
|
504
|
+
wrapperItemTextStyle: wrapperItemTextStyle,
|
|
505
|
+
tapItem: tapItem,
|
|
79
506
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
@import '../common/index.wxss';:root{--smart-ui-overlay:rgba(0,0,0,.4);--smart-ui-dialog-background:#fff;--smart-ui-border-image:linear-gradient(90deg,transparent,rgba(0,0,0,.3),transparent)}:root[theme=dark]{--smart-ui-overlay:rgba(0,0,0,.7);--smart-ui-dialog-background:#333;--smart-ui-border-image:linear-gradient(90deg,hsla(0,0%,100%,0),hsla(0,0%,100%,.3),hsla(0,0%,100%,0))}.smart-picker-column{color:var(--picker-option-selected-text-color,var(--app-B6-N1,#000));font-size:var(--picker-option-font-size,16px);font-weight:var(--font-weight-bold,500);text-align:center}.smart-picker-column,.smart-picker-column__offset{position:relative;width:100%}.smart-picker-column__visual{position:absolute;top:0;width:100%}.smart-picker-column__item
|
|
1
|
+
@import '../common/index.wxss';:root{--smart-ui-overlay:rgba(0,0,0,.4);--smart-ui-dialog-background:#fff;--smart-ui-border-image:linear-gradient(90deg,transparent,rgba(0,0,0,.3),transparent)}:root[theme=dark]{--smart-ui-overlay:rgba(0,0,0,.7);--smart-ui-dialog-background:#333;--smart-ui-border-image:linear-gradient(90deg,hsla(0,0%,100%,0),hsla(0,0%,100%,.3),hsla(0,0%,100%,0))}.smart-picker-column{color:var(--picker-option-selected-text-color,var(--app-B6-N1,#000));font-size:var(--picker-option-font-size,16px);font-weight:var(--font-weight-bold,500);text-align:center}.smart-picker-column,.smart-picker-column__offset{position:relative;width:100%}.smart-picker-column__visual{position:absolute;top:0;width:100%}.smart-picker-column__item--selected{color:var(--picker-option-selected-text-color,var(--app-B6-N1,#000));font-weight:var(--picker-option-selected-font-weight-bold,var(--font-weight-bold,700))}.smart-picker-column__item--disabled{opacity:var(--picker-option-disabled-opacity,.3);pointer-events:none}.smart-picker-column__mask{background:transparent;display:flex;flex-direction:column;height:100%;position:absolute;top:0;width:100%;z-index:10}.smart-picker-column__mask__item{flex:1}.smart-picker-column__unit{align-items:center;display:flex;justify-content:center;position:absolute;top:50%;transform:translateY(-50%);width:100%}.smart-picker-column__unit_text{color:var(--picker-option-unit-text-color,var(--app-B6-N4,rgba(0,0,0,.4)));font-size:var(--picker-option-unit-font-size,12px);left:100%;margin-left:var(--picker-option-unit-mid-size,4px);position:absolute;text-align:left;top:50%;transform:translateY(-50%);white-space:nowrap}.smart-picker-column__max-text{color:transparent;font-size:var(--picker-option-font-size,16px);font-weight:var(--font-weight-bold,500);position:relative}.smart-picker-column--disabled{opacity:var(--picker-option-disabled-opacity,.3)}.smart-picker-column__item_0 .smart-picker-column__item__text:after{content:var(--picker-item-content_0,"")}.smart-picker-column__item_1 .smart-picker-column__item__text:after{content:var(--picker-item-content_1,"")}.smart-picker-column__item_2 .smart-picker-column__item__text:after{content:var(--picker-item-content_2,"")}.smart-picker-column__item_3 .smart-picker-column__item__text:after{content:var(--picker-item-content_3,"")}.smart-picker-column__item_4 .smart-picker-column__item__text:after{content:var(--picker-item-content_4,"")}.smart-picker-column__item_5 .smart-picker-column__item__text:after{content:var(--picker-item-content_5,"")}.smart-picker-column__item_6 .smart-picker-column__item__text:after{content:var(--picker-item-content_6,"")}.smart-picker-column__item_7 .smart-picker-column__item__text:after{content:var(--picker-item-content_7,"")}.smart-picker-column__item_8 .smart-picker-column__item__text:after{content:var(--picker-item-content_8,"")}.smart-picker-column__item_9 .smart-picker-column__item__text:after{content:var(--picker-item-content_9,"")}.smart-picker-column__item_10 .smart-picker-column__item__text:after{content:var(--picker-item-content_10,"")}.smart-picker-column__item_11 .smart-picker-column__item__text:after{content:var(--picker-item-content_11,"")}.smart-picker-column__item_12 .smart-picker-column__item__text:after{content:var(--picker-item-content_12,"")}.smart-picker-column__item_13 .smart-picker-column__item__text:after{content:var(--picker-item-content_13,"")}.smart-picker-column__item_14 .smart-picker-column__item__text:after{content:var(--picker-item-content_14,"")}.smart-picker-column__item_15 .smart-picker-column__item__text:after{content:var(--picker-item-content_15,"")}.smart-picker-column__item_16 .smart-picker-column__item__text:after{content:var(--picker-item-content_16,"")}.smart-picker-column__item_17 .smart-picker-column__item__text:after{content:var(--picker-item-content_17,"")}.smart-picker-column__item_18 .smart-picker-column__item__text:after{content:var(--picker-item-content_18,"")}.smart-picker-column__item_19 .smart-picker-column__item__text:after{content:var(--picker-item-content_19,"")}.smart-picker-column__item_20 .smart-picker-column__item__text:after{content:var(--picker-item-content_20,"")}
|