程序员scholar 程序员scholar
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
首页
  • Java 基础

    • JavaSE
    • JavaIO
    • JavaAPI速查
  • Java 高级

    • JUC
    • JVM
    • Java新特性
    • 设计模式
  • Web 开发

    • Servlet
    • Java网络编程
  • Web 标准

    • HTML
    • CSS
    • JavaScript
  • 前端框架

    • Vue2
    • Vue3
    • Vue3 + TS
    • 微信小程序
    • uni-app
  • 工具与库

    • jQuery
    • Ajax
    • Axios
    • Webpack
    • Vuex
    • WebSocket
    • 第三方登录
  • 后端与语言扩展

    • ES6
    • Typescript
    • node.js
  • Element-UI
  • Apache ECharts
  • 数据结构
  • HTTP协议
  • HTTPS协议
  • 计算机网络
  • Linux常用命令
  • Windows常用命令
  • SQL数据库

    • MySQL
    • MySQL速查
  • NoSQL数据库

    • Redis
    • ElasticSearch
  • 数据库

    • MyBatis
    • MyBatis-Plus
  • 消息中间件

    • RabbitMQ
  • 服务器

    • Nginx
  • Spring框架

    • Spring6
    • SpringMVC
    • SpringBoot
    • SpringSecurity
  • SpringCould微服务

    • SpringCloud基础
    • 微服务之DDD架构思想
  • 日常必备

    • 开发常用工具包
    • Hutoll工具包
    • IDEA常用配置
    • 开发笔记
    • 日常记录
    • 项目部署
    • 网站导航
    • 产品学习
    • 英语学习
  • 代码管理

    • Maven
    • Git教程
    • Git小乌龟教程
  • 运维工具

    • Docker
    • Jenkins
    • Kubernetes
  • 算法笔记

    • 算法思想
    • 刷题笔记
  • 面试问题常见

    • 十大经典排序算法
    • 面试常见问题集锦
关于
GitHub (opens new window)
npm

(进入注册为作者充电)

  • 后端开发

  • 前端开发

    • 照片上传组件
      • 1. 组件封装
      • 2. 父组件中如何使用
    • localStorage工具类
    • sessionStorage工具类
    • 对话框组件
    • 消息提示工具类
    • 按钮组件
    • 前端文件上传
    • 前端文件下载
    • 前端数据一致性
    • 后台管理系统组件
  • 开发笔记
  • 前端开发
scholar
2024-12-27
目录

照片上传组件

# 照片上传组件

# 1. 组件封装

<template>
  <div class="photo-upload">
    <el-tooltip content="点击上传照片" placement="top">
      <div
          class="photo-container"
          @click="triggerFileInput"
      >
        <el-image
            v-if="internalPhotoUrl"
            :src="internalPhotoUrl"
            class="photo"
            fit="cover"
        ></el-image>
        <div v-else class="upload-placeholder">
          <el-icon><Plus /></el-icon>
        </div>
      </div>
    </el-tooltip>

    <!-- 隐藏的文件输入框 -->
    <input
        type="file"
        ref="fileInputRef"
        style="display: none"
        @change="handleFileChange"
        accept="image/*"
    />
  </div>
</template>

<script setup>
import { ref, watch } from 'vue';
import { Plus } from '@element-plus/icons-vue';
import request from "@/request/index.js";
import { ElMessage } from 'element-plus';

// 接收 v-model 传递的值
const props = defineProps({
  modelValue: {
    type: String,
    default: ''
  }
});

// 用于触发父组件更新 v-model 的事件
const emit = defineEmits(['update:modelValue']);

// 照片 URL 的内部状态,初始化为父组件传递的值
const internalPhotoUrl = ref(props.modelValue);
// 文件输入框的引用
const fileInputRef = ref(null);

// 监听父组件传递的值变化,并同步到内部状态
watch(() => props.modelValue, (newVal) => {
  internalPhotoUrl.value = newVal;
});

// 触发文件选择框的方法
const triggerFileInput = () => {
  if (fileInputRef.value) {
    fileInputRef.value.click();
  }
};

// 处理文件选择变化的方法
const handleFileChange = async (event) => {
  const file = event.target.files[0];
  if (!file) return;

  const formData = new FormData();
  formData.append('file', file);

  try {
    // 发送上传请求
    const response = await request.post('/upload/uploadAvatar', formData, {
      headers: {
        'Content-Type': 'multipart/form-data',
      },
    });

    if (response.code === 200) {
      // 更新照片 URL
      internalPhotoUrl.value = response.data;
      ElMessage.success('照片上传成功!');

      // 自动更新父组件的 v-model
      emit('update:modelValue', internalPhotoUrl.value);
    } else {
      ElMessage.error(response.msg || '照片上传失败,请重试。');
    }
  } catch (error) {
    console.error('Upload error:', error);
    ElMessage.error('照片上传失败,请重试。');
  }
};
</script>

<style scoped>
.photo-upload {
  width: 120px;
  height: 120px;
}
.photo-container {
  width: 100%;
  height: 100%;
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  display: flex;
  justify-content: center;
  align-items: center;
}
.photo-container:hover {
  border-color: #409EFF;
}
.photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.upload-placeholder {
  font-size: 28px;
  color: #8c939d;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

# 2. 父组件中如何使用

<template>
  <div>
    <photo-uploader v-model="avatarUrl"></photo-uploader>
    <p>当前照片 URL: {{ avatarUrl }}</p>
  </div>
</template>

<script setup>
import { ref } from 'vue';
import PhotoUploader from '@/components/PhotoUploader.vue'; // 请根据实际路径修改

// 父组件中声明一个变量用于绑定照片 URL
const avatarUrl = ref('https://example.com/initial-photo.jpg');
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

解释

  1. modelValue Prop 和 update:modelValue 事件:

    • v-model 在 Vue 3 中等效于 modelValue prop 和 update:modelValue 事件。
    • modelValue 接收父组件传入的照片 URL,update:modelValue 用于向父组件发送更新后的 URL。
  2. 内部状态 internalPhotoUrl:

    • 组件内部使用 internalPhotoUrl 维护当前的照片 URL。
    • 通过监听 props.modelValue 的变化,确保内部状态与父组件传递的值保持同步。
  3. 文件上传成功后自动更新 v-model:

    • 当文件上传成功后,组件会自动调用 emit('update:modelValue', internalPhotoUrl.value),将新的照片 URL 传递给父组件,更新 v-model 绑定的变量。

这样做的好处

  • 简化父组件逻辑:父组件不需要手动监听事件来更新照片 URL,所有的逻辑都封装在 PhotoUploader 组件内部。
  • 增强可复用性:通过 v-model 实现双向绑定,可以方便地在不同的父组件中使用 PhotoUploader 组件,而无需担心事件处理的繁琐。
编辑此页 (opens new window)
上次更新: 2025/03/16, 22:19:39
幂等性
localStorage工具类

← 幂等性 localStorage工具类→

Theme by Vdoing | Copyright © 2019-2025 程序员scholar
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式