uview-plus 3.8.113 → 3.8.119
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/changelog.md +83 -0
- package/components/u-cascader/u-cascader.vue +1 -1
- package/components/u-cropper/u-cropper.vue +8 -8
- package/components/u-datetime-picker/u-datetime-picker.vue +44 -8
- package/components/u-float-button/u-float-button.vue +1 -1
- package/components/u-goods-sku/u-goods-sku.vue +2 -2
- package/components/u-list-item/u-list-item.vue +4 -0
- package/components/u-navbar/theme-vars.scss +14 -0
- package/components/u-notice-bar/theme-vars.scss +16 -0
- package/components/u-parse/node/node.vue +23 -4
- package/components/u-select/u-select.vue +31 -11
- package/components/u-subsection/theme-vars.scss +24 -0
- package/components/u-switch/theme-vars.scss +24 -0
- package/components/u-tabbar/u-tabbar.vue +17 -6
- package/components/u-tabbar-item/midButtonGeometry.js +19 -0
- package/components/u-tabbar-item/u-tabbar-item.vue +118 -41
- package/components/u-tag/theme-vars.scss +14 -0
- package/components/u-transition/u-transition.vue +0 -1
- package/components/u-waterfall/u-waterfall.vue +181 -162
- package/libs/function/index.js +33 -0
- package/libs/mixin/mixin.js +3 -0
- package/package.json +2 -2
|
@@ -92,14 +92,16 @@
|
|
|
92
92
|
return {
|
|
93
93
|
columnList: [[]], // 存储每列的数据
|
|
94
94
|
children: [],
|
|
95
|
-
// 用于标记是否已经初始化
|
|
96
|
-
initialized: false,
|
|
97
|
-
windowWidth: 375,
|
|
98
|
-
windowHeight: 0,
|
|
99
|
-
distributionQueue: [],
|
|
100
|
-
distributionRunning: false,
|
|
101
|
-
distributionPromise: null,
|
|
102
|
-
distributionGeneration: 0
|
|
95
|
+
// 用于标记是否已经初始化
|
|
96
|
+
initialized: false,
|
|
97
|
+
windowWidth: 375,
|
|
98
|
+
windowHeight: 0,
|
|
99
|
+
distributionQueue: [],
|
|
100
|
+
distributionRunning: false,
|
|
101
|
+
distributionPromise: null,
|
|
102
|
+
distributionGeneration: 0,
|
|
103
|
+
// 每个分配循环持有独立令牌:锁被强制重置后新循环接管,旧循环恢复时只能安静退出
|
|
104
|
+
distributionRunToken: 0
|
|
103
105
|
}
|
|
104
106
|
},
|
|
105
107
|
watch: {
|
|
@@ -111,27 +113,27 @@
|
|
|
111
113
|
if (this.columnList.length == 1) {
|
|
112
114
|
this.initColumnList()
|
|
113
115
|
}
|
|
114
|
-
if (!this.isPureAppend(nVal, oVal)) {
|
|
115
|
-
this.redistributeData(nVal);
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
// 取差值,即这一次数组变化新增的部分
|
|
119
|
-
const startIndex = Array.isArray(oVal) && oVal.length > 0 ? oVal.length : 0;
|
|
120
|
-
// 纯追加时只将新增数据加入共享分配队列
|
|
121
|
-
this.handleData(nVal.slice(startIndex));
|
|
116
|
+
if (!this.isPureAppend(nVal, oVal)) {
|
|
117
|
+
this.redistributeData(nVal);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
// 取差值,即这一次数组变化新增的部分
|
|
121
|
+
const startIndex = Array.isArray(oVal) && oVal.length > 0 ? oVal.length : 0;
|
|
122
|
+
// 纯追加时只将新增数据加入共享分配队列
|
|
123
|
+
this.handleData(nVal.slice(startIndex));
|
|
122
124
|
}
|
|
123
125
|
},
|
|
124
126
|
immediate: true
|
|
125
127
|
},
|
|
126
|
-
columns: {
|
|
127
|
-
handler() {
|
|
128
|
-
// 重新分配数据
|
|
129
|
-
if (this.copyFlowList.length > 0) {
|
|
130
|
-
this.redistributeData(this.copyFlowList);
|
|
131
|
-
} else {
|
|
132
|
-
this.clear(false);
|
|
133
|
-
}
|
|
134
|
-
},
|
|
128
|
+
columns: {
|
|
129
|
+
handler() {
|
|
130
|
+
// 重新分配数据
|
|
131
|
+
if (this.copyFlowList.length > 0) {
|
|
132
|
+
this.redistributeData(this.copyFlowList);
|
|
133
|
+
} else {
|
|
134
|
+
this.clear(false);
|
|
135
|
+
}
|
|
136
|
+
},
|
|
135
137
|
immediate: false
|
|
136
138
|
}
|
|
137
139
|
},
|
|
@@ -219,144 +221,161 @@
|
|
|
219
221
|
const newColumnsCount = this.getColumnsCount();
|
|
220
222
|
const oldColumnsCount = this.columnList.length;
|
|
221
223
|
|
|
222
|
-
// 只有列数发生变化时才重新分配数据
|
|
223
|
-
if (newColumnsCount !== oldColumnsCount) {
|
|
224
|
-
this.redistributeData(this.copyFlowList);
|
|
225
|
-
}
|
|
226
|
-
}, 300);
|
|
227
|
-
},
|
|
228
|
-
|
|
229
|
-
// 重新分配所有数据
|
|
230
|
-
redistributeData(data = this.copyFlowList) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
},
|
|
330
|
-
|
|
331
|
-
//
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
for (let i =
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
224
|
+
// 只有列数发生变化时才重新分配数据
|
|
225
|
+
if (newColumnsCount !== oldColumnsCount) {
|
|
226
|
+
this.redistributeData(this.copyFlowList);
|
|
227
|
+
}
|
|
228
|
+
}, 300);
|
|
229
|
+
},
|
|
230
|
+
|
|
231
|
+
// 重新分配所有数据
|
|
232
|
+
redistributeData(data = this.copyFlowList) {
|
|
233
|
+
// 强制重置锁状态,确保能重新开始分配
|
|
234
|
+
this.distributionRunning = false;
|
|
235
|
+
this.distributionPromise = null;
|
|
236
|
+
this.clear(false);
|
|
237
|
+
// 保存所有数据
|
|
238
|
+
const allData = this.cloneData(data || []);
|
|
239
|
+
// 重新分配数据
|
|
240
|
+
return this.handleData(allData);
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
// 判断新数据是否只在原数组末尾追加
|
|
244
|
+
isPureAppend(newData, oldData) {
|
|
245
|
+
if (!Array.isArray(oldData) || oldData.length === 0) return true;
|
|
246
|
+
if (!Array.isArray(newData) || newData.length < oldData.length) return false;
|
|
247
|
+
return oldData.every((item, index) => {
|
|
248
|
+
return JSON.stringify(item) === JSON.stringify(newData[index]);
|
|
249
|
+
});
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
// 将新增数据加入共享队列,确保只有一个分配循环运行
|
|
253
|
+
handleData(newData) {
|
|
254
|
+
if (!newData || newData.length === 0) {
|
|
255
|
+
return this.distributionPromise || Promise.resolve();
|
|
256
|
+
}
|
|
257
|
+
this.distributionQueue.push({
|
|
258
|
+
generation: this.distributionGeneration,
|
|
259
|
+
data: this.cloneData(newData)
|
|
260
|
+
});
|
|
261
|
+
if (!this.distributionRunning) {
|
|
262
|
+
this.distributionPromise = this.runDistributionQueue();
|
|
263
|
+
}
|
|
264
|
+
return this.distributionPromise;
|
|
265
|
+
},
|
|
266
|
+
|
|
267
|
+
// 串行消费所有待分配数据
|
|
268
|
+
async runDistributionQueue() {
|
|
269
|
+
if (this.distributionRunning) return;
|
|
270
|
+
this.distributionRunning = true;
|
|
271
|
+
const runToken = ++this.distributionRunToken;
|
|
272
|
+
try {
|
|
273
|
+
while (this.distributionQueue.length > 0) {
|
|
274
|
+
if (runToken !== this.distributionRunToken) return;
|
|
275
|
+
const task = this.distributionQueue.shift();
|
|
276
|
+
if (task.generation !== this.distributionGeneration) continue;
|
|
277
|
+
await this.distributeData(task.data, task.generation, runToken);
|
|
278
|
+
}
|
|
279
|
+
} finally {
|
|
280
|
+
// 仅当自己仍是当前循环时才释放锁,否则会清掉接管者的运行状态
|
|
281
|
+
if (runToken === this.distributionRunToken) {
|
|
282
|
+
this.distributionRunning = false;
|
|
283
|
+
this.distributionPromise = null;
|
|
284
|
+
if (this.distributionQueue.length > 0) {
|
|
285
|
+
this.distributionPromise = this.runDistributionQueue();
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
|
|
291
|
+
// 数据被重置或分配循环被接管时,当前循环应立即停止写入
|
|
292
|
+
isStaleDistribution(generation, runToken) {
|
|
293
|
+
return generation !== this.distributionGeneration
|
|
294
|
+
|| runToken !== this.distributionRunToken;
|
|
295
|
+
},
|
|
296
|
+
|
|
297
|
+
// 逐项测量并分配数据,代数或令牌变化时立即退出
|
|
298
|
+
async distributeData(newData, generation, runToken) {
|
|
299
|
+
let columnHeights = new Array(this.columnList.length).fill(0);
|
|
300
|
+
for (const item of newData) {
|
|
301
|
+
if (this.isStaleDistribution(generation, runToken)) return;
|
|
302
|
+
columnHeights = await this.getColumnHeights();
|
|
303
|
+
if (this.isStaleDistribution(generation, runToken)) return;
|
|
304
|
+
|
|
305
|
+
const minHeightIndex = this.getMinHeightColumnIndex(columnHeights);
|
|
306
|
+
this.columnList[minHeightIndex].push(item);
|
|
307
|
+
|
|
308
|
+
await sleep(this.addTime);
|
|
309
|
+
if (this.isStaleDistribution(generation, runToken)) return;
|
|
310
|
+
await this.$nextTick();
|
|
311
|
+
if (this.isStaleDistribution(generation, runToken)) return;
|
|
312
|
+
try {
|
|
313
|
+
const rect = await this.$uGetRect(`#u-column-${minHeightIndex}`);
|
|
314
|
+
if (this.isStaleDistribution(generation, runToken)) return;
|
|
315
|
+
if (rect.height) {
|
|
316
|
+
columnHeights[minHeightIndex] = rect.height;
|
|
317
|
+
this.$emit('after-add-one', {
|
|
318
|
+
...item,
|
|
319
|
+
height: rect.height
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
} catch (e) {
|
|
323
|
+
// 获取不到列高时,下一个元素会重新测量所有列
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (this.isStaleDistribution(generation, runToken)) return;
|
|
327
|
+
this.$emit('after-add-all', {
|
|
328
|
+
columnHeights: columnHeights,
|
|
329
|
+
newData: newData
|
|
330
|
+
});
|
|
331
|
+
},
|
|
332
|
+
|
|
333
|
+
// 获取当前所有列的真实高度
|
|
334
|
+
async getColumnHeights() {
|
|
335
|
+
const columnHeights = new Array(this.columnList.length).fill(0);
|
|
336
|
+
for (let i = 0; i < this.columnList.length; i++) {
|
|
337
|
+
try {
|
|
338
|
+
const rect = await this.$uGetRect(`#u-column-${i}`);
|
|
339
|
+
columnHeights[i] = rect.height || 0;
|
|
340
|
+
} catch (e) {
|
|
341
|
+
columnHeights[i] = 0;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return columnHeights;
|
|
345
|
+
},
|
|
346
|
+
|
|
347
|
+
// 获取最短列;高度相同或暂不可测时按列数据量打散,避免全部落到第一列
|
|
348
|
+
getMinHeightColumnIndex(columnHeights) {
|
|
349
|
+
let minIndex = 0;
|
|
350
|
+
for (let i = 1; i < columnHeights.length; i++) {
|
|
351
|
+
const currentHeight = Number(columnHeights[i]) || 0;
|
|
352
|
+
const minHeight = Number(columnHeights[minIndex]) || 0;
|
|
353
|
+
if (currentHeight < minHeight) {
|
|
354
|
+
minIndex = i;
|
|
355
|
+
} else if (currentHeight === minHeight) {
|
|
356
|
+
const currentLength = this.columnList[i] ? this.columnList[i].length : 0;
|
|
357
|
+
const minLength = this.columnList[minIndex] ? this.columnList[minIndex].length : 0;
|
|
358
|
+
if (currentLength < minLength) {
|
|
359
|
+
minIndex = i;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
return minIndex;
|
|
364
|
+
},
|
|
365
|
+
|
|
366
|
+
// 复制而不是引用对象和数组
|
|
367
|
+
cloneData(data) {
|
|
368
|
+
return JSON.parse(JSON.stringify(data));
|
|
353
369
|
},
|
|
354
370
|
|
|
355
|
-
// 清空数据列表
|
|
356
|
-
clear(bak = true) {
|
|
357
|
-
this.distributionGeneration += 1;
|
|
358
|
-
this.distributionQueue.splice(0);
|
|
359
|
-
|
|
371
|
+
// 清空数据列表
|
|
372
|
+
clear(bak = true) {
|
|
373
|
+
this.distributionGeneration += 1;
|
|
374
|
+
this.distributionQueue.splice(0);
|
|
375
|
+
// 强制重置分配锁状态,避免页面隐藏导致的永久锁死
|
|
376
|
+
this.distributionRunning = false;
|
|
377
|
+
this.distributionPromise = null;
|
|
378
|
+
this.initColumnList();
|
|
360
379
|
// 同时清除父组件列表中的数据
|
|
361
380
|
if (bak) {
|
|
362
381
|
// #ifdef VUE2
|
|
@@ -465,4 +484,4 @@
|
|
|
465
484
|
max-width: 100%;
|
|
466
485
|
/* #endif */
|
|
467
486
|
}
|
|
468
|
-
</style>
|
|
487
|
+
</style>
|
package/libs/function/index.js
CHANGED
|
@@ -17,6 +17,20 @@ function emptyNodeInfo() {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
// 组件卸载后仍把它交给原生查询,APP 端会拿已失效的 nodeId 去查视图层映射表,
|
|
21
|
+
// 读到 undefined 再取 .$ 就抛 Cannot read properties of undefined (reading '$')
|
|
22
|
+
function isCompUnmounted(comp) {
|
|
23
|
+
if (!comp) {
|
|
24
|
+
return false
|
|
25
|
+
}
|
|
26
|
+
// 公共 mixin 的 beforeUnmount 里同步置位
|
|
27
|
+
if (comp.__upUnmounted) {
|
|
28
|
+
return true
|
|
29
|
+
}
|
|
30
|
+
// 未应用公共 mixin 时退回 Vue 自身标记:公开实例挂在 $ 上,内部实例直接持有
|
|
31
|
+
return !!(comp.$ ? comp.$.isUnmounted : comp.isUnmounted)
|
|
32
|
+
}
|
|
33
|
+
|
|
20
34
|
// #ifdef APP-NVUE
|
|
21
35
|
const dom = (typeof uni !== 'undefined' && uni && typeof uni.requireNativePlugin === 'function')
|
|
22
36
|
? uni.requireNativePlugin('dom')
|
|
@@ -37,6 +51,10 @@ function getNvueRect(ref) {
|
|
|
37
51
|
|
|
38
52
|
// 查询节点信息
|
|
39
53
|
export function upGetRect(selector, all = false, comp = null) {
|
|
54
|
+
// 判定必须放在条件编译之外,否则 app-harmony 上整段会被裁掉
|
|
55
|
+
if (isCompUnmounted(comp)) {
|
|
56
|
+
return Promise.resolve(all ? [] : emptyNodeInfo())
|
|
57
|
+
}
|
|
40
58
|
return new Promise((resolve) => {
|
|
41
59
|
// #ifndef APP-NVUE
|
|
42
60
|
const query = uni.createSelectorQuery()
|
|
@@ -70,6 +88,17 @@ export function upGetRect(selector, all = false, comp = null) {
|
|
|
70
88
|
})
|
|
71
89
|
}
|
|
72
90
|
|
|
91
|
+
// 卸载后替代真实观察器,保持链式调用不报错
|
|
92
|
+
function noopIntersectionObserver() {
|
|
93
|
+
const observer = {
|
|
94
|
+
relativeTo: () => observer,
|
|
95
|
+
relativeToViewport: () => observer,
|
|
96
|
+
observe: () => {},
|
|
97
|
+
disconnect: () => {}
|
|
98
|
+
}
|
|
99
|
+
return observer
|
|
100
|
+
}
|
|
101
|
+
|
|
73
102
|
// 创建交叉观察器
|
|
74
103
|
// 小程序端 uni.createIntersectionObserver(vm) 会把 Vue 实例代理直接透传给原生 API,
|
|
75
104
|
// 原生内部的 Object.keys(vm) 会触发告警:
|
|
@@ -77,6 +106,10 @@ export function upGetRect(selector, all = false, comp = null) {
|
|
|
77
106
|
// (uni-app 只给 createSelectorQuery 做了 $scope 解包,没给 createIntersectionObserver 做)
|
|
78
107
|
// 组件实例上的同名方法内部使用 $scope(原生组件实例),不会把代理外泄,因此优先使用
|
|
79
108
|
export function upCreateIntersectionObserver(comp, options) {
|
|
109
|
+
// 和 upGetRect 同理:APP 端 addIntersectionObserver 也走 window.__$__(id).$ 查表
|
|
110
|
+
if (isCompUnmounted(comp)) {
|
|
111
|
+
return noopIntersectionObserver()
|
|
112
|
+
}
|
|
80
113
|
// 各家小程序与 H5 都在组件实例上暴露了该方法,内部已完成实例解包
|
|
81
114
|
if (comp && typeof comp.createIntersectionObserver === 'function') {
|
|
82
115
|
return options ? comp.createIntersectionObserver(options) : comp.createIntersectionObserver()
|
package/libs/mixin/mixin.js
CHANGED
|
@@ -251,6 +251,9 @@ export const mixin = defineMixin({
|
|
|
251
251
|
uni.$emit('uOnReachBottom')
|
|
252
252
|
},
|
|
253
253
|
beforeUnmount() {
|
|
254
|
+
// mixin 的钩子先于组件自身钩子同步执行,比 Vue 内部的 $.isUnmounted
|
|
255
|
+
// (在 post-render 队列里异步置位)更早,异步回调据此拦截节点查询
|
|
256
|
+
this.__upUnmounted = true
|
|
254
257
|
// 判断当前页面是否存在parent和chldren,一般在checkbox和checkbox-group父子联动的场景会有此情况
|
|
255
258
|
// 组件销毁时,移除子组件在父组件children数组中的实例,释放资源,避免数据混乱
|
|
256
259
|
if (this.parent && test.array(this.parent.children)) {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "uview-plus",
|
|
3
3
|
"name": "uview-plus",
|
|
4
4
|
"displayName": "零云®uview-plus3.0重磅发布,全面的Vue3鸿蒙跨端移动组件库,组件丰富维护更新稳定。",
|
|
5
|
-
"version": "3.8.
|
|
5
|
+
"version": "3.8.119",
|
|
6
6
|
"description": "零云®uview-plus已兼容vue3支持多语言,120+全面的组件和便捷的工具会让您信手拈来。近期新增拖动排序、条码、图片裁剪、下拉刷新、虚拟列表、签名、Markdown等。",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"uview",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"echarts",
|
|
12
12
|
"ui",
|
|
13
13
|
"可视化"
|
|
14
|
-
],
|
|
14
|
+
],
|
|
15
15
|
"main": "index.js",
|
|
16
16
|
"repository": "https://github.com/ijry/uview-plus",
|
|
17
17
|
"engines": {
|