使用signature_pad制作电子签名PC端和h5横竖屏

pc端
点击之后弹出签名框,签完名生成图片
在这里插入图片描述
在这里插入图片描述
该图只是居中对齐,图片是等比的
在这里插入图片描述

h5端
在这里插入图片描述
点击全屏放大并回填书写的内容,全屏模式下点击返回键返回小屏并回填书写内容
在这里插入图片描述

代码

<template><divclass="signature-container"><FormItemref="formItem"><divclass="signature-content"v-if="!readonly"><spanv-if="!imgUrl"class="showWrite"@click="showModel">{{ disabled ? $terms('该字段不支持修改') : $terms('点击开始签名')}}</span><imgv-elseclass="signImg":src="imgUrl"alt=""><spanclass="clearImg"v-if="imgUrl && !disabled"@click="field.value = ''"><imgsrc="@/assets/images/clearBg.png"alt=""></span></div><div v-else><imgv-if="imgUrl"class="signImg":src="imgUrl"alt=""><span v-else>---</span></div><SignModelref="signModels"@setImg="setImg":field="field":isMobile="isMobile"></SignModel><vanPopref="vantModels"@setImg="setImg"@fullModels="fullModels":field="field":canvasList="canvasList":isBack="isBack":isMobile="isMobile"></vanPop><fullScreenref="fullShows"@setImg="setImg"@vanModels="vanModels":field="field":isMobile="isMobile":canvasList="canvasList":isFull="true"></fullScreen></FormItem></div>
</template><script>
// 以下代码引入
import SignModel from './signModel.vue'
import vanPop from './vanPop.vue'
import fullScreen from './fullScreen.vue'
export default {inject: {attendee: {default: {}}},props: {field: {type: Object,required: true},readonly: {type: Boolean,default: false},isMobile: {type: Boolean,default: false},isModify: {type: Boolean,default: false}},components: {SignModel,vanPop,fullScreen},data() {return {canvas: '',signaturePad: '',canvasList: [],isBack: false}},computed: {imgUrl() {let url = ''if (this.field.value && Array.isArray(this.field.value)) {url = this.field.value[0].absoluteUrl} else {url = this.field.value}return url},disabled() {return this.isForbidden || (this.isModify && !this.isAllowModify && this.attendee.detail?.status === 'Registered')}},methods: {vanModels(v) {this.canvasList = vthis.isBack = truethis.$refs.vantModels.showModel = true},fullModels(v) {this.canvasList = vthis.$refs.fullShows.showModel = true},showModel() {if (this.readonly || this.disabled) {return}this.canvasList = []if (this.isMobile) {this.$refs.vantModels.showModel = true} else {this.$refs.signModels.showModel = true}},setImg(v) {this.$set(this.field, 'value', v)if (this.isNeeded) {this.$refs.formItem.validate()}}}
}
</script>
<style lang="scss" scoped>
.signature-content {width: 100%;height: 100px;background-color: #f4f5f8;border-radius: 4px;text-align: center;line-height: 100px;color: rgba(0, 0, 0, 0.45);font-size: 14px;position: relative;
}
.showWrite {display: inline-block;cursor: pointer;width: 100%;
}
.clearImg {position: absolute;right: 4px;bottom: 4px;width: 24px;height: 24px;line-height: 24px;border-radius: 2px;background: rgba(0, 0, 0, 0.6);cursor: pointer;&:hover {background: rgba(0, 0, 0, 0.8);}img {width: 16px;height: 16px;vertical-align: sub;}
}
.signImg {// max-width: 300px;height: 100%;max-height: 100px;
}
::v-deep {.ivu-form-item-error {.signature-content {border: 1px solid #f24951;background-color: #fff1f0;}}
}
.isno {position: absolute;top: -24px;.noShow {opacity: 0;}
}
.need-write {display: inline-block;min-width: 58px;min-height: 32px;text-align: center;background: #fff9e6;border-radius: 2px;color: #ff9601;position: absolute;margin-left: 10px;padding: 0 8px;.box {position: absolute;left: -7px;top: 13px;width: 0px;height: 0px;border-top: 10px solid transparent;border-left: 10px solid #fff9e6;border-right: 10px solid transparent;transform: rotate(46deg);}
}
</style>

SignModel

<template><Modalv-model="showModel":title="$terms('签名')"width="640"><divid="signature-pad"class="signature-pad"><div class="signature-pad--body"><canvas:id="`signature-canvas${field.fieldName}`"class="canvass"></canvas><spanclass="signature-placeholder"v-if="signaturePad && signaturePad.isEmpty()">{{ $terms('请在此处签名') }}</span></div></div><div slot="footer"><spanid="clear"@click="clearButton"class="theme-txt"><span class="iconfont icon-eliminate"></span>{{ $terms('清除') }}</span><Button:disabled="isDisabled"type="primary"id="save":loading="btnLoading"@click="saveButton">{{ $terms('保存') }}</Button></div></Modal>
</template><script>
import SignaturePad from './SignaturePad'
import './icon/iconfont.css'
export default {mixins: [SignaturePad]
}
</script>
<style lang="scss" scoped>
::v-deep {.ivu-modal {height: 437px;}.ivu-modal-body {padding-left: 24px;}.ivu-modal-footer {text-align: center;position: relative;padding-top: 0;padding-bottom: 16px;}.ivu-modal-header {border-bottom: none;padding: 16px 24px;}.ivu-modal-header-inner {font-size: 20px;}.ivu-modal-close {right: 16px;top: 6px;}.ivu-icon-ios-close {&::before {font-size: 36px;}}
}
.canvass {border-radius: 8px;
}
.signature-pad--body {position: relative;height: 296px;
}
.signature-placeholder {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);color: rgba(0, 0, 0, 0.45);user-select: none;
}
#clear {position: absolute;left: 24px;cursor: pointer;height: 32px;line-height: 32px;
}
#save {width: 160px;height: 32px;
}
</style>

vanPop

<template><div><van-popupv-model="showModel"position="bottom"closeableround><div class="title">{{$terms('签名')}}</div><divid="signature-pad"class="signature-pad"><div class="signature-pad--body"><canvas:id="`signature-canvas${field.fieldName}`"class="canvass"></canvas><imgclass="bigImg"src="@/assets/h5/seeBig.png"alt=""@click="FullScreen"><spanclass="signature-placeholder"v-if="signaturePad && signaturePad.isEmpty()">{{ $terms('请在此处签名') }}</span></div></div><div class="footer"><spanid="clear"@click="clearButton"class="theme-txt"><span class="iconfont icon-eliminate"></span>{{ $terms('清除') }}</span><Button:disabled="isDisabled"type="primary"id="save":loading="btnLoading"@click="saveButton">{{ $terms('保存') }}</Button></div></van-popup></div>
</template><script>
import { Popup } from 'vant'
import 'vant/lib/index.css'
import SignaturePad from './SignaturePad'
import './icon/iconfont.css'
export default {mixins: [SignaturePad],components: {vanPopup: Popup},methods: {FullScreen() {this.showModel = falselet vals = []if (!this.signaturePad.isEmpty()) {vals = this.signaturePad.toData()}this.$emit('fullModels', vals)}}
}
</script><style lang="scss" scoped>
::v-deep {.van-popup {min-height: 304px;padding: 56px 16px 0;}.van-popup--bottom.van-popup--round {border-radius: 8px 8px 0 0;}
}
.title {position: absolute;top: 16px;left: 16px;font-size: 17px;font-weight: 500;color: #262626;
}
.canvass {width: 100%;height: 172px;border-radius: 4px;
}
.signature-pad--body {position: relative;
}
.bigImg {position: absolute;bottom: 20px;right: 12px;width: 20px;height: 20px;
}
.footer {height: 44px;
}
#clear {display: inline-block;width: 50%;height: 44px;line-height: 38px;text-align: center;font-size: 18px;font-weight: 500;vertical-align: sub;.iconfont {font-size: 18px;}
}
#save {width: 50%;height: 44px;font-size: 18px;::v-deep span {font-weight: 600;}
}
.signature-placeholder {position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%);color: rgba(0, 0, 0, 0.45);user-select: none;
}
</style>

fullScreen

<template><div class="fullContainer"><van-popupv-model="showModel"position="bottom"><divid="signature-pad"class="signature-pad"><div class="signature-pad--body"><canvas:id="`signature-canvas${field.fieldName}1`"class="canvass"></canvas><span class="backImg"><imgsrc="@/assets/h5/seeBack.png"alt=""@click="showVanPop"></span><spanclass="signature-placeholder"v-if="signaturePad && signaturePad.isEmpty()">{{ $terms('请在此处签名') }}</span><div class="footer"><spanid="clear"@click="clearButton"class="theme-txt"><span class="iconfont icon-eliminate"></span>{{ $terms('清除') }}</span><Button:disabled="isDisabled"type="primary"id="save":loading="btnLoading"@click="saveButton">{{ $terms('保存') }}</Button></div></div></div></van-popup></div>
</template><script>
import { Popup } from 'vant'
import 'vant/lib/index.css'
import SignaturePad from './SignaturePad'
import './icon/iconfont.css'
export default {mixins: [SignaturePad],components: {vanPopup: Popup},methods: {showVanPop() {let vals = []this.showModel = falseif (!this.signaturePad.isEmpty()) {vals = this.signaturePad.toData()}this.$emit('vanModels', vals)}}
}
</script><style lang="scss" scoped>
::v-deep {.van-popup {height: 100vh;overflow: hidden;}.van-popup--bottom.van-popup--round {border-radius: 8px 8px 0 0;}
}
.title {position: absolute;top: 16px;left: 16px;font-size: 17px;font-weight: 500;color: #262626;
}
.canvass {width: 100vw;height: 100vh;
}
.signature-pad--body {position: relative;
}
.backImg {position: absolute;width: 44px;height: 44px;text-align: center;padding-top: 6px;top: 16px;right: 16px;border-radius: 4px;background: rgba(0, 0, 0, 0.4);img {width: 32px;height: 32px;transform: rotate(90deg);}
}
.footer {position: absolute;transform: rotate(90deg);bottom: 154px;left: -80px;height: 44px;
}
#clear {display: inline-block;height: 44px;line-height: 38px;text-align: center;font-size: 18px;font-weight: 500;vertical-align: sub;.iconfont {font-size: 18px;}
}
#save {width: 172px;height: 44px;margin-left: 32px;font-size: 18px;::v-deep span {font-weight: 600;}
}
.signature-placeholder {position: absolute;top: 46%;left: 40%;color: rgba(0, 0, 0, 0.45);user-select: none;transform: rotate(90deg);
}
</style>

公共mixins文件 SignaturePad

import SignaturePad from 'signature_pad'
import { uploadBaseb4File } from '@/api/apply.js'
export default {props: {isMobile: {type: Boolean,default: false},field: {type: Object,required: true},isFull: {// 是否是大屏type: Boolean,default: false},isBack: {type: Boolean,default: false},canvasList: {type: Array,default: () => []}},data() {return {canvas: '',signaturePad: '',imgUrl: '',showModel: false,btnLoading: false}},computed: {isDisabled() {if (this.signaturePad) {return this.signaturePad.isEmpty()} else {return false}}},watch: {showModel(newVal, oldVal) {if (newVal) {setTimeout(() => {this.canvas = this.isFull? document.getElementById(`signature-canvas${this.field.fieldName}1`): document.getElementById(`signature-canvas${this.field.fieldName}`)this.signaturePad = new SignaturePad(this.canvas, { backgroundColor: '#F5F5F5', penColor: 'rgb(0, 0, 0)' })if (!this.isMobile) {this.canvas.width = 592this.canvas.height = 296}this.resizeCanvas()}, 100)}}},methods: {resizeCanvas(isGoBack = false, list = []) {this.canvas.width = this.canvas.offsetWidththis.canvas.height = this.canvas.offsetHeightthis.canvas.getContext('2d')this.signaturePad.clear()let newList = list.length > 0 ? list : this.canvasListif (this.isFull || this.isBack) {newList.forEach(eve => {eve.points.forEach(v => {v.num = v.xif (this.isFull && !isGoBack) {v.x = (-v.y + 180) * 2v.y = v.num * 2// v.x = -v.y + 150// v.y = v.num} else if (!isGoBack) {v.x = (v.y - 10) / 2v.y = (-v.num + 350) / 2// v.x = v.y - 100// v.y = -v.num + 300}})})this.signaturePad.fromData(newList)}},async saveButton() {if (this.signaturePad.isEmpty()) {return}let imgStr = this.signaturePad.toDataURL('image/png')if (this.isFull) {this.rotateBase64Img(imgStr, 270)} else {this.uploadImg(imgStr)}},clearButton() {this.signaturePad.clear()},uploadImg(url) {this.btnLoading = trueuploadBaseb4File({name: 'img',data: url,bventId: this.$route.params.bventId}).then(res => {this.$emit('setImg', res.absoluteUrl)this.btnLoading = falsethis.showModel = false})},rotateBase64Img(src, edg, callback) {let canvas = document.createElement('canvas')let ctx = canvas.getContext('2d')const quadrant = (edg / 90) % 4const cutCoor = { sx: 0, sy: 0, ex: 0, ey: 0 }let image = new Image()image.crossOrigin = 'anonymous'image.src = srcimage.onload = () => {let imgW = image.widthlet imgH = image.heightlet size = imgW > imgH ? imgW : imgHcanvas.width = size * 2canvas.height = size * 2switch (quadrant) {case 0:cutCoor.sx = sizecutCoor.sy = sizecutCoor.ex = size + imgWcutCoor.ey = size + imgHbreakcase 1:cutCoor.sx = size - imgHcutCoor.sy = sizecutCoor.ex = sizecutCoor.ey = size + imgWbreakcase 2:cutCoor.sx = size - imgWcutCoor.sy = size - imgHcutCoor.ex = sizecutCoor.ey = sizebreakcase 3:cutCoor.sx = sizecutCoor.sy = size - imgWcutCoor.ex = size + imgHcutCoor.ey = size + imgWbreak}ctx.translate(size, size)ctx.rotate((edg * Math.PI) / 180)ctx.drawImage(image, 0, 0)var imgData = ctx.getImageData(cutCoor.sx, cutCoor.sy, cutCoor.ex, cutCoor.ey)if (quadrant % 2 === 0) {canvas.width = imgWcanvas.height = imgH} else {canvas.width = imgHcanvas.height = imgW}ctx.putImageData(imgData, 0, 0)this.uploadImg(canvas.toDataURL())}}}
}


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部