原生实现上传文件预览

获取上传文件信息

原生的 HTML5 通过<input type="file" >属性来上传文件,我们可以采用浏览器提供的 File API 对所选择的文件进行操控。

如果我们希望访问选择的文件,分为两步

  • 获取 DOM 元素
html
1<input type="file" id="input" />
javascript
1const selectFile = document.getElementById('input')
  • 监控 change 事件
javascript
1const selectFile = document.getElementById('input')
2selectFile.addEventListener('change',()=>{
3  console.log(selectFile.files)
4})

通过 DOM 的 files 属性,我们可以得知上传文件的相关信息,比如图中的文件名(name)和大小(size) image 浏览器直接将上传文件存到 fileList 这个数据结构中,这个数据结构可以存很多个文件,如果想要存多个,那么就需要添加 html 属性multiple

html
1<input type="file" multiple id="input" />

难看的上传文件控件

上传文件的控件实在很丑,我们有很多种方法改变它,这里就介绍最常用也是最简单的方式。

第一步,隐藏 input 控件

css
1#input {
2  display: none;
3}

第二步,创建好看的点击区域,这里就用 button 控件吧

html
1<button>上传</button>
javascript
1const selectFile = document.getElementById('input')
2const button=document.querySelector('button') /
3
4selectFile.addEventListener('change',()=>{
5  console.log(selectFile.files)
6})
7
8button.onclick=function (){
9  selectFile.click() // 调用 click函数点击
10}

现在只需要对 button 组件进行样式调整就行啦。

使用 FileReader 对象预览上传的图片

下面,我们需要做一个预览图片的小功能,还是使用上面的代码,不过这里添加一个新的预览区.

我们考虑使用FileReader对象让浏览器异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容。

html
1<div>
2  <input type="file" multiple id="input" />
3</div>
4<button>上传</button>
5<img class="preview" />
css
1#input {
2  display: none;
3}
4.preview {
5  width: 100px;
6  height: 100px;
7}
javascript
1const selectFile = document.getElementById('input')
2const button = document.querySelector('button')
3const preview = document.querySelector('.preview')
4
5selectFile.addEventListener('change', () => {
6  //循环读取 fileList 的file
7  for (let file of selectFile.files) {
8    const imageReg = /image\//g //正则表达式
9   // 检测 file 的 type 属性能否匹配到"image/"
10    if (!imageReg.test(file.type)) {
11      break
12    }
13    // 这里用到 FileReader API创建一个 Reader 读取器
14    let reader = new FileReader()
15    //当 reader 对某文件读取成功后的回调
16    reader.onload = function (e){
17      preview.src=e.target.result
18    }
19    //读取 DataURL后触发onload 回调
20    reader.readAsDataURL(file);
21  }
22})
23
24button.onclick = function() {
25  selectFile.click()
26}

上面代码中readAsDataURL 方法会读取指定的 Blob 或 File 对象。

读取操作完成的时候,readyState会变成已完成 DONE,并触发 loadend (en-US) 事件,同时 result 属性将包含一个 data:URL 格式的字符串(base64 编码)以表示所读取文件的内容。

我们把这个 base64 编码放到创建好的 img 标签的 src 属性上,就可以完成图片的预览。

使用 createObjectURL 预览上传的图片

这个 API 跟readAsDataURL的效果差不多,不过它返回的不是 base64 编码,而是DOMString,我们可以理解为本地内存容器的 URL 地址。

只需要稍微修改一下代码就可以了

javascript
1const selectFile = document.getElementById('input')
2const button = document.querySelector('button')
3const preview = document.querySelector('.preview')
4
5selectFile.addEventListener('change', () => {
6  //循环读取 fileList 的file
7  for (let file of selectFile.files) {
8    const imageReg = /image\//g //正则表达式
9      // 检测 file 的 type 属性能否匹配到"image/"
10    if (!imageReg.test(file.type)) {
11      break
12    }
13    // 这里用到 createObjectURL API生成本地内存 url
14    preview.src = window.URL.createObjectURL(file)
15    preview.onload = function() {
16      //由于每次使用createObjectURL都会产生一个URL 对象。
17      //当你结束使用某个 URL 对象之后,应该通过调用这个方法来让浏览器知道不用在内存中继续保留对这个文件的引用了。
18      window.URL.revokeObjectURL(this.src)
19    }
20  }
21})
22
23button.onclick = function() {
24  selectFile.click()
25}

预览 PDF

createObjectURL 还可以用来生成 PDF 预览,我们可以采用 iframe 标签,让 pdf 展示在 iframe 上

html
1<iframe id="viewer"></iframe>
css
1#viewer {
2  width: 600px;
3  height: 600px;
4  border: 1px solid red;
5}
javascript
1selectFile.addEventListener('change', () => {
2  //循环读取 fileList 的file
3  for (let file of selectFile.files) {
4    const obj_url=window.URL.createObjectURL(file)
5    // 这里用到 createObjectURL API生成本地内存 url
6    iframe.setAttribute('src', obj_url);
7    window.URL.revokeObjectURL(obj_url);
8  }
9})

先介绍这三种比较广泛的预览形式,后续如有需要,我再补充~

enjoy!