手写签名域组件

手写签名域组件

前言

该组件基于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>

常见问题

  1. 鼠标绘制偏移

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>
  • 14
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值