关键代码:
// 触发文件选择 const triggerFileSelect = (event?: Event) => { console.log("触发文件选择"); console.log("事件目标:", event?.target); console.log("当前目标:", event?.currentTarget); console.log("事件路径:", event?.composedPath()); if (fileInputRef.value) { fileInputRef.value.click(); } }; <!-- 上传按钮 --> <div v-if="actionLayout.includes(`upload`) && fileSources.length < props.maxCount" class="upload-button-container" title="点击上传文件" @click="triggerFileSelect"> <!-- 上传图标 --> <!-- <el-icon> <Plus /></el-icon> --> <!-- 上传按钮(包含上传图标) --> <el-button type="primary" :icon="Plus" circle size="small" /> <input ref="fileInputRef" type="file" multiple style="display: none" @change="handleFileSelect" /> </div>点击一下div(class="upload-button-container"),执行两次triggerFileSelect,多次触发(事件冒泡)的应用情况:
这个问题是因为事件冒泡导致的多次触发。当你点击上传按钮时,事件触发了两次:
第一次是你实际点击
div.upload-button-container时触发第二次是因为
fileInputRef.value.click()触发了 input 的 click 事件,这个事件又冒泡到了父元素
可以修改代码,在调用triggerFileSelect时传递事件对象,并在触发 input 点击前阻止事件冒泡:
vue
<script setup lang="ts"> // ... 其他代码保持不变 ... // 触发文件选择 const triggerFileSelect = (event?: Event) => { console.log("触发文件选择"); console.log("事件目标:", event?.target); console.log("当前目标:", event?.currentTarget); console.log("事件路径:", event?.composedPath()); // 阻止事件冒泡,避免多次触发 if (event) { event.stopPropagation(); } if (fileInputRef.value) { fileInputRef.value.click(); } }; // ... 其他代码保持不变 ... </script> <template> <div class="file-selector-container"> <!-- 文件列表区域 --> <div class="file-list-container"> <!-- ... 其他代码保持不变 ... --> <!-- 上传按钮 --> <div v-if="actionLayout.includes(`upload`) && fileSources.length < props.maxCount" class="upload-button-container" title="点击上传文件" @click="triggerFileSelect($event)"> <!-- 这里传递 $event --> <!-- 上传图标 --> <!-- <el-icon> <Plus /></el-icon> --> <!-- 上传按钮(包含上传图标) --> <el-button type="primary" :icon="Plus" circle size="small" /> <input ref="fileInputRef" type="file" multiple style="display: none" @change="handleFileSelect" /> </div> </div> <!-- ... 其他代码保持不变 ... --> </div> </template>或者,更简单的解决方案是直接阻止 input 元素的点击事件冒泡:
vue
<template> <div class="file-selector-container"> <!-- 文件列表区域 --> <div class="file-list-container"> <!-- ... 其他代码保持不变 ... --> <!-- 上传按钮 --> <div v-if="actionLayout.includes(`upload`) && fileSources.length < props.maxCount" class="upload-button-container" title="点击上传文件" @click="triggerFileSelect"> <!-- 上传图标 --> <!-- <el-icon> <Plus /></el-icon> --> <!-- 上传按钮(包含上传图标) --> <el-button type="primary" :icon="Plus" circle size="small" /> <!-- 添加 @click.stop 阻止事件冒泡 --> <input ref="fileInputRef" type="file" multiple style="display: none" @change="handleFileSelect" @click.stop /> </div> </div> <!-- ... 其他代码保持不变 ... --> </div> </template>
第二种方法更简洁,直接在 input 元素上使用@click.stop阻止其点击事件冒泡到父元素,这样就不会触发两次了。
选择其中一种方法即可解决问题。推荐第二种方法,因为它更简洁且语义更清晰。
修改后的代码:
// 触发文件选择 const triggerFileSelect = (event?: Event) => { console.log("触发文件选择"); console.log("事件目标:", event?.target); console.log("当前目标:", event?.currentTarget); console.log("事件路径:", event?.composedPath()); if (fileInputRef.value) { fileInputRef.value.click(); } }; <!-- 上传按钮 --> <div v-if="actionLayout.includes(`upload`) && fileSources.length < props.maxCount" class="upload-button-container" title="点击上传文件" @click="triggerFileSelect"> <!-- 上传图标 --> <!-- <el-icon> <Plus /></el-icon> --> <!-- 上传按钮(包含上传图标) --> <el-button type="primary" :icon="Plus" circle size="small" /> <!-- 使用 @click.stop 阻止事件冒泡,从而解决点击div(class="upload-button-container"),执行两次triggerFileSelect --> <input ref="fileInputRef" type="file" multiple style="display: none" @change="handleFileSelect" @click.stop /> </div>应用效果: