使用Vue3制作一款个性化上传组件
目录
前言
技术栈
开发思路
配置一个头像上传组件
实现思路
实现代码
实现效果
FileReader API
功能介绍
核心方法
1.onload回调
2.readAsDataURL(file)
3.readAsText(file)
4.readAsArrayBuffer(file)
关键特性
URL.createObjectURL()
功能介绍
基本用法
关键特性
前言
大家在遇到“文件上传”这个需求时,可能会比较头痛。
原因在于:“使用现有的UI库,如ElementPlus里的el-upload时,定制化程度不够高,想要修改样式非常麻烦,往往出力不讨好”。
而自己制作又比较啰嗦或者压根不知道如何下手,那么阅读本篇文章,带您从头到尾制作一款个性化的上传组件吧!
技术栈
- 基于Vue3的单组件方式开发
- 使用axios进行http通信
开发思路
- 构造一个原生<input>标签用来作为“文件上传”容器,为了美观,可以给这个<input>标签设置为display:none;
- 使用<input>的.click()方法用来打开“文件选择”
- 构造一个validate函数,用来验证文件类型、文件大小
- 给“打开容器”设置一个function方法,用来控制“文件选择”
- 构造FormData对象用来配置文件信息
- 需要预览图片的,可以使用DataUrl用来临时预览图片
配置一个头像上传组件
文件类型有很多,但只要学会一种其余的自然就会了。
在这里,我们配置一个“头像上传组件”
指定图片格式只能为:“png”或“jpg”,并且上传完成后可以预览图片
实现思路
- 配置一个隐藏input作为文件选择器
- 配置一个img,并使用FileReader读取文件
实现代码
<script setup>
import { ref } from 'vue';
const avatarInput = ref(null);
const imgUrl = ref('');
// 打开文件选择器
function openSelector() {avatarInput.value.click();
}
// 验证文件合法性
function validateFile(file) {const validTypes = ['image/jpeg', 'image/png'];const maxSize = 5 * 1024 * 1024;if (!validTypes.includes(file.type)) {alert('请选择正确的图片格式');return false}if (file.size > maxSize) {alert('请上传小于等于5M的图片');return false}return true
}
// 选择文件
function handleFile(event) {const file = event.target.files[0];// 没有文件,直接返回if (!file) {return;}if (validateFile(file)) {const reader = new FileReader();reader.readAsDataURL(file);reader.onload = (e) => {// 上传图片imgUrl.value = e.target.result;}}
}
</script><template><div class="file-container"><!-- 头像 --><div class="avatar-container" @click="openSelector"><img :src="imgUrl" alt="avatar" class="avatar" v-if="imgUrl"><!-- 遮罩层 --><div class="mask"><p class="icon">+</p></div></div><input type="file"accept="image/png,image/jpeg"@change="handleFile"class="input"ref="avatarInput"></div>
</template><style scoped>
/* 输入框none隐藏 */
.input {display: none;
}
/* 头像容器 */
.avatar-container {position: relative;width: 180px;height: 180px;margin: 20px auto;border-radius: 50%;border: 1px solid #ccc;background-color: #ffffff;cursor: pointer;overflow: hidden;
}
/* 悬浮时显示遮罩层 */
.avatar-container:hover .mask {opacity: 0.6;
}
/* 遮罩层 */
.mask {position: absolute;top: 0;display: flex;justify-content: center;align-items: center;width: 100%;height: 100%;border-radius: 50%;background-color: black;opacity: 0;transition: opacity 0.5s;
}
/* +号图标 */
.icon {color: white;font-size: 80px;
}
/* 头像 */
.avatar {width: 100%;height: 100%;object-fit: cover;border-radius: 50%;
}
</style>
实现效果
FileReader API
功能介绍
FileReader是一个用于异步读取文件内容的API,可以将文件内容转为各种格式(文本、Base64编码)。它特别适合处理小型文件(图片、配置文件)
核心方法
1.onload回调
reader.onload = (e) => {// 上传图片imgUrl.value = e.target.result;
}
打印“e”对象为:
可以看到文件的DataUrl存储在:“e.target.result”
2.readAsDataURL(file)
将文件内容转换为DataURL格式,常用于图片预览
注意:该操作完成后,将会立马执行onload回调
3.readAsText(file)
将文件内容转换为文本字符串格式,常用于TXT、JSON等文本文件
注意:该操作完成后,将会立马执行onload回调
4.readAsArrayBuffer(file)
将文件内容转换为二进制数据格式,常用于需要处理二进制的场景(文件校验、音视频处理)
注意:该操作完成后,将会立马执行onload回调
关键特性
- 异步操作:所有读取操作都是异步的,通过回调函数获取结果
- 内存效率低:对于大文件,Base64编码会使文件体积增加
- 兼容性好:支持所有现代浏览器及IE10+
URL.createObjectURL()
功能介绍
URL.createObjectURL(file)用于创建一个指向文件的临时 URL(Blob URL),这个 URL 可以直接被<img>、<video> 等元素使用。
基本用法
// 创建临时URL
const objectURL = URL.createObjectURL(file);// 用于图片预览
previewImg.src = objectURL;// 使用完毕后释放资源(避免内存泄漏)
URL.revokeObjectURL(objectURL);
关键特性
- 高效:直接引用内存中的文件,无需编码转换
- 临时性质:URL仅在当前会话有效,刷新后失效
- 需手动释放:使用完毕后必须调用URL.revokeObjectURL()释放内存
- 兼容性好:支持所有现代浏览器即IE10+