课程名称:web前端架构师
课程章节:第11周 第五章
主讲老师:张轩
课程内容:开发一个通用的上传组件
之前已经开发了一个比较简单的组件 colorPicker ,这个实现比较简单,对于单元测试的优势并没有很好的体现出来
现在存在的问题
- 缺少复杂组件的经验
- 测试 的优势没有体现出来
下面实现一个通用的上传组件
需求分析
传统的上传方式,通过form 表单
<form
method="post"
enctype="multipart/form-data"
action="http://localhost:3000/upload"
>
<input type="file" name="myFile"/>
<button type="submit">提交</button>
</form>
之前为了测试我写的nodejs上传文件代码,我就是这么写的。现在已经很少有人使用了,基本上都是使用 Ajax
实现的功能,我想到了网盘的上传的的那些功能
- 基本上传流程 - 点击按钮选择,完成上传
- 支持上传文件列表
- 显示
- 文件名称
- 状态可删除
- 显示上传进度
- 有可能有更丰富的显示支持?
- 自定义模版
- 支持初始容器自定义
- 支持上传完毕后自定义
- 支持一系列生命周期钩子事件,上传事件
- beforeUpload
- onProgress
- onSuccess
- onError
- onChange
- 拖拽上传支持
- 断点续传能否实现呢?
分析完之后,我们发现要实现的功能不少
上传的原理
- form 表单
- ajax 上传
上传需要注意的地方
- form 表单enctype 需要设置为 multipart/form-data
- ajax 上传需要设置 content-type 为 multipart/form-data. (使用原生js 时不用设置,axios 需要设置)
下面编写代码
<script setup lang="ts">
// import axios from 'axios'
function uploadFile (e: Event) {
const target = e.target as HTMLInputElement
const files = target.files
if (files) {
const uploadFile = files[0]
const formData = new FormData()
formData.append(uploadFile.name, uploadFile)
const xhr = new XMLHttpRequest()
xhr.addEventListener('load', function () {
console.log(this.responseText)
})
xhr.open('POST', 'http://xxx/api/upload/')
xhr.send(formData)
// axios.post('http://xxx/api/upload/', formData, {
// headers: {
// 'Content-Type': 'multipart/form-data'
// }
// }).then(res => {s
// console.log(res)
// })
}
}
</script>
<template>
<input
type="file"
name="file"
@change="uploadFile"
>
</template>
默认上传文件按钮样式比较难看,我们选择将它隐藏掉,再写个自己的按钮,当点击按钮时触发文件按钮的click 事件
<script setup lang="ts">
import { ref } from 'vue'
const fileRef = ref<HTMLElement | null>(null)
function triggerUpload () {
fileRef.value?.click()
}
</script>
<template>
<input
type="file"
name="file"
ref="fileRef"
:style="{display: 'none'}"
@change="uploadFile"
>
<button @click="triggerUpload">
点击上传
</button>
</template>
上传文件的状态
- 准备 ready
- 上传中 loading
- 上传成功 sucess
- 上传失败 fail
<script setup lang="ts">
import { ref } from 'vue'
type UploadStatus = 'ready' | 'loading' | 'success' | 'fail'
const fileRef = ref<HTMLElement | null>(null)
const uploadStatus = ref<UploadStatus>('ready')
const xhr = new XMLHttpRequest()
function uploadFile (e: Event) {
const target = e.target as HTMLInputElement
const files = target.files
if (files) {
const uploadFile = files[0]
const formData = new FormData()
formData.append(uploadFile.name, uploadFile)
xhr.addEventListener('load', function () {
uploadStatus.value = 'success'
})
xhr.addEventListener('error', function () {
uploadStatus.value = 'fail'
})
xhr.open('POST', 'http://xxx/api/upload/')
uploadStatus.value = 'loading'
xhr.send(formData)
}
}
function triggerUpload () {
fileRef.value?.click()
}
</script>
<template>
<div>
状态<span>{{ uploadStatus }}</span>
</div>
<input
type="file"
name="file"
ref="fileRef"
:style="{display: 'none'}"
@change="uploadFile"
>
<button @click="triggerUpload">
点击上传
</button>
</template>
编写测试
- 判断组件是否正常渲染
- 点击按钮正常上传
- 上传失败后应该展示失败提示,成功后有成功提示
根据这些编写测试用例即可,过程也比较简单。需要注意的是文件上传,可以使用 new Fie 来创建文件对象(https://developer.mozilla.org/zh-CN/docs/Web/API/File/File)
这样上传组件的上传功能就完成了