uview-plus 3.7.0 → 3.7.13
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 +40 -0
- package/components/u-action-sheet/actionSheet.js +2 -0
- package/components/u-action-sheet/props.js +10 -0
- package/components/u-action-sheet/u-action-sheet.vue +3 -3
- package/components/u-box/box.js +24 -0
- package/components/u-box/props.js +37 -7
- package/components/u-box/u-box.vue +29 -14
- package/components/u-canvas/u-canvas.vue +301 -24
- package/components/u-checkbox-group/u-checkbox-group.vue +4 -1
- package/components/u-qrcode/u-qrcode.vue +1 -1
- package/components/u-select/u-select.vue +3 -0
- package/components/u-signature/u-signature.vue +137 -137
- package/components/u-slider/props.js +17 -2
- package/components/u-slider/slider.js +6 -3
- package/components/u-slider/u-slider.vue +112 -35
- package/components/u-tabs/u-tabs.vue +83 -95
- package/libs/css/flex.scss +2 -1
- package/package.json +1 -3
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<view class="u-signature">
|
|
3
|
-
<view class="u-signature__canvas-wrap">
|
|
4
|
-
<canvas
|
|
5
|
-
|
|
6
|
-
:canvas-id="canvasId"
|
|
7
|
-
:
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
<view class="u-signature__canvas-wrap" :style="{background: bgColor}">
|
|
4
|
+
<up-canvas
|
|
5
|
+
ref="signatureCanvas"
|
|
6
|
+
:canvas-id="canvasId"
|
|
7
|
+
:width="canvasWidth"
|
|
8
|
+
:height="canvasHeight"
|
|
9
|
+
:bg-color="bgColor"
|
|
10
|
+
@touchstart="touchStart"
|
|
11
|
+
@touchmove="touchMove"
|
|
10
12
|
@touchend="touchEnd"
|
|
13
|
+
:disable-scroll="true"
|
|
14
|
+
class="u-signature__canvas"
|
|
11
15
|
:style="{
|
|
12
16
|
width: canvasWidth + 'px',
|
|
13
17
|
height: canvasHeight + 'px',
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
></canvas>
|
|
18
|
+
}">
|
|
19
|
+
</up-canvas>
|
|
17
20
|
</view>
|
|
18
21
|
|
|
19
22
|
<view v-if="showToolbar" class="u-signature__toolbar">
|
|
@@ -116,7 +119,6 @@
|
|
|
116
119
|
isDrawing: false,
|
|
117
120
|
pathStack: [], // 存储绘制路径用于回退
|
|
118
121
|
currentPath: [], // 当前绘制路径
|
|
119
|
-
ctx: null,
|
|
120
122
|
isEmpty: true,
|
|
121
123
|
presetColors: [
|
|
122
124
|
'#000000', // 黑色
|
|
@@ -130,11 +132,16 @@
|
|
|
130
132
|
],
|
|
131
133
|
showBrushSettings: false,
|
|
132
134
|
showColorSettings: false,
|
|
133
|
-
lastPoint: null // 保存上一个点的坐标
|
|
135
|
+
lastPoint: null, // 保存上一个点的坐标
|
|
136
|
+
canvasInstance: null // 缓存canvas实例
|
|
134
137
|
}
|
|
135
138
|
},
|
|
136
139
|
mounted() {
|
|
137
|
-
|
|
140
|
+
// 初始化时获取canvas实例
|
|
141
|
+
this.$nextTick(() => {
|
|
142
|
+
this.getCanvasInstance();
|
|
143
|
+
this.clearCanvas();
|
|
144
|
+
});
|
|
138
145
|
},
|
|
139
146
|
watch: {
|
|
140
147
|
width: {
|
|
@@ -164,32 +171,40 @@
|
|
|
164
171
|
},
|
|
165
172
|
methods: {
|
|
166
173
|
t,
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
this.
|
|
171
|
-
|
|
172
|
-
|
|
174
|
+
|
|
175
|
+
// 获取签名画布实例
|
|
176
|
+
getCanvasInstance() {
|
|
177
|
+
if (this.canvasInstance) {
|
|
178
|
+
return this.canvasInstance;
|
|
179
|
+
}
|
|
173
180
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
181
|
+
const canvasRef = this.$refs.signatureCanvas;
|
|
182
|
+
if (canvasRef) {
|
|
183
|
+
this.canvasInstance = canvasRef;
|
|
184
|
+
return canvasRef;
|
|
185
|
+
}
|
|
186
|
+
return null;
|
|
177
187
|
},
|
|
178
188
|
|
|
179
189
|
touchStart(e) {
|
|
180
|
-
if (!this.ctx)
|
|
190
|
+
if (!this.canvasInstance || !this.canvasInstance.ctx) {
|
|
191
|
+
this.getCanvasInstance();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (!this.canvasInstance || !this.canvasInstance.ctx) return;
|
|
195
|
+
|
|
196
|
+
this.isDrawing = true;
|
|
197
|
+
this.isEmpty = false;
|
|
198
|
+
this.currentPath = [];
|
|
181
199
|
|
|
182
|
-
|
|
183
|
-
this.isEmpty = false
|
|
184
|
-
this.currentPath = []
|
|
200
|
+
const { x, y } = this.getCanvasPoint(e);
|
|
185
201
|
|
|
186
|
-
|
|
187
|
-
this.
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
this.
|
|
191
|
-
this.
|
|
192
|
-
this.ctx.setLineWidth(this.lineWidth)
|
|
202
|
+
// 设置线条样式
|
|
203
|
+
this.canvasInstance.setLineStyle(this.lineColor, this.lineWidth);
|
|
204
|
+
|
|
205
|
+
// 开始路径
|
|
206
|
+
this.canvasInstance.beginPath();
|
|
207
|
+
this.canvasInstance.moveTo(x, y);
|
|
193
208
|
|
|
194
209
|
// 记录起始点
|
|
195
210
|
this.currentPath.push({
|
|
@@ -198,83 +213,69 @@
|
|
|
198
213
|
type: 'start',
|
|
199
214
|
color: this.lineColor,
|
|
200
215
|
width: this.lineWidth
|
|
201
|
-
})
|
|
216
|
+
});
|
|
202
217
|
|
|
203
218
|
// 保存上一个点
|
|
204
|
-
this.lastPoint = { x, y }
|
|
219
|
+
this.lastPoint = { x, y };
|
|
205
220
|
|
|
206
221
|
// 阻止默认事件以提高性能
|
|
207
|
-
e.preventDefault()
|
|
222
|
+
e.preventDefault();
|
|
208
223
|
},
|
|
209
224
|
|
|
210
225
|
touchMove(e) {
|
|
211
|
-
if (!this.isDrawing || !this.ctx) return
|
|
226
|
+
if (!this.isDrawing || !this.canvasInstance || !this.canvasInstance.ctx) return;
|
|
212
227
|
|
|
213
228
|
// 阻止默认事件以提高性能
|
|
214
|
-
e.preventDefault()
|
|
229
|
+
e.preventDefault();
|
|
215
230
|
|
|
216
|
-
const { x, y } = this.getCanvasPoint(e)
|
|
231
|
+
const { x, y } = this.getCanvasPoint(e);
|
|
217
232
|
|
|
218
|
-
//
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
const t = i / steps
|
|
228
|
-
const midX = this.lastPoint.x + (x - this.lastPoint.x) * t
|
|
229
|
-
const midY = this.lastPoint.y + (y - this.lastPoint.y) * t
|
|
230
|
-
|
|
231
|
-
this.ctx.lineTo(midX, midY)
|
|
232
|
-
this.ctx.stroke()
|
|
233
|
-
this.currentPath.push({
|
|
234
|
-
x: midX,
|
|
235
|
-
y: midY,
|
|
236
|
-
type: 'move'
|
|
237
|
-
})
|
|
238
|
-
}
|
|
239
|
-
} else {
|
|
240
|
-
this.ctx.lineTo(x, y)
|
|
241
|
-
this.ctx.stroke()
|
|
242
|
-
this.currentPath.push({
|
|
243
|
-
x,
|
|
244
|
-
y,
|
|
245
|
-
type: 'move'
|
|
246
|
-
})
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
this.ctx.draw(true)
|
|
233
|
+
// 从上一个点画线到当前点
|
|
234
|
+
this.canvasInstance.lineTo(x, y);
|
|
235
|
+
this.canvasInstance.stroke(); // 实时绘制当前线段
|
|
236
|
+
this.currentPath.push({
|
|
237
|
+
x,
|
|
238
|
+
y,
|
|
239
|
+
type: 'move'
|
|
240
|
+
});
|
|
241
|
+
this.canvasInstance.draw(false);
|
|
250
242
|
|
|
251
243
|
// 更新上一个点
|
|
252
|
-
this.lastPoint = { x, y }
|
|
244
|
+
this.lastPoint = { x, y };
|
|
253
245
|
},
|
|
254
246
|
|
|
255
247
|
touchEnd(e) {
|
|
256
|
-
if (!this.isDrawing || !this.ctx) return
|
|
248
|
+
if (!this.isDrawing || !this.canvasInstance || !this.canvasInstance.ctx) return;
|
|
257
249
|
|
|
258
|
-
this.isDrawing = false
|
|
259
|
-
this.
|
|
260
|
-
this.lastPoint = null
|
|
250
|
+
this.isDrawing = false;
|
|
251
|
+
this.canvasInstance.closePath();
|
|
252
|
+
this.lastPoint = null;
|
|
261
253
|
|
|
262
254
|
// 将当前路径加入栈中用于回退
|
|
263
255
|
if (this.currentPath.length > 0) {
|
|
264
|
-
this.pathStack.push([...this.currentPath])
|
|
256
|
+
this.pathStack.push([...this.currentPath]);
|
|
265
257
|
}
|
|
258
|
+
|
|
259
|
+
// 最后统一执行一次绘制
|
|
260
|
+
this.canvasInstance.draw(true);
|
|
266
261
|
},
|
|
267
262
|
|
|
268
263
|
// 同步获取canvas坐标点(兼容处理)
|
|
269
264
|
getCanvasPoint(e) {
|
|
270
|
-
|
|
271
|
-
const
|
|
265
|
+
// #ifdef MP-WEIXIN
|
|
266
|
+
const touch = e.touches && e.touches[0] ? e.touches[0] : e.mp.touches[0];
|
|
267
|
+
// #endif
|
|
268
|
+
// #ifndef MP-WEIXIN
|
|
269
|
+
const touch = e.touches[0];
|
|
270
|
+
// #endif
|
|
272
271
|
|
|
273
|
-
//
|
|
272
|
+
// 计算相对于canvas的坐标
|
|
273
|
+
// 由于无法直接获取canvas位置,这里简化处理
|
|
274
|
+
// 实际应用中可能需要通过uni.createSelectorQuery获取canvas位置
|
|
274
275
|
return {
|
|
275
276
|
x: touch.x,
|
|
276
277
|
y: touch.y
|
|
277
|
-
}
|
|
278
|
+
};
|
|
278
279
|
},
|
|
279
280
|
|
|
280
281
|
// 选择颜色
|
|
@@ -295,84 +296,83 @@
|
|
|
295
296
|
|
|
296
297
|
// 重新绘制所有路径
|
|
297
298
|
redraw() {
|
|
298
|
-
this.
|
|
299
|
+
if (!this.canvasInstance) {
|
|
300
|
+
this.getCanvasInstance();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (!this.canvasInstance) return;
|
|
304
|
+
|
|
305
|
+
// 先清空画布
|
|
306
|
+
this.canvasInstance.clearCanvas();
|
|
299
307
|
|
|
300
308
|
if (this.pathStack.length === 0) {
|
|
301
|
-
this.isEmpty = true
|
|
302
|
-
return
|
|
309
|
+
this.isEmpty = true;
|
|
310
|
+
return;
|
|
303
311
|
}
|
|
304
312
|
|
|
305
|
-
this.isEmpty = false
|
|
313
|
+
this.isEmpty = false;
|
|
306
314
|
|
|
307
|
-
//
|
|
315
|
+
// 逐个绘制路径
|
|
308
316
|
this.pathStack.forEach(path => {
|
|
309
|
-
if (path.length === 0) return
|
|
317
|
+
if (path.length === 0) return;
|
|
310
318
|
|
|
311
|
-
this.
|
|
312
|
-
this.ctx.setLineCap('round')
|
|
313
|
-
this.ctx.setLineJoin('round')
|
|
319
|
+
this.canvasInstance.beginPath();
|
|
314
320
|
|
|
315
|
-
let lastPoint = null
|
|
321
|
+
let lastPoint = null;
|
|
316
322
|
path.forEach((point, index) => {
|
|
317
323
|
if (index === 0 && point.type === 'start') {
|
|
318
|
-
//
|
|
319
|
-
this.
|
|
320
|
-
this.
|
|
321
|
-
|
|
322
|
-
lastPoint = { x: point.x, y: point.y }
|
|
324
|
+
// 设置线条样式
|
|
325
|
+
this.canvasInstance.setLineStyle(point.color, point.width);
|
|
326
|
+
this.canvasInstance.moveTo(point.x, point.y);
|
|
327
|
+
lastPoint = { x: point.x, y: point.y };
|
|
323
328
|
} else if (point.type === 'move') {
|
|
324
|
-
this.
|
|
325
|
-
lastPoint = { x: point.x, y: point.y }
|
|
329
|
+
this.canvasInstance.lineTo(point.x, point.y);
|
|
330
|
+
lastPoint = { x: point.x, y: point.y };
|
|
326
331
|
}
|
|
327
|
-
})
|
|
328
|
-
|
|
329
|
-
this.
|
|
330
|
-
|
|
331
|
-
})
|
|
332
|
-
// #endif
|
|
333
|
-
},
|
|
334
|
-
|
|
335
|
-
// 清空画布
|
|
336
|
-
clear() {
|
|
337
|
-
this.pathStack = []
|
|
338
|
-
this.currentPath = []
|
|
339
|
-
this.isEmpty = true
|
|
340
|
-
this.lastPoint = null
|
|
341
|
-
this.clearCanvas()
|
|
332
|
+
});
|
|
333
|
+
this.canvasInstance.stroke();
|
|
334
|
+
this.canvasInstance.draw(true);
|
|
335
|
+
});
|
|
342
336
|
},
|
|
343
337
|
|
|
344
338
|
// 清空画布内容
|
|
345
339
|
clearCanvas() {
|
|
346
|
-
if (!this.
|
|
340
|
+
if (!this.canvasInstance) {
|
|
341
|
+
this.getCanvasInstance();
|
|
342
|
+
}
|
|
347
343
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
this.
|
|
351
|
-
this.ctx.draw()
|
|
352
|
-
// #endif
|
|
344
|
+
if (!this.canvasInstance) return;
|
|
345
|
+
|
|
346
|
+
this.canvasInstance.clearCanvas();
|
|
353
347
|
},
|
|
354
348
|
|
|
355
349
|
// 导出签名图片
|
|
356
|
-
exportSignature() {
|
|
357
|
-
if (this.isEmpty)
|
|
350
|
+
async exportSignature() {
|
|
351
|
+
if (this.isEmpty) {
|
|
352
|
+
console.warn('签名为空,无法导出');
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
358
355
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
fileType: 'png',
|
|
363
|
-
quality: 1,
|
|
364
|
-
success: (res) => {
|
|
365
|
-
this.$emit('confirm', res.tempFilePath)
|
|
366
|
-
},
|
|
367
|
-
fail: (err) => {
|
|
368
|
-
this.$emit('error', err)
|
|
369
|
-
}
|
|
370
|
-
}, this)
|
|
371
|
-
// #endif
|
|
356
|
+
if (!this.canvasInstance) {
|
|
357
|
+
this.getCanvasInstance();
|
|
358
|
+
}
|
|
372
359
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
360
|
+
if (!this.canvasInstance) {
|
|
361
|
+
console.error('无法获取画布实例');
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
try {
|
|
366
|
+
// 先重绘整个签名内容
|
|
367
|
+
this.redraw();
|
|
368
|
+
|
|
369
|
+
// 导出图片
|
|
370
|
+
const imagePath = await this.canvasInstance.exportImage('png', 1);
|
|
371
|
+
this.$emit('confirm', imagePath);
|
|
372
|
+
} catch (error) {
|
|
373
|
+
console.error('导出签名图片失败:', error);
|
|
374
|
+
this.$emit('error', error);
|
|
375
|
+
}
|
|
376
376
|
},
|
|
377
377
|
|
|
378
378
|
// 切换笔画设置显示
|
|
@@ -82,7 +82,7 @@ export const props = defineMixin({
|
|
|
82
82
|
type: Boolean,
|
|
83
83
|
default: () => defProps.slider.useNative
|
|
84
84
|
},
|
|
85
|
-
//
|
|
85
|
+
// 滑块厚度
|
|
86
86
|
height: {
|
|
87
87
|
type: String,
|
|
88
88
|
default: () => defProps.slider.height
|
|
@@ -91,5 +91,20 @@ export const props = defineMixin({
|
|
|
91
91
|
type: Object,
|
|
92
92
|
default: () => defProps.slider.innerStyle
|
|
93
93
|
},
|
|
94
|
+
// 是否垂直方向
|
|
95
|
+
vertical: {
|
|
96
|
+
type: Boolean,
|
|
97
|
+
default: defProps.slider.vertical
|
|
98
|
+
},
|
|
99
|
+
// 滑块粗细,为了支持垂直模式下统一粗细参数,用size代替height。
|
|
100
|
+
size: {
|
|
101
|
+
type: [Number, String],
|
|
102
|
+
default: () => defProps.slider.size
|
|
103
|
+
},
|
|
104
|
+
// 滑块长度,水平和垂直模式的长度。
|
|
105
|
+
length: {
|
|
106
|
+
type: [Number, String],
|
|
107
|
+
default: 'auto'
|
|
108
|
+
}
|
|
94
109
|
}
|
|
95
|
-
})
|
|
110
|
+
})
|