uniapp h5端电子签名
由于uniapp h5 canvas touchstart事件不执行,市场上电子签名应用基本上PC端都无法使用。
主要因canvas
标签会被uniapp编译时再套一uni-canvas
。
以下是居于svg控件电子签名解决方案
<template>
<div class="signature-container">
<div
class="signature-pad"
ref="padRef"
@mousedown="startDrawing"
@mousemove="draw"
@mouseup="stopDrawing"
@mouseleave="stopDrawing"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="stopDrawing"
>
<svg
xmlns="http://www.w3.org/2000/svg"
:width="width"
:height="height"
ref="svgRef"
>
<path
v-for="(path, index) in paths"
:key="index"
:d="path.d"
:stroke="path.color"
:stroke-width="path.width"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
<div class="button-group">
<button @click="clearSignature">清除</button>
<button @click="saveSignature">提交</button>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
const padRef = ref(null);
const svgRef = ref(null);
const width = ref(0);
const height = ref(0);
const isDrawing = ref(false);
const currentPath = ref([]);
const paths = ref([]);
// 配置项
const strokeColor = ref('#000000');
const strokeWidth = ref(2);
const emit=defineEmits(['submit']);
onMounted(() => {
resizeSignaturePad();
window.addEventListener('resize', resizeSignaturePad);
});
const resizeSignaturePad = () => {
if (padRef.value) {
width.value = padRef.value.clientWidth;
height.value = padRef.value.clientHeight;
}
};
const startDrawing = (e) => {
isDrawing.value = true;
const point = getPosition(e);
currentPath.value = [{
x: point.x,
y: point.y,
color: strokeColor.value,
width: strokeWidth.value
}];
};
const draw = (e) => {
if (!isDrawing.value) return;
const point = getPosition(e);
currentPath.value.push({
x: point.x,
y: point.y,
color: strokeColor.value,
width: strokeWidth.value
});
// 更新路径数据
updatePaths();
};
const handleTouchStart = (e) => {
e.preventDefault();
startDrawing(e.touches[0]);
};
const handleTouchMove = (e) => {
e.preventDefault();
draw(e.touches[0]);
};
const stopDrawing = () => {
if (!isDrawing.value) return;
isDrawing.value = false;
if (currentPath.value.length > 1) {
paths.value.push({
d: generatePathData(currentPath.value),
color: strokeColor.value,
width: strokeWidth.value
});
}
currentPath.value = [];
};
const getPosition = (e) => {
const rect = padRef.value.getBoundingClientRect();
return {
x: e.clientX - rect.left,
y: e.clientY - rect.top
};
};
const generatePathData = (points) => {
if (points.length === 0) return '';
let d = `M ${points[0].x} ${points[0].y}`;
for (let i = 1; i < points.length; i++) {
d += ` L ${points[i].x} ${points[i].y}`;
}
return d;
};
const updatePaths = () => {
if (currentPath.value.length > 1) {
const tempPaths = [...paths.value];
tempPaths.push({
d: generatePathData(currentPath.value),
color: strokeColor.value,
width: strokeWidth.value
});
paths.value = tempPaths;
}
};
const clearSignature = () => {
paths.value = [];
currentPath.value = [];
};
const saveSignature = () => {
if (paths.value.length === 0) {
alert('请先签名');
return;
}
const svgData = `
<svg xmlns="http://www.w3.org/2000/svg" width="${width.value}" height="${height.value}" viewBox="0 0 ${width.value} ${height.value}">
${paths.value.map(path => `<path d="${path.d}" stroke="${path.color}" stroke-width="${path.width}" fill="none" stroke-linecap="round" stroke-linejoin="round"/>`).join('')}
</svg>
`;
const svgBlob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' });
const svgUrl = URL.createObjectURL(svgBlob);
// 触发保存事件
// emit('submit', {
// // svg: svgData,
// url: svgUrl
// });
// 或者可以直接转换为PNG
convertToPng(svgUrl);
};
// 可选:将SVG转换为PNG
const convertToPng = (svgUrl) => {
const img = new Image();
img.onload = () => {
const canvas = document.createElement('canvas');
canvas.width = width.value;
canvas.height = height.value;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
const pngUrl = canvas.toDataURL('image/png');
emit('submit', pngUrl);
URL.revokeObjectURL(svgUrl);
};
img.src = svgUrl;
};
</script>
<style scoped>
.signature-container {
width: 100%;
max-width: 600px;
margin: 0 auto;
}
.signature-pad {
width: 100%;
height: 300rpx;
border: 1px solid #ddd;
background-color: #f9f9f9;
touch-action: none;
}
svg {
width: 100%;
height: 100%;
display: block;
}
.button-group {
margin-top: 10px;
display: flex;
gap: 10px;
}
button {
padding: 8px 16px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
flex: 1;
}
button:hover {
background-color: #45a049;
}
</style>
uniapp h5端电子签名
https://unnzz.com/archives/jie-jue-uniapp-h5duan-dian-zi