实现 Vue 文件上传功能

393 阅读1分钟

要实现文件上传,必须要基于原生的 input 框,在此基础上进行封装。

一、实现方案

文件可以通过点击及拖拽两种方式来上传,这两种方式我们都要实现。

我们要封装自己的文件上传组件,需要对原生的 input 框进行处理。这里我们有两种方案:

  • input 框的display 设置为 none,点击我们自己的上传组件时去触发 input 框的点击事件;
<!-- 上传组件 -->
<div 
  class="container" 
  @click="selectFile"
  @dragenter="dragenter"
  @dragleave="dragleave"
  @dragover="dragover"
  @drop="drop"
></div>

<!-- input 输入框可放于组件内 -->
<input type="file" multiple ref="input" @change="onChange" />

CSS

.container {
  width: 200px;
  height: 200px;
  border: 1px dashed #c0ccda;
  border-radius: 6px;
  background-color: #fbfdff;
  cursor: pointer;
}
input {
  // 隐藏 inputdisplay: none;
}

JS

// 点击弹出文件选择框
selectFile() {
  this.$refs.input.click()
},

// 拖拽相关api
dragenter(e) {
  e.preventDefault()
},
dragleave(e) {
  e.preventDefault()
},
dragover(e) {
  e.preventDefault()
},
drop(e) {
  e.preventDefault()
  // 只上传文件
  const files = e.dataTransfer.files
  console.log(files)
  this.$refs.input.files = files
  return
  
  // 上传包括文件夹
  this.files = []
  const items = e.dataTransfer.items
  items.forEach((i) => {
    const entry = i.webkitGetAsEntry()
    this.getFileObj(entry)
    console.log(this.files)
  })
},

// 文件上传逻辑
onChange(e) {
  console.log('文件上传逻辑')
},
  • input 框放在盒子内部,给 input 设置宽高跟父盒子相同,同时设置 input 框透明度为 0 隐藏,这时点击父盒子时实际上是在点击 input 框。
<div class="container">
  <input type="file" multiple ref="input" />
</div>

CSS

.container {
  width: 200px;
  height: 200px;
  border: 1px dashed #c0ccda;
  border-radius: 6px;
  background-color: #fbfdff;
  cursor: pointer;

  input {
    width: 100%;
    height: 100%;
    cursor: pointer;
    opacity: 0;
  }
}

点击上传

上述两种方案都可以实现点击上传。

拖拽上传

上述方案二由于 input 框是直接铺满父盒子的,所以可以直接使用原生 input 的文件拖拽功能。弊端在于无法设置拖拽时的样式。

如果想要更灵活的操作,我们可以使用方案一 + 拖拽 api(组件库的写法)

二、上传

1. 上传多个文件

2. 监控上传进度

3. 取消上传