vue组件——H5手写签字版的实现

4 篇文章 0 订阅
3 篇文章 0 订阅

效果图
在这里插入图片描述

在这里插入图片描述

<template>
    <div class="signature">
        <header>签名</header>
		<div class="rect_position" v-if="isShow">
			<div class="div_canvas_container">
				<canvas id="signCanvas"></canvas>
			</div>
		</div>
		<span class="clear_btn" @click="handelClearEl">清除签名</span>
        <button class="confirm_btn" @click="saveImage">确定</button>
    </div>
</template>
<script>
export default {
    name: 'sign',
    data () {
        return {
			imgsrc: '',
			isShow: true
        }
    },
    mounted () {
		const _this = this
        this.$nextTick(() => {
            setTimeout(() => {
                _this.initCanvas()
            }, 100)
		})
	},
    methods: {
        initCanvas() {
            let rate = 2
            let oCanvas = document.getElementById("signCanvas")
            oCanvas.width = oCanvas.offsetWidth * rate
            oCanvas.height = oCanvas.offsetHeight * rate
            let cxt = oCanvas.getContext("2d")
            cxt.fillStyle = "#fff" // 签名版背景颜色
            cxt.fillRect(0, 0, oCanvas.width, oCanvas.height)
            cxt.lineWidth = 6 * rate // 签名线条粗细
            cxt.strokeStyle = "#101010"  // 签名线条颜色
            let posX = 0 //x坐标
            let posY = 0 //y坐标
            let position = null
			let parentPosintin = oCanvas.getBoundingClientRect()
			// 解决canvas有间距 手指落点和实际绘画点有偏移的问题
			const offsetT = oCanvas.offsetTop
			const offsetL = oCanvas.offsetLeft
			// console.log(offsetT, offsetL);
            //手指触摸屏幕可记录此时的位置作为起点
            oCanvas.addEventListener("touchstart", function(event) {
				posX = event.changedTouches[0].clientX
				// console.log(posX);
                posY = event.changedTouches[0].clientY - parentPosintin.top + 0.5
                cxt.beginPath()
                cxt.moveTo((posX - offsetL) * rate, (posY - offsetT + 20) * rate)
            });
            //手指屏滑动画线
            oCanvas.addEventListener("touchmove", function(event) {
                optimizedMove(event)
            })
            let requestAnimationFrame = window.requestAnimationFrame
            let optimizedMove = requestAnimationFrame ? function(e) {
					requestAnimationFrame(function() {
						move(e)
					})
				} : move
            function move(event) {
                posX = event.changedTouches[0].clientX + 0.5
                posY = event.changedTouches[0].clientY - parentPosintin.top + 0.5
                cxt.lineTo((posX - offsetL) * rate, (posY - offsetT + 20) * rate)
                cxt.stroke()
            }
        },
        // 清除画板
        handelClearEl() {
            let oCanvas = document.getElementById("signCanvas")
            let cxt = oCanvas.getContext("2d")
			cxt.clearRect(0, 0, oCanvas.width, oCanvas.height)
			setTimeout(() => {
				// 清除画板后重新绘制画布
				this.initCanvas()
			}, 200);
        },
        //保存为图片
        saveImage() {
			let oCanvas = document.getElementById("signCanvas")
			let imgBase64 = oCanvas.toDataURL("image/png")
			oCanvas.toBlob(async (blobObj) => {
				var file = new File([blobObj], "pic.png", {
					type: blobObj.type,
					lastModified: Date.now()
				})
				this.convertImg(file)
			})
        },
        //旋转图片
		convertImg(file) {
			// 旋转图片操作不可见
			this.isShow = false
			let _this = this;
			let canvas1 = document.getElementById("signCanvas")
			let context1 = canvas1.getContext('2d')
			var oReader = new FileReader()
			oReader.readAsDataURL(file)
			oReader.onload = function (e) {
				var img = new Image()
				img.src = e.target.result
				img.onload = function () {
					// 图片原始尺寸
					const originWidth = this.width
					const originHeight = this.height
					// 最大尺寸限制
					const maxWidth = 1080,
						maxHeight = 1080
					// 目标尺寸
					let targetWidth = originWidth,
						targetHeight = originHeight
					// 图片尺寸超过300x300的限制
					if (originWidth > maxWidth || originHeight > maxHeight) {
						if (originWidth / originHeight > maxWidth / maxHeight) {
							targetWidth = maxWidth
							targetHeight = Math.round(
								maxWidth * (originHeight / originWidth)
							)
						} else {
							targetHeight = maxHeight
							targetWidth = Math.round(
								maxHeight * (originWidth / originHeight)
							)
						}
					}
					var type = "image/png"
					// canvas对图片进行缩放
					canvas1.width = targetHeight
					canvas1.height = targetWidth
					context1.save()
					// 旋转90度	
					// 设置画布旋转的中心点	
					context1.translate(canvas1.width / 2, canvas1.height / 2)
					context1.rotate(-90 * Math.PI / 180)
					context1.translate(-canvas1.width / 2, -canvas1.height / 2)
					// 吧图片绘制在旋转的中心点
					context1.drawImage(img, canvas1.width / 2 - img.width / 2, canvas1.height / 2 - img.height / 2)
					// context1.drawImage(img, 0, 0, canvas1.width, canvas1.height)
					context1.translate(canvas1.width / 2, canvas1.height / 2)
					context1.rotate(90 * Math.PI / 180)
					context1.translate(canvas1.width / 2, canvas1.height / 2)
					context1.restore()
					// 将canvas的透明背景设置成白色
					var imageData = context1.getImageData(0,0,canvas1.width,canvas1.height
					)
					for (var i = 0; i < imageData.data.length; i += 4) {
						// 当该像素是透明的,则设置成白色
						if (imageData.data[i + 3] == 0) {
							imageData.data[i] = 255
							imageData.data[i + 1] = 255
							imageData.data[i + 2] = 255
							imageData.data[i + 3] = 255
						}
					}
					context1.putImageData(imageData, 0, 0)
					var dataurl = canvas1.toDataURL(type)
					_this.basedata = dataurl
					_this.getPolictReceiptImg()

				}
			}
		},
		// 
		getPolictReceiptImg () {
			if (window.sessionStorage.getItem('sign')) {
				window.sessionStorage.removeItem('sign')
				window.sessionStorage.setItem('sign', this.basedata)
            } else {
				window.sessionStorage.setItem('sign', this.basedata)
			}
			this.$emit('returnImg')
		}
  	}
}
</script>

<style lang="less" scoped>
.signature {
	width: 100vw;
	height: 100vh;
	box-sizing: border-box;
	// padding: 10px 10px 10px 30px;
	padding: 10px 10px 10px 20px;
	.rect_position {
		width: 100%;
		height: 100%;
		box-sizing: border-box;
		padding: 16px;
		background: linear-gradient(to left, black, black) left top no-repeat,
		linear-gradient(to bottom, black, black) left top no-repeat,
		linear-gradient(to left, black, black) right top no-repeat,
		linear-gradient(to bottom, black, black) right top no-repeat,
		linear-gradient(to left, black, black) left bottom no-repeat,
		linear-gradient(to bottom, black, black) left bottom no-repeat,
		linear-gradient(to left, black, black) right bottom no-repeat,
		linear-gradient(to left, black, black) right bottom no-repeat;
		background-size: 16px 40px, 40px 16px, 16px 40px, 40px 16px;
		/*左边两条线的宽高 上边两条线的宽高 右边两条线的宽高 下边两条线的宽高*/
		.div_canvas_container {
			width: 100%;
			height: 100%;
			#signCanvas {
				width: 100%;
				height: 100%;
				background: #FFF;
				border: none;
				box-sizing: border-box;
				// overflow: hidden;
			}
		}
	}
	header {
		position: absolute;
		width: 100px;
		height: 30px;
		line-height: 30px;
		background-color: #ccc;
		color: #FFF;
		font-size: 14px;
		text-align: center;
		top: 50%;
		right: -16px;
		transform:  rotate(90deg) translateX(-50%);
	}
	.clear_btn {
		position: absolute;
		// top: 27px;
		// left: -20px;
		top: 70px;
    	left: -20px;
		padding: 7px 10px;
		transform: rotate(90deg);
		background-color: #FF5D3C;
		color: #FFF;
		font-size: 14px;
	}
	.confirm_btn {
		position: absolute;
		// left: -8px;
		// bottom: 20px;
		left: -6px;
		bottom: 58px;
		padding: 7px 10px;
		text-align: center;
		transform: rotate(90deg);
		border: 0;
		outline: 0;
		font-size: 14px;
	}
}


</style>

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue.js是一种流行的JavaScript框架,用于构建现代Web应用程序,如移动应用程序和单页应用程序。使用Vue.js开发移动应用程序时,经常需要使用各种UI组件。其中,el-table是一个常用的表格组件,可以方便地展示数据。 移动端的el-table组件需要考虑到手机屏幕的大小和触摸操作的交互设计。因此,我们需要手写实现一套适用于移动端的el-table组件。 首先,我们需要设计一个表格结构,包括表头、表体和表尾。在移动端,由于屏幕较小,通常需要使用滚动条来滚动表体。因此,我们需要给表格设置固定高度,并设置overflow: auto属性。 其次,我们需要实现表格的数据绑定和分页功能。通常情况下,移动端的数据量较小,因此我们可以一次性将所有数据加载到前端进行分页展示。我们可以使用分页器组件实现分页,并通过计算分页数据来动态更新表格数据。 最后,我们需要考虑到表格的交互设计。在移动端,我们通常使用左右滑动来进行某些操作。例如,我们可以使用左滑删除删除某一行数据,右滑编辑某一行数据。此外,我们还可以添加筛选功能和搜索功能,方便用户快速查找需要的数据。 总之,Vue.js手写实现移动端el-table组件需要考虑到表格结构、数据绑定、分页功能和交互设计等方面。通过仔细设计和实现,我们可以创建出易用性、高效性和美观性的el-table组件,满足用户需要。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值