大家好。让我们继续制作组件。这次我们就一起来做一个花哨的组件,作为大家找故障的辅助工具。最初的想法来自于黄奕老师的粉丝群。老师玩找茬,然后剪出一张图。除了喊666,他不知道该说什么。他第一次感受到科技如此贴近生活。我觉得很酷,所以我自己研究了一下,终于实现了。我想在这里与大家分享。感谢liuyubobobo老师的canvas课程。我学到了很多知识,开了眼界。原来canvas还可以这么玩。话不多说,抓紧实施吧。后面会详细介绍故障查找的实现步骤:1.获取截图数据2.找到关键点3.比较两张图片4.呈现给页面1.获取截图数据1.1获取Ctrl+图片数据v发现区别就是速度,所以截图之后马上Ctrl+v需要获取图片的数据进行对比。先写模板和对应的事件:{{tips}}//Tips
exportdefault{data(){return{tips:''}},mounted(){document.addEventListener("click",this.getFocus);//点击空白处聚焦,为了速度!},beforeDestroy(){document.removeEventListener("点击",this.getFocus);},方法:{getFocus(){this.$refs['input'].focus();},pasteImgDate(e){constfile=e.clipboardData.items[0].getAsFile();//获取图像数据if(!file){this.tips="Nodatatocopy";返回;}...},onblur(){this.tips=''}}}首先我们设置一个tips变量提示运行中遇到的问题,然后我们监听粘贴事件,按下后会触发Ctrl+v在焦点输入框上。在这个事件对象中,可以获取到截图对应的数据,相当于选择图片作为文件类型的输入,为文档添加点击事件,点击任意位置获取输入的焦点盒子,一切为了速度!1.2在canvas上绘制然后我们将得到的数据转成base64在canvas上绘制:methods:{pasteImgDate(e){...constreader=newFileReader();reader.readAsDataURL(文件);//读取图像数据reader.onload=e=>{constimg=newImage();img.src=e.target.result;//获取转换后的base64格式img.onload=()=>{constcanvas=document.createElement("canvas");//创建画布标签constctx=canvas.getContext("2d");constwidth=img.width;constheight=img.height;canvas.width=宽度;canvas.height=高度;ctx.drawImage(img,0,0,宽度,高度);//将图片绘制到canvas标签中}}}}既然获取了图片数据,就好办了,使用newFileReader读取文件,然后转为base64格式,赋值给一个空的img标签,监听它的onload事件,最后使用drawImageAPI在canvas标签上绘制图片。函数中的0,0表示绘图的起始x轴和y轴位置,绘图将遵循Size2.找到关键点2.1确认目标点的像素信息。这里先说明一下这个工具的核心实现原理。其实并不复杂。就是用canvas获取整个大图的所有像素信息,然后分别比较里面的两个小图。像素的RGB值求差。但是每张图的截图位置肯定是不一样的,但是经过观察,我们也能发现很多有规律的地方。两张小图在同一水平线上,并且高宽相同,间距相同。最后他们周围的背景是一样的。那么我们现在第一步就是要知道左边小图的左上角在哪里。于是截屏放到ps里,把它的左上角调到最大:通过吸管取值,发现和图片接触的点的RGB值都是80、148、176,ok,找到了,我们从大图的x轴开始逐行查找,第一个点肯定是这里。接下来,编写以下代码:methods:{pasteImgDate(e){...ctx.drawImage(img,0,0,width,height);//代码前constimgData=ctx.getImageData(0,0,width,height);constpixelData=imgData.data;}}2.2通过遍历,根据条件,我们使用drawImage将图片绘制到canvas中。现在我们通过getImageData读取画布中的数据,里面的像素值存储在data属性中。.他们的排列是一个一维数组,放一张liuyubobobo老师的canvas课程截图:这里说明一下,从canvas读取的像素值排列成一维数组,每四个值代表一个的RGBA像素。所以遍历这个数组有两种方式:第一种是单循环顺序遍历,从第一个节点开始,一个一个遍历到最后一个像素,像这样:for(leti=0;width*height;i++){constr=pixelData[4*i+0];//第i个像素的r通道值constg=pixelData[4*i+1];//第i个像素的g通道值constb=pixelData[4*i+2];//第i个像素的b通道值}第二种是双循环的顺序遍历,可以知道已经遍历到了某行某列,像这样:for(lety=0;ypixelData[(y*img.width+x+457)*4+0]&&pixelData[(y*img.width+x)*4+1]+10>pixelData[(y*img.width+x+457)*4+1]&&pixelData[(y*img.width+x)*4+2]+10>pixelData[(y*img.width+x+457)*4+2]){像素数据[(y*img.width+x+457)*4+0]=0;pixelData[(y*img.width+x+457)*4+1]=0;pixelData[(y*img.width+x+457)*4+2]=0;}}}}为什么不使用!==来判断两个像素点的差异呢,因为两张图片不只是发现差异的地方不一样,是机器计算出来的我发现不一样的地方太多了,并且有小的像素波动,所以使用!==不能准确反映找到的图片。于是再找一个条件,把同一个点的RGB设置为0,也就是设置为黑色。4.呈现给页面4.1添加到画布的像素信息已被修改。现在我们把它放在canvas标签里,然后把canvas标签放在body里。pasteImgDate(e){...if(!this.imgPos.y&&!this.imgPos.x){this.tips="截图不匹配";返回;}删除this.imgPos.y;//移除deletethis.imgPos.x;constcanDraw=document.getElementById("__canvas_diff_");canDraw&&document.body.removeChild(canDraw);constcanvas2=document.createElement("canvas");constctx2=canvas2.getContext("2d");canvas2.id="__canvas_diff_";canvas2.width=宽度;canvas2.height=高度;ctx2.putImageData(imgData,0,0,0,0,宽度,高度);//将数据放入画布document.body.appendChild(canvas2);}组件安装npmivue-gn-componentsimport{FindDIff}from'vue-gn-components';import"vue-gn-components/lib/style/index.css";Vue.use(FindDIff)组件调用最后,如果使用qq截图工具,请确保截图为png格式,因为像素的jpg将有损压缩。第一次可以保存一个png到本地,以后每次都记住你的选择。源码位置>>>vue-gn-components.我觉得还可以,请给我一个开始。