使用Vue3制作一款个性化上传组件

目录

前言

技术栈

开发思路

配置一个头像上传组件

实现思路

实现代码

实现效果

[FileReader API](#FileReader API)

功能介绍

核心方法

1.onload回调

2.readAsDataURL(file)

3.readAsText(file)

4.readAsArrayBuffer(file)

关键特性

URL.createObjectURL()

功能介绍

基本用法

关键特性


前言

大家在遇到"文件上传"这个需求时,可能会比较头痛。

原因在于:"使用现有的UI库,如ElementPlus里的el-upload时,定制化程度不够高,想要修改样式非常麻烦,往往出力不讨好"。

而自己制作又比较啰 嗦或者压根不知道如何下手,那么阅读本篇文章,带您从头到尾制作一款个性化的上传组件吧!

技术栈

  • 基于Vue3单组件方式开发
  • 使用axios进行http通信

开发思路

  1. 构造一个原生**<input>** 标签用来作为"文件上传 "容器,为了美观,可以给这个**<input>** 标签设置为display:none;
  2. 使用**<input>**的.click()方法用来打开"文件选择"
  3. 构造一个validate函数,用来验证文件类型、文件大小
  4. 给"打开容器"设置一个function 方法,用来控制"文件选择"
  5. 构造FormData对象用来配置文件信息
  6. 需要预览图片的,可以使用DataUrl用来临时预览图片

配置一个头像上传组件

文件类型有很多,但只要学会一种其余的自然就会了。

在这里,我们配置一个"头像上传组件"

指定图片格式只能为:"png"或"jpg",并且上传完成后可以预览图片

实现思路

  1. 配置一个隐藏input作为文件选择器
  2. 配置一个img,并使用FileReader读取文件

实现代码

html 复制代码
<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回调

javascript 复制代码
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) 用于创建一个指向文件的临时 URLBlob URL),这个 URL 可以直接被**<img>** 、<video> 等元素使用。

基本用法

javascript 复制代码
// 创建临时URL
const objectURL = URL.createObjectURL(file);

// 用于图片预览
previewImg.src = objectURL;

// 使用完毕后释放资源(避免内存泄漏)
URL.revokeObjectURL(objectURL);

关键特性

  • 高效:直接引用内存中的文件,无需编码转换
  • 临时性质:URL仅在当前会话有效,刷新后失效
  • 需手动释放:使用完毕后必须调用URL.revokeObjectURL()释放内存
  • 兼容性好:支持所有现代浏览器即IE10+
相关推荐
|晴 天|几秒前
我如何用Vue 3打造一个现代化个人博客系统(性能提升52%)
前端·javascript·vue.js
风止何安啊8 分钟前
网页都知道要双向握手才加载!从 URL 到页面渲染,单向喜欢连 DNS 都解析不通
前端·javascript·面试
太极OS14 分钟前
给 AI Skill 做 CI/CD:GitHub + ClawHub + Xiaping 同步发布实战
前端
你_好14 分钟前
Chrome 内置了 AI 工具协议?WebMCP 抢先体验 + 开源 DevTools 全解析
前端·mcp
GISer_Jing15 分钟前
LangChain.js + LangGraph.js 前端AI开发实战指南
前端·javascript·langchain
正在发育ing__19 分钟前
从源码看vue的key和状态错乱的patch
前端
木心术120 分钟前
TypeScript实战进阶:从基础类型到高级类型编程
javascript·ubuntu·typescript
Hello--_--World39 分钟前
浏览器同源策略与跨域问题
javascript
yuqifang42 分钟前
vue3+typescript+vite封装自己的UI组件库并上传至npm
vue.js·arkui
黄林晴43 分钟前
第一次听到 Tauri 这个词,去学习一下
前端