[Vue3 + TS + Vite]文件选择器-组件
文件选择器组件代码
<script setup lang="ts">
import { ref, onMounted, defineProps, defineEmits, computed, toRaw } from 'vue';// 定义props
interface Props {buttonTextUnactive?: string;buttonTextActive?: string;onFatherClick?: boolean;
}// 定义emits
interface Emits {(e: 'file-selected', files: File[]): void;(e: 'picker-canceled'): void;
}const props = defineProps<Props>();
const emits = defineEmits<Emits>();// 状态
const isPickerActive = ref(false);
const selectedFiles = ref<File[]>([]);// 初始化按钮文本
const buttonText = computed(() => {let defaultButtonText = {unactive: '选择文件',active: '文件选择器已打开'};return isPickerActive.value ?(props.buttonTextActive ? props.buttonTextActive : defaultButtonText.active) :(props.buttonTextUnactive ? props.buttonTextUnactive : defaultButtonText.unactive);
});// 文件选择器由父组件click事件响应
const onFatherClick = computed(() => {return props.onFatherClick === true;
});const fatherClick = async () => {console.log('props', props.onFatherClick);console.log('onFatherClick', onFatherClick.value);await openFilePicker(); // 等待文件选择器的结果const result = toRaw(selectedFiles.value);return result; // 返回文件选择的结果
};// 外部触发文件选择器
const handleClick = () => {if (isPickerActive.value) return;openFilePicker();
};// 打开文件选择器
const openFilePicker = async () => {isPickerActive.value = true;try {const files = await window.showOpenFilePicker();selectedFiles.value = Array.from(files);console.log('组件--file-selected');emits('file-selected', selectedFiles.value);} catch (error) {console.log('组件--picker-canceled');emits('picker-canceled');} finally {isPickerActive.value = false;}
};onMounted(() => {// 添加监听器// 清理return () => {};
});defineExpose({fatherClick,
});
</script><template><div><button v-if="onFatherClick" :disabled="isPickerActive">{{ buttonText }}</button><button v-else @click="handleClick" :disabled="isPickerActive">{{ buttonText }}</button><!-- <pre v-if="selectedFiles.length > 0">{{ selectedFiles }}</pre> --></div>
</template>
父组件调用代码
调用方法1-子组件触发Click事件:
<script setup lang="ts">
import { ref } from "vue";const cc_click = ref();const onFileSelected = (files: File[]) => {console.log('父组件--文件已选择:', files);
};const onPickerCanceled = () => {console.log('父组件--文件选择被取消');
};
</script><template><file-selector ref="cc_click" @file-selected="onFileSelected" @picker-canceled="onPickerCanceled" />
</template>
调用方法2-父组件触发Click事件:
<script setup lang="ts">
import { ref } from "vue";const cc_click = ref();const onFileSelected = (files: File[]) => {console.log('父组件--文件已选择:', files);
};const onPickerCanceled = () => {console.log('父组件--文件选择被取消');
};const click_select = async () => {let value = await cc_click.value.fatherClick();console.log('cc_click', value);
};
</script><template><file-selector ref="cc_click" :onFatherClick="true" @click="click_select"@file-selected="onFileSelected" @picker-canceled="onPickerCanceled"/>
</template>
经验笔记
之所以不选择使用input标签file种类,是因为input标签file种类存在原生的缺陷,无法响应文件选择器关闭取消事件。
-
组件设计:
- Props: 定义了三个props:
buttonTextUnactive
,buttonTextActive
, 和onFatherClick
。这些props允许父组件自定义按钮文本和控制文件选择器的触发方式。 - Computed Properties:
buttonText
是一个计算属性,用于根据isPickerActive
和传递的props来动态显示按钮文本。 - State Management: 使用
ref
来管理组件状态,如isPickerActive
和selectedFiles
。 - Exposing Methods: 通过
defineExpose
暴露fatherClick
方法给父组件,以便父组件能够触发文件选择器。
- Props: 定义了三个props:
-
事件处理:
- Emit Events: 使用
emits
定义了两个事件:file-selected
和picker-canceled
。这些事件在文件选择后或用户取消选择时被触发。 - Handling Clicks: 如果
onFatherClick
为true
,则按钮不绑定点击事件,而是等待父组件调用fatherClick
方法。否则,点击事件由组件内部处理。
- Emit Events: 使用
-
模板结构:
- Conditional Rendering: 根据
onFatherClick
的值来条件渲染不同的按钮。 - Button Interaction: 按钮根据
isPickerActive
的值禁用或启用。
- Conditional Rendering: 根据
-
生命周期钩子:
- Setup Cleanup: 使用
onMounted
来添加和移除事件监听器,确保组件正确清理。
- Setup Cleanup: 使用
-
父组件使用:
- Method 1: 使用
ref
获取组件实例,并通过事件监听器来响应文件选择结果。 - Method 2: 通过
ref
调用fatherClick
方法来触发文件选择器,并通过事件监听器来响应文件选择结果。
- Method 1: 使用
-
注意事项:
showOpenFilePicker
API: 这个API需要在安全的上下文中使用,例如HTTPS,并且只在部分现代浏览器中可用。showOpenFilePicker
关闭事件:showOpenFilePicker
没有原生的关闭事件,这里通过try/catch
来模拟文件选择器关闭的情况。
-
调试与测试:
- Console Logs: 在关键位置添加console logs来调试流程。
- Testing Scenarios: 测试不同的场景,包括选择文件、取消选择、多次打开文件选择器等。
结论
这个组件提供了一种灵活的方式来创建文件选择器,允许父组件自定义外观和行为,并通过事件和方法与组件进行交互。它使用Vue 3的现代特性,如<script setup>
语法糖和ref
/computed
,使得代码简洁高效。
参考链接:
Window:showOpenFilePicker() 方法
相关文章:
[Vue3 + TS + Vite]文件选择器-组件
文件选择器组件代码 <script setup lang"ts"> import { ref, onMounted, defineProps, defineEmits, computed, toRaw } from vue;// 定义props interface Props {buttonTextUnactive?: string;buttonTextActive?: string;onFatherClick?: boolean; }// 定…...

Chrome书签搜索插件
效果展示 这是一个chroma插件,可以按住 ctrl/command B 进行搜索您的书签,并且点击打开您的书签。支持上下切换回车打开新页面。 扩展下载地址 bookmark-search 欢迎有任何问题给我提 issues...
MATLAB算法实战应用案例精讲-【人工智能】联邦学习(二)(附python代码实现)
目录 前言 几个高频面试题目 面向隐私保护的机器学习(PPML)和安全机器学习(Secure ML)的区别: 联邦学习、安全计算是什么关系? 联邦学习有哪些类型?如何区分横向联邦学习和纵向联邦学习? 什么是IID?什么是Non-iid? 联邦学习训练后的模型是一个公共的模型,而…...
在 C++ 中实现一个简单的图形用户界面(GUI)应用
在 C 中实现一个简单的图形用户界面(GUI)应用 图形用户界面(GUI)应用程序是现代软件开发中不可或缺的一部分。它们为用户提供了直观的交互方式,使得操作更加简单和高效。本文将介绍如何在 C 中实现一个简单的 GUI 应用…...

如何编写一个CMakeLists.txt文件(由简到难,较详细)
在Linux系统下,经常使用CMakeLists.txt文件来链接、编译C工程,大部分人clone的代码里都是有CMakeLists.txt文件的,只需要cmake .. 和make就完事了,但在工作中,你必须要有从无到有编写CMakeLists.txt文件的能力。 一、…...

数据结构----链表
一丶概念 链表又称单链表、链式存储结构,用于存储逻辑关系为“一对一”的数据。 和顺序表不同同,使用链表存储数据,不强制要求数据在内存中集中存储,各个元素可以分散存储在内存中。 二丶特点 特点:内存不连续…...

【Qt】内置对话框
一.Qt内置对话框 Qt 提供了多种可复⽤的对话框类型,即 Qt 标准对话框。Qt标准对话框全部继承于QDialog类。常⽤标准对话框如下: 二.内置对话框分类 1.消息对话框 QMessageBox 1.1 概念 消息对话框是应⽤程序中最常⽤的界⾯元素。消息对话框主要⽤于为…...
excel常规操作
一、去重 IF(COUNTIF($D$1:D2,D2)>1,"",C2) —— D是去重的列 二、不同列匹配 VLOOKUP(A1,E:F,2,0) vlookup(查找值, 查找区域, 返回查找区域的第几列数据, 精确查找输入参数"0"or"false" 或 模糊查找输入参数"1"or"true…...
uniapp webview子页面向父页面发送数据和触发事件,重点在第3条!!!
1、众所周知H5中iframe可以用过postmessage进行,从H5子页面向H5父页面进行通信。方法如下: // 子页面 window.parent.postMessage({ data: 你的消息 }, *);// 父页面 <iframe src"xxxxxxxxxxx"></iframe> window.addEventListene…...
【STM32实物】基于STM32+ESP32+手机APP设计的智能宠物喂食系统实物源码原理图PCB设计文档演示视频——(文末工程资料下载)
基于STM32+ESP32+手机APP设计的智能宠物喂食系统 演示视频 基于STM32+ESP32+手机APP设计的智能宠物喂食系统 摘 要 近年来,宠物在人们生活中越来越不可或缺,给人们带来的陪伴和快乐。然而,由于种种原因,主人不能时刻照顾宠物的饮食,所以宠物喂食装置变得尤为重要。传…...

EMC学习笔记5——辐射骚扰发射
辐射骚扰发射是基本的实验项目,目的是检验设备在工作时有没有产生意外的过强电磁辐射。 例如发电机,在工作时会产生意外的电磁波辐射,因为电子设备中隐藏了一些天线,这些隐藏的天线在辐射电磁波。 一、两种基本的天线结构 如前面…...

深入理解浏览器解析机制和XSS向量编码
基础部分 1.<a href"%6a%61%76%61%73%63%72%69%70%74:%61%6c%65%72%74%28%31%29">aaa</a> <a>标签可以识别,但是解析不了, 是在协议的编码顺序上,先认协议 URL 编码 "javascript:alert(1)" 2.<a …...

winform 大头针实现方法——把窗口钉在最上层
平时我们再使用成熟的软件的时候,会发现有个大头针的功能挺不错的。就是点一下大头针,窗口就会钉住,一直保持在最上面一层,这样可以一边设置参数,一边观察这个窗口里面的变化,比较方便。下面我就来简单实现…...

中间件|day1.Redis
Redis 定义 Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hash…...

PMP到底有什么用?
PMP 就是项目管理证书,全称是项目管理专业人士资格认证,对于一个在项目管理岗位混迹五年的老油条来说,PMP 证书是敲开项目管理岗位的第一块砖,每年考 PMP 的人都很多,要是 PMP 证书没有价值,还会有那么多人…...
apache huidi 时间旅行Time Travel)机制
Apache Hudi(Hadoop Upserts Deletes and Incrementals)是一个数据管理框架,它帮助你高效地管理存储在分布式存储系统(如HDFS或云存储)上的大型数据集。其一个关键特性是“时间旅行”,这允许你在特定时间点查询数据的历史版本。 什么是Apache Hudi中的时间旅行? Apach…...

Python 数据可视化,怎么选出合适数据的图表
数据可视化最佳实践 1. 引言:为什么数据可视化最佳实践很重要 数据可视化是数据分析和决策过程中不可或缺的一部分。通过有效的可视化,复杂的数据可以转化为易于理解的信息,从而帮助观众快速做出正确的判断。然而,糟糕的可视化可…...
c# 元组
文章目录 元组的定义元组的使用示例使用场景创建一个列表 在 C# 中,元组(Tuple)是一种用于存储多个值的数据结构,它可以方便地将不同类型的多个值打包在一起。元组在 C# 7.0 及更高版本中得到了增强,允许更方便地创建和…...

自定义注解
目录 使用注解定义分布式锁 Aop例子 retention 表示在什么时候可以用,runtime表示在运行期可以用 target表示可以用在哪些上面 inherited表示可以被继承 切点和切面类 重点是 pjp.proceed(args) 这个就是执行目标方法,下面的这一段没啥意思 也可…...

报错:Can‘t find Python executable “python“, you can set the PYTHON env variable
将项目导入vscode,执行npm install命令后,报错了,报错的信息是node-sass安装失败,同时提示需要python环境的错误信息,这是因为安装node-sass失败了,而node-sass依赖于Python环境。 1.报错:Cant find Python…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...