参考博客:https://www.cnblogs.com/smile-fanyin/p/16544271.html,里面还包含了橡皮擦功能,因为签名对橡皮擦功能需求不大,所以没有使用。
在做中石油后台管理项目时,遇到了交接班表格要求实现签字效果,在参考上述博客后,在vue3项目中实现了此功能,上源码:
<template>
<a-modal
v-model:visible="panelVisible"
class="signNameModel"
title="签字"
width="600"
height="400"
size="large"
:destroy-on-close="true"
@cancel="cancel"
>
<template #default>
<div class="signWrap">
<VueSignaturePad
ref="signaturePadRef"
width="100%"
height="100%"
:options="options"
/>
</div>
</template>
<template #footer>
<div class="footer flex justify-between">
<div class="otherSet flex">
<div class="penTxt">笔刷大小:</div>
<div
class="circleWrap"
:class="{ active: isActive1 }"
@click="selSize(1)"
>
<div class="b1">·</div>
</div>
<div
class="circleWrap"
:class="{ active: isActive2 }"
@click="selSize(2)"
>
<div class="b2">·</div>
</div>
<div
class="circleWrap"
:class="{ active: isActive3 }"
@click="selSize(3)"
>
<div class="b3">·</div>
</div>
</div>
<div class="gtnGroup">
<a-button type="primary" size="small" @click="undo">撤销</a-button>
<a-button
type="primary"
size="small"
style="margin-left: 20px"
@click="clear"
>清屏</a-button
>
<a-button
type="primary"
size="small"
style="margin-left: 20px"
@click="cancel"
>取消</a-button
>
<a-button
type="primary"
size="small"
style="margin-left: 20px"
@click="save"
>保存</a-button
>
</div>
</div>
</template>
</a-modal>
</template>
<script lang="ts" setup>
import { message } from 'ant-design-vue';
const panelVisible = ref<boolean>(false);
const signaturePadRef = ref();
const options = ref({
penColor: '#000',
minWidth: 1, // 控制画笔最小宽度
maxWidth: 1, // 控制画笔最大宽度
});
const isActive1 = ref<boolean>(true);
const isActive2 = ref<boolean>(false);
const isActive3 = ref<boolean>(false);
const props = defineProps<{
signVisible: boolean;
}>();
const { signVisible } = toRefs(props);
const emit = defineEmits(['signed']);
// 手写签名按钮的点击
const handleClick = () => {
panelVisible.value = true;
isActive1.value = true;
isActive2.value = false;
isActive3.value = false;
options.value = {
penColor: '#000',
minWidth: 1,
maxWidth: 1,
};
};
// 撤销
const undo = () => {
signaturePadRef.value.undoSignature();
};
// 清除
const clear = () => {
signaturePadRef.value.clearSignature();
};
// 取消
const cancel = () => {
panelVisible.value = false;
emit('signed');
};
// 保存
const save = () => {
const { isEmpty, data } = signaturePadRef.value.saveSignature();
if (!data) return message.error('请先进行签名');
panelVisible.value = false;
emit('signed', data);
};
// 调节画笔粗细大小
const selSize = (val:any) => {
options.value = {
penColor: '#000',
minWidth: val,
maxWidth: val,
};
if (val === 1) {
isActive1.value = true;
isActive2.value = false;
isActive3.value = false;
} else if (val === 2) {
isActive1.value = false;
isActive2.value = true;
isActive3.value = false;
} else if (val === 3) {
isActive1.value = false;
isActive2.value = false;
isActive3.value = true;
}
};
watchEffect(() => {
if (signVisible.value) {
handleClick();
}
});
</script>
<style scoped lang="less">
.img-wrap {
width: 100%;
height: 164px;
margin-top: 2px;
border: 1px solid #ccc;
img {
width: 70%;
height: 100%;
}
}
.signWrap {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
.signName {
flex: 1;
border-top: 1px solid #ccc;
}
}
.footer {
height: 40px;
display: flex;
justify-content: space-between;
align-items: center;
.gtnGroup {
width: 50%;
margin-left: 20px;
}
.otherSet {
width: 50%;
display: flex;
align-items: center;
.penTxt {
width: 70px;
}
.selSize {
width: 70px;
}
.el-select__caret {
position: absolute;
right: -3px;
}
.b1,
.b2,
.b3 {
background: #000;
border-radius: 50%;
}
.circleWrap {
display: flex;
justify-content: center;
align-items: center;
width: 58px;
height: 58px;
cursor: pointer;
margin-right: 20px;
}
.active {
border: 1px dashed #0074d9;
}
.b1 {
width: 4px;
height: 4px;
}
.b2 {
width: 6px;
height: 6px;
}
.b3 {
width: 8px;
height: 8px;
}
}
}
.signNameModel {
.vxe-modal--content {
padding: 0 !important;
}
}
</style>
使用并回显:
<template>
<div v-if="onShiftPersonUrl" class="img">
<img class="w-full h-full" :src="onShiftPersonUrl" />
</div>
<SignaturePad :sign-visible="signVisible" @signed="signed" />
</template>
<script lang="ts" setup>
import SignaturePad from '@/views/components/Signature.vue';
const onShiftPersonUrl = ref();
const signed = (imgSrc?: any) => {
signVisible.value = false;
if (!imgSrc) return;
onShiftPersonUrl.value = imgSrc;
};
<script/>