Vue解析剪切板图片并实现发送功能
前言
我们在使用QQ进行聊天时,从别的地方Ctrl+C一张图片,然后在聊天窗口Ctrl+V,QQ就会将你刚才复制的图片粘贴到即将发送的消息容器里,按下Enter键,这张图片将会发送出去。接下来跟各位开发者分享下这项功能在Vue中如何来实现。先跟大家展示下最终实现的效果。在线体验地址
实现思路
- 页面挂载时监听剪切板粘贴事件
- 监听文件流
- 读取文件流中的数据
- 创建img标签
- 将获取到的base64码赋值到img标签的src属性
- 将生成的img标签append到即将发送的消息容器里
- 监听回车事件
- 获取可编辑div容器中的所有子元素
- 遍历获取到的元素,找出img元素
- 判断当前img元素是否有alt属性(表情插入时有alt属性),
- 如果没有alt属性当前元素就是图片
- 将base64格式的图片转成文件上传至服务器
- 上传成功后,将服务器返回的图片地址推送到websocket服务
- 客户端收到推送后,渲染页面
实现过程
本片文章主要讲解剪切板图片的解析以及将base64图片转换成文件上传至服务器,下方代码中的axios的封装以及websocket的配置与使用可参考我的另外两篇文章:Vue合理配置axios并在项目中进行实际应用和Vue合理配置WebSocket并实现群聊
监听剪切板事件(mounted生命周期中),将图片渲染到即将发送到消息容器里
constthat=this; document.body.addEventListener('paste',function(event){ //自己写的一个全屏加载插件,文章地址:https://juejin.im/post/5e3307145188252c30002fa7 that.$fullScreenLoading.show("读取图片中"); //获取当前输入框内的文字 constoldText=that.$refs.msgInputContainer.textContent; //读取图片 letitems=event.clipboardData&&event.clipboardData.items; letfile=null; if(items&&items.length){ //检索剪切板items for(leti=0;i1920){ //真实比例缩小5倍 scale=5; } } //设置可编辑div中图片宽高 img.width=imgWidth; img.height=imgHeight; //压缩图片,渲染页面 that.compressPic(imgContent,scale,function(newBlob,newBase){ //删除可编辑div中的图片名称 that.$refs.msgInputContainer.textContent=oldText; img.src=newBase;//设置链接 //图片渲染 that.$refs.msgInputContainer.append(img); that.$fullScreenLoading.hide(); }); }; }; reader.readAsDataURL(file); });
base64图片压缩函数
//参数:base64地址,压缩比例,回调函数(返回压缩后图片的blob和base64) compressPic:function(base64,scale,callback){ constthat=this; let_img=newImage(); _img.src=base64; _img.onload=function(){ let_canvas=document.createElement("canvas"); letw=this.width/scale; leth=this.height/scale; _canvas.setAttribute("width",w); _canvas.setAttribute("height",h); _canvas.getContext("2d").drawImage(this,0,0,w,h); letbase64=_canvas.toDataURL("image/jpeg"); //当canvas对象的原型中没有toBlob方法的时候,手动添加该方法 if(!HTMLCanvasElement.prototype.toBlob){ Object.defineProperty(HTMLCanvasElement.prototype,'toBlob',{ value:function(callback,type,quality){ letbinStr=atob(this.toDataURL(type,quality).split(',')[1]), len=binStr.length, arr=newUint8Array(len); for(leti=0;i1024*1024){ that.compressPic(base64,scale,callback); }else{ callback(blob,base64); } },"image/jpeg"); } } }
完善消息发送函数,获取输入框里的所有子元素,找出base64图片将其转为文件并上传至服务器(此处需要注意:base64转文件时,需要用正则表达式删掉base64图片的前缀),将当前图片地址推送至websocket服务。
对下述代码有不理解的地方,可阅读我的另一篇文章:Vue实现图片与文字混输,
sendMessage:function(event){ if(event.keyCode===13){ //阻止编辑框默认生成div事件 event.preventDefault(); letmsgText=""; //获取输入框下的所有子元素 letallNodes=event.target.childNodes; for(letitemofallNodes){ //判断当前元素是否为img元素 if(item.nodeName==="IMG"){ if(item.alt===""){ //是图片 letbase64Img=item.src; //删除base64图片的前缀 base64Img=base64Img.replace(/^data:image\/\w+;base64,/,""); //随机文件名 letfileName=(newDate()).getTime()+".jpeg"; //将base64转换成file letimgFile=this.convertBase64UrlToImgFile(base64Img,fileName,'image/jpeg'); letformData=newFormData(); //此处的file与后台取值时的属性一样,append时需要添加文件名,否则一直时blob formData.append('file',imgFile,fileName); //将图片上传至服务器 this.$api.fileManageAPI.baseFileUpload(formData).then((res)=>{ constmsgImgName=`/${res.fileName}/`; //消息发送:发送图片 this.$socket.sendObj({ msg:msgImgName, code:0, username:this.$store.state.username, avatarSrc:this.$store.state.profilePicture, userID:this.$store.state.userID }); //清空输入框中的内容 event.target.innerHTML=""; }); }else{ msgText+=`/${item.alt}/`; } }else{ //获取text节点的值 if(item.nodeValue!==null){ msgText+=item.nodeValue; } } } //消息发送:发送文字,为空则不发送 if(msgText.trim().length>0){ this.$socket.sendObj({ msg:msgText, code:0, username:this.$store.state.username, avatarSrc:this.$store.state.profilePicture, userID:this.$store.state.userID }); //清空输入框中的内容 event.target.innerHTML=""; } } }
base64图片转flie
//base64转file convertBase64UrlToImgFile:function(urlData,fileName,fileType){ //转换为byte letbytes=window.atob(urlData); //处理异常,将ascii码小于0的转换为大于0 letab=newArrayBuffer(bytes.length); letia=newInt8Array(ab); for(leti=0;i解析websocket推送的消息
//消息解析 messageParsing:function(msgObj){ //解析接口返回的数据并进行渲染 letseparateReg=/(\/[^/]+\/)/g; letmsgText=msgObj.msgText; letfinalMsgText=""; //将符合条件的字符串放到数组里 constresultArray=msgText.match(separateReg); if(resultArray!==null){ for(letitemofresultArray){ //删除字符串中的/符号 item=item.replace(/\//g,""); //判断是否为图片:后缀为.jpeg if(this.isImg(item)){ //解析为img标签 constimgTag=``; //替换匹配的字符串为img标签:全局替换 msgText=msgText.replace(newRegExp(`/${item}/`,'g'),imgTag); } } finalMsgText=msgText; }else{ finalMsgText=msgText; } msgObj.msgText=finalMsgText; //渲染页面 this.senderMessageList.push(msgObj); //修改滚动条位置 this.$nextTick(function(){ this.$refs.messagesContainer.scrollTop=this.$refs.messagesContainer.scrollHeight; }); } 判断当前字符串是否为有图片后缀
//判断是否为图片 isImg:function(str){ letobjReg=newRegExp("[.]+(jpg|jpeg|swf|gif)$","gi"); returnobjReg.test(str); }踩坑记录
直接将base64格式的图片通过websocket发送至服务端
结果很明显,服务端websocket服务报错,报错原因:内容超过最大长度。
前端通过post请求将base64码传到服务端,服务端直接将base64码解析为图片保存至服务器
从下午2点折腾到晚上6点,一直在找Java解析base64图片存到服务器的方案,最终选择了放弃,采用了前端转换方式,这里的问题大概是前端传base64码到后端时,http请求会进行转义,导致后端解析得到的base64码是错误的,所以一直没有成功。
项目地址:chat-system
总结
以上所述是小编给大家介绍的Vue解析剪切板图片并实现发送功能,希望对大家有所帮助!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。