uview-plus 3.8.86 → 3.8.106
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 +150 -3
- package/components/u-action-sheet/u-action-sheet.vue +21 -2
- package/components/u-barcode/u-barcode.vue +0 -2
- package/components/u-button/u-button.vue +2 -5
- package/components/u-canvas/u-canvas.vue +368 -74
- package/components/u-cell/u-cell.vue +8 -0
- package/components/u-datetime-picker/u-datetime-picker.vue +53 -4
- package/components/u-dragsort/u-dragsort.vue +55 -31
- package/components/u-icon/u-icon.vue +12 -3
- package/components/u-icon/util.js +81 -10
- package/components/u-index-item/u-index-item.vue +1 -1
- package/components/u-index-list/u-index-list.vue +1 -1
- package/components/u-novel-reader/content-normalizer.js +80 -0
- package/components/u-novel-reader/layout-engine.js +225 -0
- package/components/u-novel-reader/measure-adapter.js +69 -0
- package/components/u-novel-reader/novelReader.js +35 -0
- package/components/u-novel-reader/persistence.js +144 -0
- package/components/u-novel-reader/props.js +100 -0
- package/components/u-novel-reader/reader-catalog.vue +234 -0
- package/components/u-novel-reader/reader-content.vue +226 -0
- package/components/u-novel-reader/reader-core.js +151 -0
- package/components/u-novel-reader/reader-settings.vue +325 -0
- package/components/u-novel-reader/reader-toolbar.vue +313 -0
- package/components/u-novel-reader/theme-vars.scss +49 -0
- package/components/u-novel-reader/u-novel-reader.vue +836 -0
- package/components/u-poster/u-poster.vue +236 -219
- package/components/u-qrcode/qrcode.js +56 -49
- package/components/u-qrcode/u-qrcode.vue +159 -88
- package/components/u-scroll-list/scrollWxs.wxs +1 -1
- package/components/u-slider/u-slider.vue +1 -1
- package/components/u-swipe-action-item/index.wxs +43 -25
- package/components/u-swipe-action-item/nvue.js +9 -0
- package/components/u-swipe-action-item/other.js +32 -21
- package/components/u-swipe-action-item/props.js +5 -0
- package/components/u-swipe-action-item/swipeActionItem.js +1 -0
- package/components/u-swipe-action-item/u-swipe-action-item.vue +28 -4
- package/components/u-switch/u-switch.vue +1 -1
- package/components/u-tabbar/u-tabbar.vue +2 -1
- package/components/u-tabbar-item/u-tabbar-item.vue +64 -21
- package/components/u-tabs/u-tabs.vue +11 -8
- package/components/u-tabs-pro/u-tabs-pro.vue +212 -0
- package/components/u-text/text.js +1 -1
- package/components/u-text/u-text.vue +18 -6
- package/components/u-upload/u-upload.vue +1 -1
- package/components/u-waterfall/u-waterfall.vue +118 -65
- package/libs/config/config.js +1 -1
- package/libs/config/props.js +1 -0
- package/libs/function/index.js +66 -0
- package/libs/mixin/mixin.js +4 -50
- package/libs/root/index.js +78 -5
- package/libs/root/page.js +7 -7
- package/libs/root/root.js +73 -3
- package/libs/util/app-nvue-webview-canvas.js +486 -0
- package/libs/util/gcanvas/bridge/bridge-weex.js +0 -2
- package/libs/util/gcanvas/context-2d/FillStyleLinearGradient.js +0 -0
- package/libs/util/gcanvas/context-2d/FillStylePattern.js +0 -0
- package/libs/util/gcanvas/context-2d/FillStyleRadialGradient.js +0 -0
- package/libs/util/gcanvas/context-2d/RenderingContext.js +0 -0
- package/libs/util/gcanvas/context-webgl/ActiveInfo.js +0 -0
- package/libs/util/gcanvas/context-webgl/Buffer.js +0 -0
- package/libs/util/gcanvas/context-webgl/Framebuffer.js +0 -0
- package/libs/util/gcanvas/context-webgl/GLenum.js +0 -0
- package/libs/util/gcanvas/context-webgl/GLmethod.js +0 -0
- package/libs/util/gcanvas/context-webgl/GLtype.js +0 -0
- package/libs/util/gcanvas/context-webgl/Program.js +0 -0
- package/libs/util/gcanvas/context-webgl/Renderbuffer.js +0 -0
- package/libs/util/gcanvas/context-webgl/RenderingContext.js +0 -0
- package/libs/util/gcanvas/context-webgl/Shader.js +0 -0
- package/libs/util/gcanvas/context-webgl/ShaderPrecisionFormat.js +0 -0
- package/libs/util/gcanvas/context-webgl/Texture.js +0 -0
- package/libs/util/gcanvas/context-webgl/UniformLocation.js +0 -0
- package/libs/util/gcanvas/context-webgl/classUtils.js +0 -0
- package/libs/util/gcanvas/env/canvas.js +0 -0
- package/libs/util/gcanvas/env/image.js +0 -0
- package/libs/util/gcanvas/env/tool.js +0 -0
- package/libs/util/gcanvas/index.js +3 -3
- package/package.json +1 -1
- package/types/comps/swipeActionItem.d.ts +13 -0
- package/types/comps/tabs.d.ts +2 -1
- package/types/comps/text.d.ts +1 -1
- package/types/func.d.ts +23 -0
- package/types/index.d.ts +1 -0
|
@@ -92,10 +92,14 @@
|
|
|
92
92
|
return {
|
|
93
93
|
columnList: [[]], // 存储每列的数据
|
|
94
94
|
children: [],
|
|
95
|
-
// 用于标记是否已经初始化
|
|
96
|
-
initialized: false,
|
|
97
|
-
windowWidth: 375,
|
|
98
|
-
windowHeight: 0
|
|
95
|
+
// 用于标记是否已经初始化
|
|
96
|
+
initialized: false,
|
|
97
|
+
windowWidth: 375,
|
|
98
|
+
windowHeight: 0,
|
|
99
|
+
distributionQueue: [],
|
|
100
|
+
distributionRunning: false,
|
|
101
|
+
distributionPromise: null,
|
|
102
|
+
distributionGeneration: 0
|
|
99
103
|
}
|
|
100
104
|
},
|
|
101
105
|
watch: {
|
|
@@ -107,22 +111,27 @@
|
|
|
107
111
|
if (this.columnList.length == 1) {
|
|
108
112
|
this.initColumnList()
|
|
109
113
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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));
|
|
114
122
|
}
|
|
115
123
|
},
|
|
116
124
|
immediate: true
|
|
117
125
|
},
|
|
118
|
-
columns: {
|
|
119
|
-
handler() {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
+
columns: {
|
|
127
|
+
handler() {
|
|
128
|
+
// 重新分配数据
|
|
129
|
+
if (this.copyFlowList.length > 0) {
|
|
130
|
+
this.redistributeData(this.copyFlowList);
|
|
131
|
+
} else {
|
|
132
|
+
this.clear(false);
|
|
133
|
+
}
|
|
134
|
+
},
|
|
126
135
|
immediate: false
|
|
127
136
|
}
|
|
128
137
|
},
|
|
@@ -210,73 +219,115 @@
|
|
|
210
219
|
const newColumnsCount = this.getColumnsCount();
|
|
211
220
|
const oldColumnsCount = this.columnList.length;
|
|
212
221
|
|
|
213
|
-
// 只有列数发生变化时才重新分配数据
|
|
214
|
-
if (newColumnsCount !== oldColumnsCount) {
|
|
215
|
-
this.redistributeData();
|
|
216
|
-
}
|
|
217
|
-
}, 300);
|
|
218
|
-
},
|
|
219
|
-
|
|
220
|
-
// 重新分配所有数据
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if (!newData || newData.length
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
222
|
+
// 只有列数发生变化时才重新分配数据
|
|
223
|
+
if (newColumnsCount !== oldColumnsCount) {
|
|
224
|
+
this.redistributeData(this.copyFlowList);
|
|
225
|
+
}
|
|
226
|
+
}, 300);
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
// 重新分配所有数据
|
|
230
|
+
redistributeData(data = this.copyFlowList) {
|
|
231
|
+
this.clear(false);
|
|
232
|
+
// 保存所有数据
|
|
233
|
+
const allData = this.cloneData(data || []);
|
|
234
|
+
// 重新分配数据
|
|
235
|
+
return this.handleData(allData);
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
// 判断新数据是否只在原数组末尾追加
|
|
239
|
+
isPureAppend(newData, oldData) {
|
|
240
|
+
if (!Array.isArray(oldData) || oldData.length === 0) return true;
|
|
241
|
+
if (!Array.isArray(newData) || newData.length < oldData.length) return false;
|
|
242
|
+
return oldData.every((item, index) => {
|
|
243
|
+
return JSON.stringify(item) === JSON.stringify(newData[index]);
|
|
244
|
+
});
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
// 将新增数据加入共享队列,确保只有一个分配循环运行
|
|
248
|
+
handleData(newData) {
|
|
249
|
+
if (!newData || newData.length === 0) {
|
|
250
|
+
return this.distributionPromise || Promise.resolve();
|
|
251
|
+
}
|
|
252
|
+
this.distributionQueue.push({
|
|
253
|
+
generation: this.distributionGeneration,
|
|
254
|
+
data: this.cloneData(newData)
|
|
255
|
+
});
|
|
256
|
+
if (!this.distributionRunning) {
|
|
257
|
+
this.distributionPromise = this.runDistributionQueue();
|
|
258
|
+
}
|
|
259
|
+
return this.distributionPromise;
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
// 串行消费所有待分配数据
|
|
263
|
+
async runDistributionQueue() {
|
|
264
|
+
if (this.distributionRunning) return;
|
|
265
|
+
this.distributionRunning = true;
|
|
266
|
+
try {
|
|
267
|
+
while (this.distributionQueue.length > 0) {
|
|
268
|
+
const task = this.distributionQueue.shift();
|
|
269
|
+
if (task.generation !== this.distributionGeneration) continue;
|
|
270
|
+
await this.distributeData(task.data, task.generation);
|
|
271
|
+
}
|
|
272
|
+
} finally {
|
|
273
|
+
this.distributionRunning = false;
|
|
274
|
+
this.distributionPromise = null;
|
|
275
|
+
if (this.distributionQueue.length > 0) {
|
|
276
|
+
this.distributionPromise = this.runDistributionQueue();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
|
|
281
|
+
// 逐项测量并分配数据,代数变化时立即退出
|
|
282
|
+
async distributeData(newData, generation) {
|
|
283
|
+
let columnHeights = new Array(this.columnList.length).fill(0);
|
|
284
|
+
for (const item of newData) {
|
|
285
|
+
if (generation !== this.distributionGeneration) return;
|
|
286
|
+
columnHeights = await this.getColumnHeights();
|
|
287
|
+
if (generation !== this.distributionGeneration) return;
|
|
288
|
+
|
|
250
289
|
const minHeightIndex = this.getMinHeightColumnIndex(columnHeights);
|
|
251
|
-
// console.log('this.columnList', this.columnList)
|
|
252
290
|
this.columnList[minHeightIndex].push(item);
|
|
253
291
|
|
|
254
|
-
// 获取实际渲染后的元素高度而不是估算
|
|
255
292
|
await sleep(this.addTime);
|
|
293
|
+
if (generation !== this.distributionGeneration) return;
|
|
256
294
|
await this.$nextTick();
|
|
295
|
+
if (generation !== this.distributionGeneration) return;
|
|
257
296
|
try {
|
|
258
297
|
const rect = await this.$uGetRect(`#u-column-${minHeightIndex}`);
|
|
259
|
-
|
|
298
|
+
if (generation !== this.distributionGeneration) return;
|
|
260
299
|
if (rect.height) {
|
|
261
300
|
columnHeights[minHeightIndex] = rect.height;
|
|
262
|
-
// 加载一个后置事件
|
|
263
301
|
this.$emit('after-add-one', {
|
|
264
302
|
...item,
|
|
265
303
|
height: rect.height
|
|
266
304
|
});
|
|
267
305
|
}
|
|
268
306
|
} catch (e) {
|
|
269
|
-
//
|
|
270
|
-
// columnHeights[i] = 0;
|
|
307
|
+
// 获取不到列高时,下一个元素会重新测量所有列
|
|
271
308
|
}
|
|
272
309
|
}
|
|
273
|
-
|
|
274
|
-
this.$emit('after-add-all', {
|
|
275
|
-
columnHeights: columnHeights,
|
|
310
|
+
if (generation !== this.distributionGeneration) return;
|
|
311
|
+
this.$emit('after-add-all', {
|
|
312
|
+
columnHeights: columnHeights,
|
|
276
313
|
newData: newData
|
|
277
314
|
});
|
|
278
315
|
},
|
|
279
316
|
|
|
317
|
+
// 获取当前所有列的真实高度
|
|
318
|
+
async getColumnHeights() {
|
|
319
|
+
const columnHeights = new Array(this.columnList.length).fill(0);
|
|
320
|
+
for (let i = 0; i < this.columnList.length; i++) {
|
|
321
|
+
try {
|
|
322
|
+
const rect = await this.$uGetRect(`#u-column-${i}`);
|
|
323
|
+
columnHeights[i] = rect.height || 0;
|
|
324
|
+
} catch (e) {
|
|
325
|
+
columnHeights[i] = 0;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return columnHeights;
|
|
329
|
+
},
|
|
330
|
+
|
|
280
331
|
// 获取最短列;高度相同或暂不可测时按列数据量打散,避免全部落到第一列
|
|
281
332
|
getMinHeightColumnIndex(columnHeights) {
|
|
282
333
|
let minIndex = 0;
|
|
@@ -301,9 +352,11 @@
|
|
|
301
352
|
return JSON.parse(JSON.stringify(data));
|
|
302
353
|
},
|
|
303
354
|
|
|
304
|
-
// 清空数据列表
|
|
305
|
-
clear(bak = true) {
|
|
306
|
-
this.
|
|
355
|
+
// 清空数据列表
|
|
356
|
+
clear(bak = true) {
|
|
357
|
+
this.distributionGeneration += 1;
|
|
358
|
+
this.distributionQueue.splice(0);
|
|
359
|
+
this.initColumnList();
|
|
307
360
|
// 同时清除父组件列表中的数据
|
|
308
361
|
if (bak) {
|
|
309
362
|
// #ifdef VUE2
|
package/libs/config/config.js
CHANGED
package/libs/config/props.js
CHANGED
package/libs/function/index.js
CHANGED
|
@@ -5,6 +5,71 @@ import {
|
|
|
5
5
|
} from './test.js'
|
|
6
6
|
import { round } from './digit.js'
|
|
7
7
|
import config from '../config/config.js'
|
|
8
|
+
|
|
9
|
+
function emptyNodeInfo() {
|
|
10
|
+
return {
|
|
11
|
+
width: 0,
|
|
12
|
+
height: 0,
|
|
13
|
+
left: 0,
|
|
14
|
+
right: 0,
|
|
15
|
+
top: 0,
|
|
16
|
+
bottom: 0
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// #ifdef APP-NVUE
|
|
21
|
+
const dom = (typeof uni !== 'undefined' && uni && typeof uni.requireNativePlugin === 'function')
|
|
22
|
+
? uni.requireNativePlugin('dom')
|
|
23
|
+
: null
|
|
24
|
+
|
|
25
|
+
function getNvueRect(ref) {
|
|
26
|
+
return new Promise((resolve) => {
|
|
27
|
+
if (!dom || !ref) {
|
|
28
|
+
resolve(emptyNodeInfo())
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
dom.getComponentRect(ref, (res) => {
|
|
32
|
+
resolve(res && res.size ? res.size : emptyNodeInfo())
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
// #endif
|
|
37
|
+
|
|
38
|
+
// 查询节点信息
|
|
39
|
+
export function upGetRect(selector, all = false, comp = null) {
|
|
40
|
+
return new Promise((resolve) => {
|
|
41
|
+
// #ifndef APP-NVUE
|
|
42
|
+
const query = uni.createSelectorQuery()
|
|
43
|
+
const scopedQuery = comp ? query.in(comp) : query
|
|
44
|
+
scopedQuery[all ? 'selectAll' : 'select'](selector)
|
|
45
|
+
.boundingClientRect((rect) => {
|
|
46
|
+
if (all) {
|
|
47
|
+
resolve(Array.isArray(rect) ? rect : [])
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
resolve(rect || emptyNodeInfo())
|
|
51
|
+
})
|
|
52
|
+
.exec()
|
|
53
|
+
// #endif
|
|
54
|
+
|
|
55
|
+
// #ifdef APP-NVUE
|
|
56
|
+
sleep(30).then(async () => {
|
|
57
|
+
const refs = comp?.$refs || comp?.proxy?.$refs || comp?.refs || {}
|
|
58
|
+
const selectorRef = refs[selector.substring(1)]
|
|
59
|
+
if (all) {
|
|
60
|
+
const selectorRefs = Array.isArray(selectorRef)
|
|
61
|
+
? selectorRef
|
|
62
|
+
: selectorRef ? [selectorRef] : []
|
|
63
|
+
resolve(await Promise.all(selectorRefs.map(ref => getNvueRect(ref))))
|
|
64
|
+
return
|
|
65
|
+
}
|
|
66
|
+
const ref = Array.isArray(selectorRef) ? selectorRef[0] : selectorRef
|
|
67
|
+
resolve(await getNvueRect(ref))
|
|
68
|
+
})
|
|
69
|
+
// #endif
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
8
73
|
/**
|
|
9
74
|
* @description 如果value小于min,取min;如果value大于max,取max
|
|
10
75
|
* @param {number} min
|
|
@@ -841,6 +906,7 @@ function hslToHex(h, s, l) {
|
|
|
841
906
|
}
|
|
842
907
|
|
|
843
908
|
export default {
|
|
909
|
+
upGetRect,
|
|
844
910
|
range,
|
|
845
911
|
getPx,
|
|
846
912
|
sleep,
|
package/libs/mixin/mixin.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineMixin } from '../vue'
|
|
2
|
-
import { deepMerge, $parent,
|
|
2
|
+
import { deepMerge, $parent, upGetRect } from '../function/index'
|
|
3
3
|
import test from '../function/test'
|
|
4
4
|
import route from '../util/route'
|
|
5
5
|
import {
|
|
@@ -12,13 +12,6 @@ import {
|
|
|
12
12
|
getThemeVarsForStyle,
|
|
13
13
|
syncThemeRuntimeFromStorage
|
|
14
14
|
} from '../theme/runtime'
|
|
15
|
-
// #ifdef APP-NVUE
|
|
16
|
-
// 由于weex为阿里的KPI业绩考核的产物,所以不支持百分比单位,这里需要通过dom查询组件的宽度
|
|
17
|
-
const dom = (typeof uni !== 'undefined' && uni && typeof uni.requireNativePlugin === 'function')
|
|
18
|
-
? uni.requireNativePlugin('dom')
|
|
19
|
-
: null
|
|
20
|
-
// #endif
|
|
21
|
-
|
|
22
15
|
export const mixin = defineMixin({
|
|
23
16
|
// 定义每个组件都可能需要用到的外部样式以及类名
|
|
24
17
|
props: {
|
|
@@ -49,7 +42,7 @@ export const mixin = defineMixin({
|
|
|
49
42
|
}
|
|
50
43
|
},
|
|
51
44
|
onLoad() {
|
|
52
|
-
// getRect
|
|
45
|
+
// 保留 uni.$u.getRect 兼容入口
|
|
53
46
|
this.upBindGetRect()
|
|
54
47
|
this.upInitThemeVersion()
|
|
55
48
|
if (this.upIsPageScope()) {
|
|
@@ -223,47 +216,8 @@ export const mixin = defineMixin({
|
|
|
223
216
|
navTo(url = '', linkType = 'navigateTo') {
|
|
224
217
|
route({ type: this.linkType, url })
|
|
225
218
|
},
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
// 解决办法为在组件根部再套一个没有任何作用的view元素
|
|
229
|
-
$uGetRect(selector, all) {
|
|
230
|
-
return new Promise((resolve) => {
|
|
231
|
-
// #ifndef APP-NVUE
|
|
232
|
-
uni.createSelectorQuery()
|
|
233
|
-
.in(this)[all ? 'selectAll' : 'select'](selector)
|
|
234
|
-
.boundingClientRect((rect) => {
|
|
235
|
-
if (all && Array.isArray(rect) && rect.length) {
|
|
236
|
-
resolve(rect)
|
|
237
|
-
}
|
|
238
|
-
if (!all && rect) {
|
|
239
|
-
resolve(rect)
|
|
240
|
-
}
|
|
241
|
-
})
|
|
242
|
-
.exec()
|
|
243
|
-
// #endif
|
|
244
|
-
|
|
245
|
-
// #ifdef APP-NVUE
|
|
246
|
-
sleep(30).then(() => {
|
|
247
|
-
let selectorNvue = selector.substring(1) // 去掉开头的#或者.
|
|
248
|
-
let selectorRef = this.$refs[selectorNvue]
|
|
249
|
-
if (!selectorRef) {
|
|
250
|
-
// console.log('不存在元素,请检查是否设置了ref属性' + selectorNvue + '。')
|
|
251
|
-
resolve({
|
|
252
|
-
with: 0,
|
|
253
|
-
height: 0,
|
|
254
|
-
left: 0,
|
|
255
|
-
right: 0,
|
|
256
|
-
top: 0,
|
|
257
|
-
bottom: 0
|
|
258
|
-
})
|
|
259
|
-
}
|
|
260
|
-
dom.getComponentRect(selectorRef, res => {
|
|
261
|
-
// console.log(res)
|
|
262
|
-
resolve(res.size)
|
|
263
|
-
})
|
|
264
|
-
})
|
|
265
|
-
// #endif
|
|
266
|
-
})
|
|
219
|
+
$uGetRect(selector, all = false) {
|
|
220
|
+
return upGetRect(selector, all, this)
|
|
267
221
|
},
|
|
268
222
|
getParentData(parentName = '') {
|
|
269
223
|
// 避免在created中去定义parent变量
|
package/libs/root/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { dirname, relative, resolve } from 'node:path'
|
|
2
2
|
import { fileURLToPath } from 'node:url'
|
|
3
3
|
import process from 'node:process'
|
|
4
|
-
import { existsSync, mkdirSync, statSync, writeFileSync } from 'node:fs'
|
|
4
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'
|
|
5
5
|
|
|
6
6
|
import { createFilter, normalizePath } from 'vite'
|
|
7
7
|
|
|
@@ -10,6 +10,12 @@ import { rebuildUpApp, registerUpApp } from './root.js'
|
|
|
10
10
|
import { loadPagesJson, normalizePlatformPath, toArray } from './utils.js'
|
|
11
11
|
|
|
12
12
|
const rootLibPath = normalizePath(dirname(fileURLToPath(import.meta.url)))
|
|
13
|
+
const appStaticIconFontRelativePath = 'static/app-plus/uview-plus/upicon.ttf'
|
|
14
|
+
const appStaticIconFontFlag = 'const useAppStaticIconFont = false;'
|
|
15
|
+
const appStaticIconFontEnabledFlag = 'const useAppStaticIconFont = true;'
|
|
16
|
+
const appRemoteIconFontCondition = /\/\*\s*#ifdef\s+APP\s+\|\|\s+(MP-QQ\s+\|\|\s+MP-TOUTIAO\s+\|\|\s+MP-BAIDU\s+\|\|\s+MP-KUAISHOU\s+\|\|\s+MP-XHS)\s*\*\//
|
|
17
|
+
const appCompiledRemoteIconFontFace = /[ \t]*(?:\/\/[^\n]*\n[ \t]*)?@font-face\s*\{[^{}]*font-family:\s*['"]?uicon-iconfont['"]?;?[^{}]*at\.alicdn\.com\/t\/font_2225171[^{}]*\}\s*/
|
|
18
|
+
const appCompiledRemoteIconFontFaceGlobal = /[ \t]*(?:\/\/[^\n]*\n[ \t]*)?@font-face\s*\{[^{}]*font-family:\s*['"]?uicon-iconfont['"]?;?[^{}]*at\.alicdn\.com\/t\/font_2225171[^{}]*\}\s*/g
|
|
13
19
|
|
|
14
20
|
export default function UniUpRoot(options = {}) {
|
|
15
21
|
const rootOptions = {
|
|
@@ -53,7 +59,10 @@ export default function UniUpRoot(options = {}) {
|
|
|
53
59
|
const rootPath = normalizePath(projectInfo.rootPath)
|
|
54
60
|
const appUpPath = normalizePath(resolve(rootPath, `${rootFileName}.vue`))
|
|
55
61
|
const rootToastHostPath = normalizePath(resolve(rootLibPath, 'root-toast-host.vue'))
|
|
56
|
-
const
|
|
62
|
+
const iconFontSourcePath = normalizePath(resolve(rootLibPath, '../../components/u-icon/upicon.ttf'))
|
|
63
|
+
const appStaticIconFontPath = normalizePath(resolve(rootPath, appStaticIconFontRelativePath))
|
|
64
|
+
const uIconUtilPath = normalizePath(resolve(rootPath, 'uni_modules/uview-plus/components/u-icon/util.js'))
|
|
65
|
+
const uIconVuePath = normalizePath(resolve(rootPath, 'uni_modules/uview-plus/components/u-icon/u-icon.vue'))
|
|
57
66
|
const themeRuntimePath = normalizePath(resolve(rootPath, 'uni_modules/uview-plus/libs/theme/runtime.js'))
|
|
58
67
|
const pagesPath = normalizePath(resolve(rootPath, 'pages.json'))
|
|
59
68
|
const excludedPaths = toArray(rootOptions.excludePages)
|
|
@@ -90,6 +99,51 @@ export default function UniUpRoot(options = {}) {
|
|
|
90
99
|
writeFileSync(appUpPath, defaultRootSfc, 'utf-8')
|
|
91
100
|
}
|
|
92
101
|
|
|
102
|
+
const shouldCopyFile = (sourcePath, targetPath) => {
|
|
103
|
+
if (!existsSync(targetPath)) return true
|
|
104
|
+
if (statSync(sourcePath).size !== statSync(targetPath).size) return true
|
|
105
|
+
return !readFileSync(sourcePath).equals(readFileSync(targetPath))
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const ensureAppStaticIconFont = () => {
|
|
109
|
+
if (process.env.UNI_PLATFORM !== 'app') return
|
|
110
|
+
if (!existsSync(iconFontSourcePath)) {
|
|
111
|
+
throw new Error(`uview-plus built-in icon font is missing: ${iconFontSourcePath}`)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
mkdirSync(dirname(appStaticIconFontPath), { recursive: true })
|
|
115
|
+
if (shouldCopyFile(iconFontSourcePath, appStaticIconFontPath)) {
|
|
116
|
+
copyFileSync(iconFontSourcePath, appStaticIconFontPath)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const removeAppCompiledRemoteIconFontFace = (code) => code.replace(appCompiledRemoteIconFontFaceGlobal, '')
|
|
121
|
+
|
|
122
|
+
const transformAppStaticIconFont = (code, cleanId) => {
|
|
123
|
+
if (process.env.UNI_PLATFORM !== 'app') return null
|
|
124
|
+
if (cleanId === uIconUtilPath && code.includes(appStaticIconFontFlag)) {
|
|
125
|
+
return code.replace(appStaticIconFontFlag, appStaticIconFontEnabledFlag)
|
|
126
|
+
}
|
|
127
|
+
if (cleanId === uIconVuePath && appRemoteIconFontCondition.test(code)) {
|
|
128
|
+
return code.replace(appRemoteIconFontCondition, '/* #ifdef $1 */')
|
|
129
|
+
}
|
|
130
|
+
if (cleanId === uIconVuePath && appCompiledRemoteIconFontFace.test(code)) {
|
|
131
|
+
return removeAppCompiledRemoteIconFontFace(code)
|
|
132
|
+
}
|
|
133
|
+
return null
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const removeAppRemoteIconFontFaceFromCssAssets = (bundle) => {
|
|
137
|
+
if (process.env.UNI_PLATFORM !== 'app') return
|
|
138
|
+
Object.values(bundle).forEach((asset) => {
|
|
139
|
+
if (asset.type !== 'asset') return
|
|
140
|
+
if (!asset.fileName.endsWith('.css')) return
|
|
141
|
+
if (typeof asset.source !== 'string') return
|
|
142
|
+
if (!appCompiledRemoteIconFontFace.test(asset.source)) return
|
|
143
|
+
asset.source = removeAppCompiledRemoteIconFontFace(asset.source)
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
|
|
93
147
|
const refreshPagesJson = () => {
|
|
94
148
|
if (!existsSync(pagesPath)) return
|
|
95
149
|
const mtimeMs = statSync(pagesPath).mtimeMs
|
|
@@ -101,10 +155,16 @@ export default function UniUpRoot(options = {}) {
|
|
|
101
155
|
return {
|
|
102
156
|
name: 'vite-plugin-uni-up-root',
|
|
103
157
|
enforce: 'pre',
|
|
104
|
-
configResolved(
|
|
158
|
+
configResolved(config) {
|
|
159
|
+
const { plugins } = config
|
|
105
160
|
hasPlatformPlugin = plugins.some(v => v.name === 'vite-plugin-uni-platform')
|
|
161
|
+
if (plugins.some(v => v.name === 'uni:app-nvue')) {
|
|
162
|
+
config.build.rollupOptions = config.build.rollupOptions || {}
|
|
163
|
+
config.build.rollupOptions.treeshake = false
|
|
164
|
+
}
|
|
106
165
|
},
|
|
107
166
|
buildStart() {
|
|
167
|
+
ensureAppStaticIconFont()
|
|
108
168
|
ensureRootFile()
|
|
109
169
|
refreshPagesJson()
|
|
110
170
|
},
|
|
@@ -113,6 +173,14 @@ export default function UniUpRoot(options = {}) {
|
|
|
113
173
|
const isSfcBlock = id.includes('?')
|
|
114
174
|
const cleanId = normalizePath(id.split('?')[0])
|
|
115
175
|
|
|
176
|
+
const iconFontCode = transformAppStaticIconFont(code, cleanId)
|
|
177
|
+
if (iconFontCode) {
|
|
178
|
+
return {
|
|
179
|
+
code: iconFontCode,
|
|
180
|
+
map: null,
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
116
184
|
const filterMain = createFilter(mainFiles)
|
|
117
185
|
if (filterMain(cleanId)) {
|
|
118
186
|
ms = await registerUpApp(code, rootFileName, getRelativeImportPath(cleanId, rootToastHostPath))
|
|
@@ -120,7 +188,9 @@ export default function UniUpRoot(options = {}) {
|
|
|
120
188
|
|
|
121
189
|
const filterUpRoot = createFilter(appUpPath)
|
|
122
190
|
if (filterUpRoot(cleanId)) {
|
|
123
|
-
ms = await rebuildUpApp(code, rootOptions.enabledVirtualHost
|
|
191
|
+
ms = await rebuildUpApp(code, rootOptions.enabledVirtualHost, {
|
|
192
|
+
rootToastHostImportPath: getRelativeImportPath(cleanId, rootToastHostPath)
|
|
193
|
+
})
|
|
124
194
|
}
|
|
125
195
|
|
|
126
196
|
refreshPagesJson()
|
|
@@ -130,7 +200,7 @@ export default function UniUpRoot(options = {}) {
|
|
|
130
200
|
if (cleanId.endsWith('.nvue')) {
|
|
131
201
|
ms = await transformNvuePage(
|
|
132
202
|
code,
|
|
133
|
-
getRelativeImportPath(cleanId,
|
|
203
|
+
getRelativeImportPath(cleanId, appUpPath),
|
|
134
204
|
getRelativeImportPath(cleanId, themeRuntimePath),
|
|
135
205
|
rootOptions.enabledGlobalRef
|
|
136
206
|
)
|
|
@@ -147,5 +217,8 @@ export default function UniUpRoot(options = {}) {
|
|
|
147
217
|
}
|
|
148
218
|
return null
|
|
149
219
|
},
|
|
220
|
+
generateBundle(_, bundle) {
|
|
221
|
+
removeAppRemoteIconFontFaceFromCssAssets(bundle)
|
|
222
|
+
},
|
|
150
223
|
}
|
|
151
224
|
}
|
package/libs/root/page.js
CHANGED
|
@@ -53,11 +53,11 @@ export async function transformPage(code, enabledGlobalRef = false) {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
function ensureOptionsComponent(ms, scriptContent) {
|
|
56
|
-
if (scriptContent.includes('
|
|
56
|
+
if (scriptContent.includes('AppUpRoot')) return
|
|
57
57
|
|
|
58
58
|
const componentsMatch = scriptContent.match(/components\s*:\s*\{/)
|
|
59
59
|
if (componentsMatch) {
|
|
60
|
-
ms.appendLeft(componentsMatch.index + componentsMatch[0].length, '
|
|
60
|
+
ms.appendLeft(componentsMatch.index + componentsMatch[0].length, ' AppUpRoot,')
|
|
61
61
|
return
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -65,7 +65,7 @@ function ensureOptionsComponent(ms, scriptContent) {
|
|
|
65
65
|
if (exportDefaultMatch) {
|
|
66
66
|
ms.appendLeft(
|
|
67
67
|
exportDefaultMatch.index + exportDefaultMatch[0].length,
|
|
68
|
-
'\n components: {
|
|
68
|
+
'\n components: { AppUpRoot },'
|
|
69
69
|
)
|
|
70
70
|
}
|
|
71
71
|
}
|
|
@@ -89,7 +89,7 @@ function ensureOptionsThemeMixin(ms, scriptContent) {
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
function getScriptSetupImports(componentImportPath, runtimeImportPath) {
|
|
92
|
-
return `import
|
|
92
|
+
return `import AppUpRoot from '${componentImportPath}'
|
|
93
93
|
import { computed as __upComputed, onBeforeUnmount as __upOnBeforeUnmount, onMounted as __upOnMounted, ref as __upRef } from 'vue'
|
|
94
94
|
import { onShow as __upOnShow } from '@dcloudio/uni-app'
|
|
95
95
|
import {
|
|
@@ -161,7 +161,7 @@ const upThemeNavBgColor = __upComputed(() => {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
function getOptionsImports(componentImportPath, runtimeImportPath) {
|
|
164
|
-
return `import
|
|
164
|
+
return `import AppUpRoot from '${componentImportPath}'
|
|
165
165
|
import {
|
|
166
166
|
applyNativeThemeUI as __upApplyNativeThemeUI,
|
|
167
167
|
applyNativeThemeUIDeferred as __upApplyNativeThemeUIDeferred,
|
|
@@ -251,7 +251,7 @@ export async function transformNvuePage(
|
|
|
251
251
|
const sfc = await parseSFC(code)
|
|
252
252
|
const ms = new MagicString(code)
|
|
253
253
|
|
|
254
|
-
wrapTemplate(ms, sfc, '
|
|
254
|
+
wrapTemplate(ms, sfc, 'AppUpRoot', getPageRootRefSource(sfc, enabledGlobalRef), true)
|
|
255
255
|
|
|
256
256
|
if (sfc.scriptSetup) {
|
|
257
257
|
ms.appendLeft(sfc.scriptSetup.loc.start.offset, getScriptSetupImports(componentImportPath, runtimeImportPath))
|
|
@@ -261,7 +261,7 @@ export async function transformNvuePage(
|
|
|
261
261
|
ensureOptionsThemeMixin(ms, sfc.script.content)
|
|
262
262
|
} else {
|
|
263
263
|
ms.append(
|
|
264
|
-
`\n<script>\n${getOptionsImports(componentImportPath, runtimeImportPath)}export default {\n components: {
|
|
264
|
+
`\n<script>\n${getOptionsImports(componentImportPath, runtimeImportPath)}export default {\n components: { AppUpRoot },\n mixins: [__upNvueThemeMixin]\n}\n</script>\n`
|
|
265
265
|
)
|
|
266
266
|
}
|
|
267
267
|
|