要实现文件上传,必须要基于原生的 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 {
// 隐藏 input 框
display: 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(组件库的写法)