[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: 使用
-
注意事项:
showOpenFilePickerAPI: 这个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…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
CMake 从 GitHub 下载第三方库并使用
有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
elementUI点击浏览table所选行数据查看文档
项目场景: table按照要求特定的数据变成按钮可以点击 解决方案: <el-table-columnprop"mlname"label"名称"align"center"width"180"><template slot-scope"scope"><el-buttonv-if&qu…...
五子棋测试用例
一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏,有着深厚的文化底蕴。通过将五子棋制作成网页游戏,可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家,都可以通过网页五子棋感受到东方棋类…...
绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化
iOS 应用的发布流程一直是开发链路中最“苹果味”的环节:强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说,这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发(例如 Flutter、React Na…...
32位寻址与64位寻址
32位寻址与64位寻址 32位寻址是什么? 32位寻址是指计算机的CPU、内存或总线系统使用32位二进制数来标识和访问内存中的存储单元(地址),其核心含义与能力如下: 1. 核心定义 地址位宽:CPU或内存控制器用32位…...
