使用动态组件和自定义事件时的 VueJS 警告

Posted

技术标签:

【中文标题】使用动态组件和自定义事件时的 VueJS 警告【英文标题】:VueJS warning when using dynamic components and custom-events 【发布时间】:2021-04-09 18:57:23 【问题描述】:

所以,我收到了这个警告:

" 无关的非发射事件侦听器 (addNewResource) 已传递给组件,但无法自动继承,因为组件呈现片段或文本根节点。如果侦听器仅用作组件自定义事件侦听器,请使用“发射”选项。”

我不明白为什么。我正在使用带有 2 个自定义事件的动态组件。我尝试将两个发出的事件都添加到两个组件的 emits 对象中。

App.vue

<template>
  <AppHeader />
  <NavigationBar @select-component="selectComponent" />
  <keep-alive>
    <component
      :is="selectedComponent"
      v-bind="componentProps"
      @delete-resource="deleteResource"
      @add-new-resource="addNewResource"
    ></component>
  </keep-alive>
</template>

<script>
import AppHeader from "./components/SingleFile/AppHeader.vue";
import NavigationBar from "./components/NavigationBar.vue";
import LearningResources from "./components/LearningResources.vue";
import AddResource from "./components/AddResource.vue";

export default 
  components: 
    AppHeader,
    NavigationBar,
    LearningResources,
    AddResource,
  ,
  data() 
    return 
      selectedComponent: "learning-resources",
      learningResources: [
        
          name: "Official Guide",
          description: "The official Vue.js documentation",
          link: "https://v3.vuejs.org",
        ,
        
          name: "Google",
          description: "Learn to google...",
          link: "https://www.google.com/",
        ,
      ],
    ;
  ,
  methods: 
    selectComponent(component) 
      this.selectedComponent = component;
    ,
    deleteResource(name) 
      this.learningResources = this.learningResources.filter(
        (resource) => resource.name !== name
      );
    ,
    addNewResource(newResourceObject) 
      const newResource = 
        name: newResourceObject.title,
        description: newResourceObject.description,
        link: newResourceObject.link,
      ;
      this.learningResources.push(newResource);
    ,
  ,
  computed: 
    componentProps() 
      if (this.selectedComponent === "learning-resources") 
        return 
          learningResources: this.learningResources,
        ;
      
      return null;
    ,
  ,
;
</script>

AddResource.vue

<template>
  <base-card>
    <template #default>
      <form @submit.prevent>
        <div>
          <label for="title">Title</label>
          <input type="text" v-model="newResource.title" />
        </div>
        <br />

        <div>
          <label for="description">Description</label>
          <textarea rows="3" v-model="newResource.description" />
        </div>
        <br />

        <div>
          <label for="link">Link</label>
          <input type="text" v-model="newResource.link" />
        </div>

        <button @click="$emit('add-new-resource', newResource)">
          Add Resource
        </button>
      </form>
    </template>
  </base-card>
</template>

<script>
import BaseCard from "./Base/BaseCard.vue";

export default 
  components: 
    BaseCard,
  ,
  emits: ["add-new-resource"],
  data() 
    return 
      newResource: 
        title: "",
        description: "",
        link: "",
      ,
    ;
  ,
;
</script>

LearningResources.vue

<template>
  <base-card v-for="resource in learningResources" :key="resource.name">
    <template #header>
      <h3> resource.name </h3>
      <button @click="$emit('delete-resource', resource.name)">Delete</button>
    </template>

    <template #default>
      <p> resource.description </p>
      <p><a :href="resource.link">View Resource</a></p>
    </template>
  </base-card>
</template>

<script>
import BaseCard from "./Base/BaseCard.vue";

export default 
  components: 
    BaseCard,
  ,
  props: 
    learningResources: Array,
  ,
  emits: ["deleteResource"],
;
</script>

【问题讨论】:

【参考方案1】:

似乎是因为&lt;component&gt; 被用于两个独立的组件,它们都不会发出与另一个相同的事件。

你可以试试disabling each components' attribute inheritance:

export default 
    ...
    inheritAttrs: false
    ...

如果这不符合您的需要,您可以重构逻辑以处理两个发出的事件,即将事件重命名为共享名称,如"addOrDeleteResource",然后确定在App.vue 中发出的事件并处理它相应地。

【讨论】:

传递的props和emits事件没有传递给$attrs,所以我不能使用第一个建议 第一个建议不起作用怎么办?我测试了它,它对我有用。 如果您从我的回答中添加 sn-p:inheritAttrs: falseexport default ... 中的任何位置,它应该可以工作 现在可以了。谢谢。但是现在我有另一个问题,它是如何以及为什么起作用的? =)) 正如错误所说:事件...could not be automatically inherited。因此,通过禁用属性继承,您可以防止编译器运行此步骤并尝试设置组件不需要的自定义事件。不过,我不确定这会如何影响您的其他属性,所以请留意,如果您遇到任何错误,请尝试使用$attrs,就像文档说的那样

以上是关于使用动态组件和自定义事件时的 VueJS 警告的主要内容,如果未能解决你的问题,请参考以下文章

在 Vue js 中动态使用多个页面(组件)

模板template绑定事件和自定义组件Component二级联动

自定event事件之全局初始化中自动触发

vue之props和自定义事件的驼峰命名

打字稿中的样式组件“as”道具和自定义道具

如何在 Vuejs 中设置刷新时的旧输入值