v-on 监听器中的 Vue $emit 不起作用

Posted

技术标签:

【中文标题】v-on 监听器中的 Vue $emit 不起作用【英文标题】:Vue $emit inside a v-on listener doesn't work 【发布时间】:2020-04-29 10:43:26 【问题描述】:

我有 3 个组件,一个显示评论,一个显示 cmets 列表,一个管理应显示的内容。

当用户点击评论时,Comment 组件会发出一个“comment-selected”事件,并且 CommentsList 组件会监听它以将其转发(也通过执行 $emit)到 CommentsView 组件。

所以基本上我必须将事件从组件传递给祖父母。

Comment 和 CommentsList 之间的通信正常,我可以在 Vue 开发工具中看到 CommentsList 中的第二个 $emit 也正常工作,但从未触发 CommentsView 上的侦听器。

但是,如果我在 CommentsList 中执行相同的 $emit,但在其他地方,例如在 mount() 而不是“comment-selected”事件侦听器中,它会起作用。

这里是组件:

<template>
  <div>
    <ul class="comments-list list-unstyled">
      <li class="comments-list-item" v-for="comment in comments" :key="comment.id">
        <app-comment :comment="comment" :post-id="postId" @comment-selected="comment => onSelect(comment)" />
      </li>
    </ul>
  </div>
</template>

<script lang="ts">
  import AppComment from './Comment.vue';

  import  Component, Vue, Prop  from 'vue-property-decorator';

  import  Comment  from '@/models/comment';

  @Component(
    name: 'comments-list',
    components: 
      AppComment,
    ,
  )
  export default class CommentsList extends Vue 

    @Prop( type: String, required: true ) private readonly type!: string;
    @Prop( type: Number, required: true ) private readonly postId!: number;
    @Prop( type: Array as () => Comment[], required: true ) private readonly comments!: Comment[];

    private onSelect(comment: Comment) 
      // This function is called and the event is emitted in the Vue dev tools
      this.$emit('comment-selected', comment);
    
  
</script>
<template>
  <div class="comments-view-shape">
    <app-comments-list :type="type" :post-id="postId" :comments="comments" @comment-selected="comment => onSelect(comment)" />
  </div>
</template>

<script lang="ts">
  import AppCommentsList from './CommentsList.vue';

  import  Component, Vue, Prop  from 'vue-property-decorator';

  import  Comment  from '@/models/comment';

  @Component(
    name: 'comments-view',
    components: 
      AppCommentsList,
    ,
  )
  export default class CommentsView extends Vue 

    @Prop( type: String, required: true ) private readonly type!: string;
    @Prop( type: Number, required: true ) private readonly postId!: number;
    @Prop( type: Array as () => Comment[], required: true ) private readonly comments!: Comment[];

    private onSelect(comment: Comment) 
      // This function is never called but if I do an $emit in CommentsList, outside the v-on callback (like in mounted), it works
      console.log(comment);
    
  
</script>

为什么这不起作用?

【问题讨论】:

这似乎是合法的,它可以在没有打字稿的情况下工作 =) 我想知道模板中的箭头函数是否没有改变this 的范围。您是否尝试过使用@comment-selected="onSelect"@comment-selected="onSelect(comment);" 而不是@comment-selected="comment =&gt; onSelect(comment)" @Imarqs,不,它只是让你得到参数,你已经将一个级别传递给发射器。 codesandbox.io/embed/… 。一个小的工作示例,没有 TS。正如我们在 Vue DevTolls 中看到的那样?我们有 2 个事件,一个来自 Comments,我们在 CommentsList 中捕获,另一个来自 CommentsList,我们在 CommentsView 中。 @lmarqs 很遗憾,我可以确认无论有没有箭头功能,它都不起作用。 view-class-component 被弃用了 BtW 【参考方案1】:

好的,我发现了问题,它与事件系统无关,这是我的代码中的错误,它在 Comment 组件中。

CommentsList 是递归的,列表中的评论可以在他内部有一个 CommentsList 组件来显示评论的所有答案。我正在对子级别的 CommentsList(显示答案的那个)进行测试,它只是没有事件侦听器。

总结一下,这就是我所拥有的:

<template>
  <div :id="`comment-$comment.id`" class="comment">
    <div class="comment-shape">
      <div class="comment-data">
        <div class="comment-content" v-html="comment.content"></div>
        <app-comments-list
          type="post" :post-id="postId"
          :comments="comment.childs"
          v-if="hasChilds" />
      </div>
    </div>
  </div>
</template>

我也只需要在这个 CommentsList 中添加一个监听器:

<template>
  <div :id="`comment-$comment.id`" class="comment">
    <div class="comment-shape">
      <div class="comment-data">
        <div class="comment-content" v-html="comment.content"></div>
        <app-comments-list
          type="post" :post-id="postId"
          :comments="comment.childs"
          v-if="hasChilds"
          @comment-selected="comment => onSelect(comment)" />
      </div>
    </div>
  </div>
</template>

这让我想知道是否没有更好的方法来做到这一点,但这是另一个话题。

【讨论】:

以上是关于v-on 监听器中的 Vue $emit 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

自定义事件在 Vue.js 组件中的应用

Vue源码之 $emit

Vue父子组件通信之$emit(基于vue2.5,ES6)

vue2.0中v-on绑定自定义事件的理解

Vue自定义事件

Vue--v-on监听事件