本文采用的是 vue 框架, 但是不管什么框架, 原理是相通的, 所以希望大家不要将自己的格局局限在 框架里.
说句题外话, 最近尤雨溪说要开发 vue 3.0 了, 而且听说变动挺大的. 我倒是觉得其实没什么大不了的. 我准备趁着这个机会学习一下 React, 然后找个小项目实践一下. 毕竟学习 vue 3.0 也是学, 学 React 也是学, 那我更想了解下更多的知识.
文件上传功能开发
好了, 言归正传, 使用第三方的组件库, 总是觉得修改起来很麻烦, 所以在最近的项目中才决定自己实现一套文件上传的功能.
其实使用 html 的 input 标签是可以实现文件选择功能的, 然后再将选择的文件通过 http 请求传送到后台就行了. 具体代码如下:
<input id="upload" type="file">
通过将 input 标签的 type 设为 file 就可以实现文件选取的功能了. 然后通过选择器读取选取的文件信息即可.
- let uploadFile = document.querySelector("#uploadMission")
- let form = new FormData()
- form.append('file', uploadFile.files[0])
- form.append('yourData', "helloworld")
yourData 就是你希望传送给后台的除了 file 字段以外的字段, 请求的参数格式为:
{
file: 这里是一大段文件信息,
- yourData: helloworld
- }
所以可以根据实际情况进行传参.
自定义文件上传样式
可是有一个问题, 就是: HTML 的样式很丑, 完全不符合 UI 设计, 而且还不好改. 所以我采取的方案是: 自己定义一个样式, 然后点击的时候实际调用原生的 input 标签. 这样你想让样式展示成什么样都行, 不过记得要将原生的 input 标签进行隐藏哦. 具体代码如下:
- <span class="yourStyle" @click="uploadFile">
- 上传文件
- </span <input id="upload" type="file" @change="doRealUpload" style="display: none;">
当点击 uploadFile 时, 主动调用 input 的 click 事件, 触发文件选择功能, 选取完文件之后, 文件会被读取到 input 标签中. 我们只需要按照上面文件上传功能开发的流程进行处理即可.
有一点需要注意的是: 文件选择完之后会触发 input 标签的 change 事件, 这时候才能读取到文件信息. 所以记得将文件传送至后台的操作放在 doRealUpload 方法中.
解决重复上传同一文件无效问题
经过上面的步骤, 其实已经可以实现自定义文件上传功能了. 但是总有人喜欢将同一个文件经过修改后重复上传. 但是因为 input 的 change 事件是通过文件路径来识别是否为同一文件的, 如果文件名或路径不改, 即使文件内容修改了, 在重复上传时也无法触发 change 事件.
本来我想着将 upload.files[0] 的值置为 null 不就解决了么? 但是这是只读属性了, 根本改不了. 然后我又想着, 应该会有 clear 方法, 将文件信息清空吧? 可惜也没有...
场面一度很尴尬, 于是我就想出了让 input 标签重新加载的方法, 这样等于是将 input 标签进行了初始化, 里面保存的文件信息当然也一并消除啦.
有的人可能会想要通过 DOM 操作重新生成一个新的同样的 input 标签. 这样当然是可行的. 但是这让我觉得采用的 jQuery 的老思想, 并不合符 Vue 以数据为核心的原则. 所以我利用了 Vue 中 v-if 与 v-show 的特性.
Vue 中 v-if 的标签每次是重新加载的, 而 v-show 则是在一开始就进行加载, 随后直接读缓存. 所以我将 input 标签加上 v-if, 然后每次调用 uploadFile 方法的时候将 inputShow 置为 true, 而在文件上传成功后的回调函数中将 inputShow 置为 false. 这样每次点击上传按钮的时候都会重新加载一次 input 标签, 也就是对 input 进行初始化操作.
具体代码如下:
- uploadFile() {
- const vm = this
- vm.inputShow = true
- setTimeout( () => {
- let uploadFile = document.querySelector("#upload")
- uploadFile.click()
- }, 100)
- }
这里之所以要加 setTimeout 方法, 是因为不加的话可能会因为代码执行速度比 DOM 的渲染速度要快而导致, 在执行选择操作的时候报错. 因为执行 click 事件的时候 input 标签还没创建完成呢.
结束语
到这里我们的自定义文件上传功能就完成啦. 如果你喜欢本篇文章记得点关注哦, 你的支持是我继续分享的最大动力.
来源: https://juejin.im/post/5bcee8e4f265da0abc2ba4a2