这一版本优化了很多
This commit is contained in:
@@ -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)
|
||||
},
|
||||
|
||||
// 清空画布内容
|
||||
|
||||
Reference in New Issue
Block a user