使用canvas实现简易版的截图效果
完整代码如下
canvas不是很会,按自己的理解写的注释,仅供参考,有错误的望指出,大佬有好的学习canvas的文档或者视频可以评论区分享下
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>html,body {margin: 0;padding: 0;}.fileInput {margin: 12px 0;}</style>
</head><body><div class="fileInput"><input type="file" accept="image/*" id="fileInput"></div><div class="canvasShootContainer"><canvas class="shoot"></canvas></div><div class="canvasShowContainer"><canvas class="show"></canvas></div><script>// 获取所需的所有元素const fileInput = document.querySelector('#fileInput')const canvasShootContainer = document.querySelector('.canvasShootContainer')const canvasShowContainer = document.querySelector('.canvasShowContainer')const canvasShoot = document.querySelector('.shoot')const canvasShow = document.querySelector('.show')const ctx = canvasShoot.getContext('2d')const ctx2 = canvasShow.getContext('2d')const opacity = 0.5 // 设置蒙层透明度let drawPosition = [] // 截图的位置信息: 在画布中的起始位子,截图的大小const img = new Image() // 创建图片用来获取图片信息// 1,初始化function init() {setEvent() // 给元素绑定事件}// 2,执行初始化事件function setEvent() {fileInput.addEventListener('change', handleFileInputChange, false)canvasShoot.addEventListener('mousedown', handleCanvasMouseDown, false)}// 画布点击: 获取截图的起始位置function handleCanvasMouseDown(e) {console.log(e, '55')let startX = e.offsetXlet startY = e.offsetYdrawPosition = [startX, startY]canvasShoot.addEventListener('mousemove', handleCanvasMouseMove, false)canvasShoot.addEventListener('mouseup', handleCanvasMouseUp, false)}// 画布中鼠标移动: 确定起始位置后,动态的变动截图区域,计算截图的大小,并根据画布和截图的大小动态绘制扣空区、图片function handleCanvasMouseMove(e) {let endX = e.offsetXlet endY = e.offsetYlet [startX, startY] = drawPositionconst drawWidth = endX - startXconst drawHeight = endY - startYdrawPosition = [startX, startY, drawWidth, drawHeight]// 获取画布大小const { width, height } = canvasShootconsole.log(drawPosition, '71')// 清理画布ctx.clearRect(0, 0, width, height)// 绘制蒙层drawMask(width, height, opacity)// 绘制截取区域setShootArea(width, height, drawPosition)}function handleCanvasMouseUp() {canvasShoot.removeEventListener('mousemove', handleCanvasMouseMove, false)canvasShoot.removeEventListener('mouseup', handleCanvasMouseUp, false)// 抬起鼠标后,绘制截取的图片drawShootImage(drawPosition)}// 获取新的文件 : 获取图片文件的信息,根据图片信息创建被截图图片的画布,及绘制图片function handleFileInputChange(e) {const file = e.target.files[0]// 获取解析文件的实例const reader = new FileReader()// 解析文件信息,在result中获取 base64 信息reader.readAsDataURL(file)reader.onload = (e) => {let result = e.target.resultimg.src = resultimg.onload = function () {const { width, height } = this// 根据图片的大小设置画布容器,及画布的大小generateCanvas(canvasShootContainer, canvasShoot, width, height)// 在画布中绘制图片ctx.drawImage(img, 0, 0)// 绘制蒙版drawMask(width, height, opacity)}}}// 根据图片信息绘制画布容器,及画布大小function generateCanvas(canvasShootContainer, canvasShoot, width, height) {canvasShootContainer.style.width = width + 'px'canvasShootContainer.style.height = height + 'px'canvasShoot.width = widthcanvasShoot.height = heightcanvasShootContainer.style.display = 'block'}// 绘制蒙版function drawMask(width, height, opacity) {ctx.fillStyle = `rgba(0,0,0,${opacity})`ctx.fillRect(0, 0, width, height)}// 绘制截图的透明区域// 我个人理解: 画布氛围两层: 绘制的图片 + 遮照的蒙层 : 蒙层在图片层上面,下面绘制的扣空区,是在蒙层上扣去的,不影响图片层// 可以先后关闭 77 , 153行代码,看下效果 function setShootArea(width, height, drawPosition) {if (!drawPosition?.length) return// 设置为混动模式,此模式下:新绘制的图形会原来画布中的内容扣除,但扣空区域不会填充颜色是透明的 ctx.globalCompositeOperation = 'destination-out'ctx.fillStyle = '#000' // 这里设置什么颜色都不重要,因为扣空出不会渲染颜色ctx.fillRect(...drawPosition) // 根据截图信息,绘制图形// 此模式下绘制的内容会覆盖在画布原来的内容上,但是上面扣空的区域不会被覆盖// 且不开启下面的模式,画布都会变成透明的ctx.globalCompositeOperation = 'destination-over'// 不绘制图形,只会看到被扣空的蒙层,因为每次绘制截图时,画布内容被清空了ctx.drawImage(img, 0, 0, width, height, 0, 0, width, height)}function drawShootImage(drawPosition) {// 获取画布中的图片信息,获取区域: 起始坐标,图片大小let data = ctx.getImageData(...drawPosition)console.log(data , '139')const {width , height} = data// 设置展示截图的容器及画布大小generateCanvas(canvasShowContainer , canvasShow ,width ,height)// 绘制截图ctx2.putImageData(data,0,0,)}init()</script>
</body></html>