最近在做一个论坛的项目,发布评论的时候,很多时候会用到截图上传的功能,通过微信截图,QQ截图,直接将截取的图片通过Ctrl+v
复制到输入框里,自动上传将图片渲染到页面上,今天就来实现一个这样的功能。
主要的知识点是,浏览的paste
事件,clipboardData
。
paste
一个标准的Dom事件,粘贴事件,会在用户按下Ctrl+v
,或者通过鼠标复制时触发.像其他事件一样,我们可以通过addEventListener
为一个Element
添加一个粘贴事件的监听函数 如以下代码。
document.addEventListener('paste', (event) => {console.log('粘贴事件', event)
});
复制代码
Copy
我使用vue,给多行输入框绑定一个v-paster的自定义指令,这个自定义指令直接监听元素的粘贴事件。
复制代码
Copy
// 指令粘贴指令定义directives: {paste: {bind(el, binding, vnode) {el.addEventListener('paste', function (event) {//这里直接监听元素的粘贴事件binding.value(event);});},},},
复制代码
Copy
paste
一个标准的Dom事件,粘贴事件,会在用户按下Ctrl+v
,或者通过鼠标复制时触发.像其他事件一样,在下面的代码中我打印的是一个叫做ClipboardEvent
的对象,内部存在着一个叫做clipboardData
的属性,这便是我们在复制时存储数据的对象。 其中的items
就是我们要操作的对象,需要粘贴的元素都在其中存储。
然后调用FileReader对象,该方法有两个参数,其中第二个参数是文本的编码方式,默认值为 UTF-8。这个方法非常容易理解,将文件以文本方式读取,读取的结果即是这个文本文件中的内容。
**readAsBinaryString:**该方法将文件读取为二进制字符串,通常我们将它传送到后端,后端可以通过这段字符串存储文件。
**readAsDataURL:**这是例子程序中用到的方法,该方法将文件读取为一段以 data: 开头的字符串,这段字符串的实质就是 Data URL,Data URL是一种将小文件直接嵌入文档的方案。这里的小文件通常是指图像与 html 等格式的文件。
最后组装为一个formData对象上传
//微信截图上传图片时触发
handleParse(e) {let file = null;var data=e.clipboardData||window.clipboardData, that = this;console.log('fun',data);blob=data.items[0].getAsFile();var isImg=(blob&&1)||-1;var reader=new FileReader();if(isImg>=0){//将文件读取为 DataURLreader.readAsDataURL(blob);}reader.onload=function(event){//获取base64流var base64_str=event.target.result;//div中的img标签src属性赋值,可以直接展示图片// console.log('base64_str',base64_str);var bytes = window.atob(base64_str.split(',')[1]);var array = [];for(var i = 0; i < bytes.length; i++){array.push(bytes.charCodeAt(i));}var blob = new Blob([new Uint8Array(array)], {type: 'image/jpeg'});var formData = new FormData();formData.append('file',blob, Date.now() + '.jpg');formData.append('filename', 'file')console.log(blob);that.update(formData);}
},
update(formData) {// 上传fetch('http://xxx/xxx',{method: 'post',headers: {authorization: localStorage.getItem('token')},body: formData}).then(response => response.json()).then(res=>{let pic = res.data.url;})
},
复制代码
Copy
关于fetch上传图片,在上面的示例中其实失败了很久,最后找到的原因是请求头的content-type,我填了application/json和MulitPart/form-data 均不能成功上传,最后去掉这个content-type才上传成功。原因是fetch 作为浏览器自身提供的api,当传入的参数为 formDate 格式时,不可手动设置content-type。