vue 同一页面引用多个重复组件,但不同组件内的数据感觉是混乱的,请问怎么解决?

问题背景

先贴个图说一下我的页面布局:
vue 同一页面引用多个重复组件,但不同组件内的数据感觉是混乱的,请问怎么解决?
如上图,页面中有 5 个重复的子组件,当在某一个组件中点击白色上传区域并选择文件后,对应操作的子组件的白色上传区域会展示当前选中的文件名。

发现问题

现在有个很奇怪的问题是,不管我点击哪一个子组件的白色上传区域,最后选了文件后,文件名都会展示在第一个组件中。明明每个组件的数据是隔离的,这里为啥会这样呢?有点不太理解。
vue 同一页面引用多个重复组件,但不同组件内的数据感觉是混乱的,请问怎么解决?

代码片段

父组件

<template>
<div class="grid gap-0 grid-cols-4 grid-rows-2 h-full pb-8">
  <Card title="导入项目排名" type="projectRank"></Card>
  <Card title="导入申请书初审结果" type="projectFirstTrial"></Card>
  <Card title="导入申请书终审结果" type="projectFinalTrial"></Card>
  <Card title="导入实施方案终审结果" type="executeFinalTrial"></Card>
  <Card title="导入机构对项目的评分" type="projectScore"></Card>
</div>
</template>

<script setup lang="ts">
import Card from "@/components/importDataCard.vue";
</script>

子组件有两个属性,由父组件传入。

子组件

<template>
 //子组件的 template 不止这些,为了给大家减轻阅读负担,我只贴了核心部分
<div class="w-full h-full">
    <div class="mb-6">
        <div class="flex flex-col justify-center items-center w-full h-32">
            <label :for="file ? '' : 'file-input'">
                <div class="flex flex-col justify-center items-center pt-5 pb-6">
                <template v-if="file">
                    <p class="mb-2 text-sm relative text-gray-500 dark:text-gray-400">{{ file.name }}</p>
                  </template>
                 <template v-else>
                      <p class="mb-2 text-sm text-gray-500 dark:text-gray-400">点击上传或拖拽文件到此处</p>
                     <p class="text-xs font-extralight text-gray-500 dark:text-gray-400">仅支持 CSV</p>
                  </template>
                  </div>
                 <input id="file-input" type="file" class="hidden" @change="setFile" accept=".csv"/>
  </label>
              </div>
          </div>
     <div class="mb-6">
          <button type="button">导入数据</button>
      </div>
</div>
</template>

<script setup lang="ts">
import {ref, defineProps} from 'vue';

const props = defineProps({
  type: String,
  title: String
})

const file = ref<File|null>(null)
function setFile(e) {
  file.value = e.target.files[0]
}
</script>

以上就是所有的问题描述,请各位前端大佬分析分析,到底怎么回事呢?

代码是写给人看的,顺便给机器运行一下。
最佳答案

问题解决了,这个问题跟 vue 没有半毛钱关系。在 vue 中创建多个相同子组件,他都有独立且完整的生命周期,并且变量都是隔离的。


下面且说这问题出哪了。

大家看到有一句 <label :for="file ? '' : 'file-input'">,这个 label 标签就指定了白色的上传区域,当 file 未被设置时,这个 for 属性是一个固定值 file-input

下面还有这么一句 <input id="file-input" type="file" class="hidden" @change="setFile",这是最终接收文件的 input 输入框,他的 id 刚好就是上边 label 指定的 id 值。

问题就在于,在一个 DOM 树中,元素的 id 是独一无二的,我的组件有 5 个,都是同样的 ID,就造成了上述奇葩问题。做了如下修改:

错误:

<label :for="file ? '' : 'file-input'">
...
<input id="file-input" type="file" class="hidden" @change="setFile"/>
</label>

正确:

<label :for="file ? '' : type">
...
<input :id="type" type="file" class="hidden" @change="setFile"/>
</label>

注: 以上是把固定的 ID 值替换成了变量 type,这个变量即 props 属性之一,在上面的子组件代码中有定义。

记录一下,希望帮到需要的小伙伴。

1年前 评论
讨论数量: 3

问题解决了,这个问题跟 vue 没有半毛钱关系。在 vue 中创建多个相同子组件,他都有独立且完整的生命周期,并且变量都是隔离的。


下面且说这问题出哪了。

大家看到有一句 <label :for="file ? '' : 'file-input'">,这个 label 标签就指定了白色的上传区域,当 file 未被设置时,这个 for 属性是一个固定值 file-input

下面还有这么一句 <input id="file-input" type="file" class="hidden" @change="setFile",这是最终接收文件的 input 输入框,他的 id 刚好就是上边 label 指定的 id 值。

问题就在于,在一个 DOM 树中,元素的 id 是独一无二的,我的组件有 5 个,都是同样的 ID,就造成了上述奇葩问题。做了如下修改:

错误:

<label :for="file ? '' : 'file-input'">
...
<input id="file-input" type="file" class="hidden" @change="setFile"/>
</label>

正确:

<label :for="file ? '' : type">
...
<input :id="type" type="file" class="hidden" @change="setFile"/>
</label>

注: 以上是把固定的 ID 值替换成了变量 type,这个变量即 props 属性之一,在上面的子组件代码中有定义。

记录一下,希望帮到需要的小伙伴。

1年前 评论

自己动手解决,还能回来把答案贴上,给你点赞👍

现在很多人问题解决了直接就把帖子删了。。

1年前 评论
luci (楼主) 1年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!