前端上传文件的形式有两种
- 二进制传输 用二进制流的形式传输
- Base64 把文件转为base64字符串传输
文件相关js对象解析
- Blob对象 把文件转化为二进制形式获取为blob对象
- File 通过input标签读取过来的对象(file对象是blob对象的子类所以blob对象的方法file对象也可的使用如slice方法)
- FormData 可以用来搭载blob对象来传输
- FileReader 多用于把文件读取为某种形式,如文本,base64
代码接口部分都为伪代码自己定义即可
FormData搭载二进制形式上传文件
4. <script setup>
5. import axios from 'axios'
6. const f1 = (e) => {
7. //获取到file对象
8. const file = e.target.files[0]
9. //限制文件大小
10. if(file.size > 100000) {
11. alert('文件不能大于10kb')
12. e.target.value = ''
13. return
14. }
15. //限制文件后缀名
16. const name = file.name.split('.')[1]
17. if(name!== 'docx') {
18. alert('文件类型必须是docx')
19. e.target.value = ''
20. return
21. }
22. //通过FormData可以用来搭载数据来传输
23. //1.新建formData对象
24. const from = new FormData()
25. //通过append 方法加入文件
26. from.append('file',file)
27. axios.post('/xxx',from)
28. }
29. </script>
30.
31. <template>
32. <div>
33. <input type="file" @change="f1" />
34. </div>
35. </template>
36.
37. <style scoped>
38. </style>
FileReader把文件读取为base64的形式上传
40. <script setup>
41. import {ref} from 'vue'
42. import axios from 'axios'
43. const imgUrl = ref('')
44. const f1 = (e) => {
45. //获取到file对象
46. const file = e.target.files[0]
47. //限制文件大小
48. if(file.size > 1000000) {
49. alert('文件不能大于100kb')
50. e.target.value = ''
51. return
52. }
53. //限制文件后缀名
54. const name = file.name.split('.')[1]
55. if(name!== 'jpeg') {
56. alert('文件类型必须是docx')
57. e.target.value = ''
58. return
59. }
60. const fileReader = new FileReader()
61. fileReader.readAsDataURL(file)
62. fileReader.onload = () => {
63. //缩略图
64. console.log(fileReader.result)
65. imgUrl.value = fileReader.result
66. axios.post('/xxx',{base64:fileReader.result})
67. }
68. }
69. </script>
70.
71. <template>
72. <div>
73. <input type="file" @change="f1" />
74. <img :src='imgUrl'/>
75. </div>
76. </template>
77.
78. <style scoped>
79. img {
80. width: 100px;
81. }
82. </style>
多文件上传
<script setup>
import {reactive, ref} from 'vue'
import axios from 'axios'
const imgArr = reactive([])
const base64Arr = reactive([])
//多文件上传
const f2 = (e) => {
console.log(e.target.files)
const fileList = e.target.files
for(let i=0; i<fileList.length;i++) {
imgArr.push(fileList[i])
let fr = new FileReader()
fr.readAsDataURL(fileList[i])
fr.onload=()=> {
base64Arr.push(fr.result)
}
}
}
const submit = () => {
imgArr.forEach(file => {
let form = new FormData()
form.append(file.name, file)
axios.post('/xxx',form)
})
}
</script>
<template>
<div>
<input type="file" @change="f2" multiple/>
<img v-for="(item ,index) in base64Arr" :key="index" :src="item" />
<button @click="submit" >上传</button>
</div>
</template>
<style scoped>
img {
width: 100px;
height: 100px;
}
</style>
大文件切片上传和断点续传
- 大文件(获取到文件对象)
- Slice方法切片(对大文件进行切片)
- 部分内容(获取到切片后的部分内容进行上传)
- 记录当前切到哪一位(记录当前上传到哪里)
- 后端拼接切片 (后端对前端切片内容拼接 前端不需要关注)
<script setup>
import {reactive, ref} from 'vue'
import axios from 'axios'
let per = ref(0)
let f3 = async(e) => {
//大文件上传
let file = e.target.files[0]
//slice是blob对象的方法,但是file对象是blod对象的子类
let fileSize = file.size //文件大小
let current = 0; //开始值
let size = 2 * 1024 * 1024 //每次传递2M内容
let localPer = parseInt(localStorage.getItem(file.name))
if(localPer) {
current = localPer
}
while(current < fileSize) {
let _sli = file.slice(current,current + size) // 0-2M、2-4M、4-6M ....
let form = new FormData()
form.append(file.name,_sli)
form.append('partIndex',current)
await axios.post('http://localhost:3000/part',form)
current += size //每次循环累加current
localStorage.setItem(file.name,current)
per.value = Math.min((current/fileSize)*100,100) //Math.min()两个值取最小值 current/fileSize大于1时就会取100
if(per.value == '100') localStorage.removeItem(file.name)
}
}
</script>
<template>
<div>
<input type="file" @change="f3"/>
<div>{{per}}</div>
</div>
</template>
<style scoped>
</style>
实现效果
代码地址
司徒飞/vue-file-server
https://gitee.com/situ_fei/vue-file-server.git
司徒飞/vue-filehttps://gitee.com/situ_fei/vue-file.git