使用vue-esign实现手机签名
ps:vue-esign只适用vue2,vue3可以使用vue-signature-pad
这里先附上文档地址
1.下载
$ npm install vue-esign
2.引入
2.1 全局引入
//main.js文件
//引入
import vueEsign from "vue-esign";
Vue.use(vueEsign)
2.2 组件内引入
<script>
//引入
import vueEsign from "vue-esign";
//注册组件
export default {
...
components: {vueEsign}
}
</script>
<template>
/*使用*/
<vue-esign></vue-esign>
</template>
3.使用案例
签名板在手机打开,默认是竖屏,如果旋转屏幕(前提是未锁定屏幕方向),签名板会也会变成横向。
3.1效果和源码
<template>
<div id="sign" v-loading="loading">
<vue-esign
class="esign"
ref="esign"
v-if="showPad"
:width="padWidth"
:height="padHeight"
:isCrop="isCrop"
:lineWidth="lineWidth"
:lineColor="lineColor"
:bgColor="bgColor"
></vue-esign>
<div class="text-green tip">*请在签名板上进行签名,并保持字迹清晰</div>
<div class="btn-group btns">
<pas-btn
@click="handleReset"
width="100px"
height="30px"
fontSize="16px"
color="grey"
radius="0.4rem"
>清空</pas-btn
>
<pas-btn
color="green"
width="100px"
height="30px"
fontSize="16px"
@click="handleGenerate"
radius="0.4rem"
>确定</pas-btn
>
</div>
<div class="toast" v-show="showToast">
{{ msg }}
</div>
</div>
</template>
<script>
import vueEsign from "vue-esign";
export default {
name: "Sign",
components: {
vueEsign,
},
data() {
return {
lineWidth: 3, //笔画的粗细
lineColor: "#000000", //画笔颜色
bgColor: "", //背景颜色
resultImg: "",
isCrop: true, //是否将白色多余部分裁掉
showPad: false,
padWidth: document.body.clientWidth - 0.8 * this.$rem,
padHeight: 240,
staffCode: sessionStorage.getItem("staffCode"),
msg: "请先签字再提交",
showToast: false,
originProtrait: window.matchMedia("(orientation: portrait)").matches,
loading: false,
};
},
methods: {
handleReset() {
this.$refs["esign"].reset(); //清空画布
},
handleGenerate() {
this.loading = true;
// 获取base64
this.$refs.esign
.generate()
.then((res) => {
// 转成文件
const file = this.dataURLtoFile(res, "签名照.png");
/*
...上传文件操作
*/
})
.catch(() => {
this.showToast = true;
this.loading = false;
setTimeout(() => {
this.showToast = false;
this.msg = "请先签字再提交";
}, 1000);
// 画布没有签字时会执行这里,报'Not Signned'
});
},
dataURLtoFile: function (dataurl, filename) {
var arr = dataurl.split(","),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
}
},
mounted() {
this.loading = false;
this.staffCode = this.$route.query.staffCode;
this.padHeight = window.matchMedia("(orientation: portrait)").matches
? 240
: document.body.clientHeight - 85;
this.showPad = true;
window.onorientationchange = () => {
this.loading = true;
document.location.reload();
};
},
};
</script>
<style lang="scss">
#sign {
position: relative;
padding: 0.5rem 0.4rem;
canvas {
box-shadow: 0px 0px 21px 0px rgba(92, 124, 187, 0.27);
}
.toast {
display: inline-block;
padding: 0.15rem;
position: absolute;
color: #fff;
background-color: rgba(0, 0, 0, 0.7);
border-radius: 10px;
top: calc(50% - 1rem);
left: calc(50% - 0.8rem);
transition: 0.3s;
}
.tip {
margin-top: 0.2rem;
}
.btns {
margin-top: 0.27rem;
}
}
@media screen and (orientation: landscape) {
#sign {
padding: 0.1rem 1rem;
}
}
</style>
3.2几个关键点:
3.2.1 签名板的宽高设置
因为签名板是mounted阶段就已经生成了,这时候没有办法通过width和height参数来修改宽高了。所以需要修改宽高,可以使用v-if使签名板先不渲染,设置了宽高之后,再进行渲染。这里我用了showPad来控制。然后旋转屏幕时,重新加载页面,达到签名板随着屏幕旋转的效果。window.matchMedia("(orientation: portrait)").matches用来判断页面是否是竖屏,竖屏则会返回true。
this.padHeight = window.matchMedia("(orientation: portrait)").matches
? 240
: document.body.clientHeight - 85;
this.showPad = true;
window.onorientationchange = () => {
this.loading = true; //显示loading
document.location.reload();
};
3.2.2 isCrop属性
isCrop设置为true,可以使生成图片去掉留白部分。想象一下有些人可能会将字签到角落里,如果没有设置isCrop属性,生成的图片就会不太美观。
3.2.3 生成图片
文档已经写了,生成的图片是base64格式,但是一般传给后端都会使用File格式的文件,所以需要先将base64转为File,用了dataURLtoFile方法
dataURLtoFile: function (dataurl, filename) {
var arr = dataurl.split(","),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
},
3.2.4 横竖屏样式
使用媒体查询可以根据手机屏幕当前的横竖屏状态设置不同样式
@media screen and (orientation: landscape) {
/* ... 横屏*/
}
@media screen and (orientation: portrait) {
/* ... 竖屏 */
}