前言
该组件基于Vue3
<template>
<div>
<el-row>
<el-col v-if="imageBase" :span="6">
<el-image style="width: 120px;" :src="imageBase"></el-image>
</el-col>
<el-col :span="12" style="line-height: 60px">
<el-button type="primary" @click="handleClick">签名</el-button>
</el-col>
</el-row>
<el-dialog title="签名" append-to-body v-model="showSign" width="440">
<canvas id="canvas"
:width="width"
:height="height"
@mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"></canvas>
<el-row>
<el-col>
<el-button type="primary" icon="RefreshLeft" @click="handleQuash">撤销</el-button>
<el-button type="primary" icon="RefreshRight" @click="handleRestore">还原</el-button>
<el-button type="danger" icon="Delete" @click="handleClear">清除</el-button>
<el-button type="success" icon="Check" @click="handleSave">保存</el-button>
</el-col>
</el-row>
</el-dialog>
</div>
</template>
<script setup>
import {getCurrentInstance, ref, toRaw} from "vue";
const { proxy } = getCurrentInstance();
const props = defineProps({
width: {
type: Number,
default: 400
},
height: {
type: Number,
default: 200
}
})
const emits = defineEmits(['save']);
const ctx = ref(null);
const isDrawing = ref(false);
const x = ref(0);
const y = ref(0);
const MOUSE_LEFT_BUTTON = 0;
const showSign = ref(false);
const canvasData = ref([]);
const canvasDataIndex = ref(0);
const imageBase = ref('');
const handleClick = () => {
showSign.value = true;
proxy.$nextTick(() => {
const canvas = document.getElementById('canvas');
ctx.value = canvas.getContext('2d');
if (!ctx.value) return;
isDrawing.value = false;
})
}
const handleMouseDown = (event) => {
if (event.button !== MOUSE_LEFT_BUTTON) {
return;
}
x.value = event.offsetX;
y.value = event.offsetY;
isDrawing.value = true;
}
const handleMouseMove = (event) => {
if (event.button !== MOUSE_LEFT_BUTTON) {
return;
}
if (isDrawing.value) {
drawLine(ctx, "black", 1, x.value, y.value, event.offsetX, event.offsetY);
x.value = event.offsetX;
y.value = event.offsetY;
}
}
const handleMouseUp = (event) => {
if (event.button !== MOUSE_LEFT_BUTTON) {
return;
}
if (isDrawing.value) {
drawLine(ctx, "black", 1, x, y, event.offsetX, event.offsetY);
x.value = 0;
y.value = 0;
isDrawing.value = false;
canvasData.value.push(ctx.value.getImageData(0, 0, props.width, props.height))
canvasDataIndex.value++;
}
}
const drawLine = (ctx, color, lineWidth, x1, y1, x2, y2) => {
ctx.value.beginPath();
ctx.value.strokeStyle = color;
ctx.value.lineWidth = lineWidth;
ctx.value.moveTo(x1, y1);
ctx.value.lineTo(x2, y2);
ctx.value.stroke();
}
const handleQuash = () => {
if (canvasDataIndex.value > 1) {
canvasDataIndex.value--;
ctx.value.putImageData(canvasData.value[canvasDataIndex.value], 0, 0);
} else if (canvasDataIndex.value === 1) {
canvasDataIndex.value--;
ctx.value.putImageData(ctx.value.createImageData(props.width, props.height), 0, 0);
}
}
const handleRestore = () => {
if (canvasDataIndex.value < canvasData.value.length) {
ctx.value.putImageData(canvasData.value[canvasDataIndex.value], 0, 0);
canvasDataIndex.value++;
}
}
const handleClear = () => {
ctx.value.clearRect(0, 0, props.width, props.height);
}
const handleSave = () => {
const canvas = document.getElementById('canvas');
imageBase.value = canvas.toDataURL();
emits('save', imageBase.value)
showSign.value = false;
}
</script>
<style scoped>
.canvas {
}
#canvas {
background-color: #e3e3e3;
}
</style>
常见问题
- 鼠标绘制偏移
canvas鼠标绘制偏移
问题原因:修改canvas尺寸不能使用style进行修改
<canvas id="canvas"
:style="{ width: width + 'px', height: height + 'px' }"
@mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"></canvas>
解决问题:通过width、height属性进行设置
<canvas id="canvas"
:width="width"
:height="height"
@mousedown="handleMouseDown"
@mousemove="handleMouseMove"
@mouseup="handleMouseUp"></canvas>