js,vue图片上传预览,拖拽上传(FileReader(),window.URL.createObjectURL)

1,908 阅读5分钟

今天整理下FileReader 和 window.URL.createObjectURL,一直以来在上传图片的时候,图片预览用今天整理下FileReader()构造函数,对象上的readAsDataURL方法可以将读取的文件编码成DATA URL,base64,方便是方便,但是貌似需要兼容高版本浏览器,也有同学遇到某些移动端上图片不展示,原因是图片没有图片类型。

FileReader()

我们先来看下FileReader()构造函数的一些语法吧。 FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。

其中File对象可以是来自用户在一个input元素上选择文件后返回的FileList对象,也可以来自拖放操作生成的 DataTransfer对象,还可以是来自在一个HTMLCanvasElement上执行mozGetAsFile()方法后返回结果。

重要提示: FileReader仅用于以安全的方式从用户(远程)系统读取文件内容 它不能用于从文件系统中按路径名简单地读取文件。 要在JavaScript中按路径名读取文件,应使用标准Ajax解决方案进行服务器端文件读取,如果读取跨域,则使用CORS权限。

事件处理

  • FileReader.onabort 处理abort事件。该事件在读取操作被中断时触发。
  • FileReader.onerror 处理error事件。该事件在读取操作发生错误时触发。
  • FileReader.onload 处理load事件。该事件在读取操作完成时触发。
  • FileReader.onloadstart 处理loadstart事件。该事件在读取操作开始时触发。
  • FileReader.onloadend 处理loadend事件。该事件在读取操作结束时(要么成功,要么失败)触发。
  • FileReader.onprogress 处理progress事件。该事件在读取Blob时触发。

功能方法

  • readAsArrayBuffer() 方法用于启动读取指定的 Blob 或 File 内容。当读取操作完成时,readyState 变成 DONE(已完成),并触发 loadend 事件,同时 result 属性中将包含一个 ArrayBuffer 对象以表示所读取文件的数据。
  • readAsBinaryString 方法会读取指定的 Blob 或 File 对象,当读取完成的时候,readyState 会变成DONE(已完成),并触发 loadend 事件,同时 result 属性将包含所读取文件原始二进制格式。
  • readAsDataURL 方法会读取指定的 Blob 或 File 对象。读取操作完成的时候,readyState 会变成已完成DONE,并触发 loadend 事件,同时 result 属性将包含一个data:URL格式的字符串(base64编码)以表示所读取文件的内容。
  • readAsText 方法可以将 Blob 或者 File 对象转根据特殊的编码格式转化为内容(字符串形式)这个方法是异步的,也就是说,只有当执行完成后才能够查看到结果,如果直接查看是无结果的,并返回undefined。也就是说必须要挂载 实例下的 onload 或 onloadend 的方法处理转化后的结果。 当转化完成后, readyState 这个参数就会转换 为 done 即完成态, event("loadend") 挂载的事件会被触发,并可以通过事件返回的形参得到中的 FileReader.result 属性得到转化后的结果

举个例子:

document.querySelector('input[type=file]').addEventListener('change', ()=>{
    var reader = new FileReader();//读取文件
    reader.readAsDataURL(files[0]);
    reader.onload = (ev) => {
        console.log(ev)
        this.srcImgUrl = reader.result
        //或者
        const img = new Image()
        img.src = reader.result
        document.body.appendChild(img)  // reader.result为获取结果
    }
    reader.onprogress = (ev)=>{
        //这里是读取文件中的进度,ev.loaded是当前读取的大小
        console.log(ev.loaded)
    }
},false)

也可以读取文件

document.querySelector('input[type=file]').addEventListener('change', ()=>{
    var reader = new FileReader();//读取文件
    reader.readAsText(input.files[0],'utf8') 
    reader.onload = ()=>{
      document.body.innerHTML += reader.result  
    }
},false)

window.URL.createObjectURL(blob||file)

URL.createObjectURL()方法会根据传入的参数创建一个指向该参数对象的URL。   这个URL的生命仅存在于它被创建的这个文档里,新的对象URL指向执行的File对象或者是Blob对象。   

objectURL = window.URL.createObjectURL(blob || file);

File对象,就是一个文件,比如我用input type="file"标签来上传文件,那么里面的每个文件都是一个File对象。

Blob对象,就是二进制数据,比如通过new Blob()创建的对象就是Blob对象。

每次调用createObjectURL时,即使你已经为同一个文件创建过一个URL,也会创建一个新的URL对象。   如果你不再需要这个对象,需要使用URL.revokeObjectURL()方法释放它。   

let src = URL.createObjectURL(file)//file为input上传的图片
let img = new Image()
img.src = src
img.onload = () => {
    this.srcImgUrl = src
}

监听上传进度

如果是axios的话,我们可以这样监听进度:

const config = {
    onUploadProgress: e => {
        //上传进度计算
        parseInt((e.loaded / e.total) * 100)
    }
}
axios.post('接口地址', formData, config)

其实也是依赖于原生ajax 的封装,原生ajax的onprogress方法。

new XMLHttpRequest().onprogress = (e)=>{
     parseInt((e.loaded / e.total) * 100)
}

图片拖拽到页面某个区域上传

其实主要操作事件是drop,但是浏览器是有一些默认行为,所以在鼠标拖动的时候清除默认行为和取消冒泡。

<div>
    <input type="file" @change="uploadPage" multiple accept=".png, .jpg, .gif" />
    <img :src="srcImgUrl" />
    <div class="drop" id="drop_area" :style="{'border-color': (borderhover ? '#3d8cff':'#BBBBBB')}">
    </div>
</div>

data() {
    return {
        srcImgUrl:'',
        borderhover:false,
    }
},
mounted() {
    var dropbox = document.getElementById('drop_area');
    dropbox.addEventListener("drop",this.enentDrop,false)
    dropbox.addEventListener("dragleave",function (e) {
        //拖拽离开时触发的方法
        e.stopPropagation();
        e.preventDefault();
        this.borderhover =  false;
    })
    dropbox.addEventListener("dragenter",function (e) {
        //拖拽进入时触发的方法
        e.stopPropagation();
        e.preventDefault();
        this.borderhover =  true;
    })
    dropbox.addEventListener("dragover",function (e) {
        //拖拽在区域中不停移动的方法
        e.stopPropagation();
        e.preventDefault();
        this.borderhover =  true
    })
},
methods:{
    enentDrop: function(e){
        //拖拽后放入时触发的方法
        this.borderhover = false
        e.stopPropagation();
        e.preventDefault(); 
        let fileData = e.dataTransfer.files;
        //fileData为上传的图片或者文件,然后操作上传..........
    }
}

在拖拽图片的时候接近设定好的区域,我这里是让边框标为蓝色,这时候鼠标还是拖拽的状态,这里可以按需求来做。

拖拽是后来html5新增的属性,还算方便,欢迎感兴趣是的各位同学讨论。有好的建议我文章中再添加上去。