这一版本优化了很多

This commit is contained in:
王利强
2026-06-03 10:16:37 +08:00
parent 8046316216
commit 2af9f1fd59
954 changed files with 58194 additions and 1609 deletions

View File

@@ -3,6 +3,7 @@
<view class="u-signature__canvas-wrap">
<canvas
class="u-signature__canvas"
:id="canvasId"
:canvas-id="canvasId"
:disable-scroll="true"
@touchstart="touchStart"
@@ -130,11 +131,16 @@
],
showBrushSettings: false,
showColorSettings: false,
lastPoint: null // 保存上一个点的坐标
lastPoint: null, // 保存上一个点的坐标
canvasLeft: 0,
canvasTop: 0
}
},
mounted() {
this.initCanvas()
// #ifndef APP-NVUE
setTimeout(() => { this.updateCanvasOffset() }, 100)
// #endif
},
watch: {
width: {
@@ -176,6 +182,7 @@
},
touchStart(e) {
this.updateCanvasOffset()
if (!this.ctx) return
this.isDrawing = true
@@ -262,12 +269,80 @@
if (this.currentPath.length > 0) {
this.pathStack.push([...this.currentPath])
}
this['$emit']('change', this.pathStack)
},
// 动态更新 Canvas 在当前视口下的实时位置偏移,用于高精度计算
updateCanvasOffset() {
// #ifndef APP-NVUE
const query = uni.createSelectorQuery()
query.select('#' + this.canvasId).boundingClientRect(rect => {
if (rect) {
this.canvasLeft = rect.left
this.canvasTop = rect.top
}
}).exec()
// #endif
},
// 同步获取canvas坐标点兼容处理
getCanvasPoint(e) {
// 🌟 1. 100% 微信真机秘籍:优先读取原生 mpEvent 内的 changedTouches它保存了触发本次笔迹移动的那个最精确的触点
const mpTouch = e.mp && e.mp.changedTouches && e.mp.changedTouches[0] ? e.mp.changedTouches[0] : null
const uniTouch = (e.changedTouches && e.changedTouches[0]) || (e.touches && e.touches[0])
const touch = mpTouch || uniTouch
if (!touch) return { x: 0, y: 0 }
// 🌟 2. 直取微信原生和 Uni-App 规范下的相对坐标 x/y直接就是基于 Canvas 左上角,无需任何复杂 selector 视口偏移计算,永无偏差)
if (touch.x !== undefined && touch.y !== undefined && !isNaN(touch.x) && !isNaN(touch.y)) {
return {
x: touch.x,
y: touch.y
}
}
// 🌟 3. 万一由于 Vue3 层层嵌套导致 touch 丢失了相对坐标,我们再启用绝对定位 fallback 偏移作为高精度备用防护
let x = touch.clientX - this.canvasLeft
let y = touch.clientY - this.canvasTop
if (isNaN(x) || x === undefined) x = 0
if (isNaN(y) || y === undefined) y = 0
return {
x: Math.max(0, x),
y: Math.max(0, y)
}
},
getCanvasPointUnused(e) {
const touch = e.touches[0] || e.changedTouches[0]
if (!touch) return { x: 0, y: 0 }
// 1. 优先使用原生组件的相对坐标
if (touch.x !== undefined && touch.y !== undefined && !isNaN(touch.x) && !isNaN(touch.y)) {
return {
x: touch.x,
y: touch.y
}
}
// 2. 针对 iOS 苹果微信小程序(没有 x/y采用视口绝对坐标减去容器视口偏移量计算
let x = touch.clientX - this.canvasLeft
let y = touch.clientY - this.canvasTop
// 3. 严格数据降级保护,绝不容许 NaN 等非法数值污染画布路径,彻底封死放射状黑墨水
if (isNaN(x) || x === undefined) x = 0
if (isNaN(y) || y === undefined) y = 0
return {
x: Math.max(0, x),
y: Math.max(0, y)
}
},
getCanvasPointOld(e) {
const touch = e.touches[0]
const canvas = uni.createSelectorQuery().in(this).select('.u-signature__canvas')
// 移除了高频调用的无用 SelectorQuery 以防止内存泄漏和线程卡顿
// 返回一个包含坐标的对象
return {
@@ -290,6 +365,7 @@
// 重新绘制
this.redraw()
this['$emit']('change', this.pathStack)
},
// 重新绘制所有路径
@@ -338,6 +414,7 @@
this.isEmpty = true
this.lastPoint = null
this.clearCanvas()
this['$emit']('change', this.pathStack)
},
// 清空画布内容