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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。