Vue $ emit внутри слушателя v-on не работает - PullRequest
1 голос
/ 12 января 2020

У меня есть 3 компонента, один для отображения комментария, один для отображения списка комментариев и один для управления тем, что должно отображаться.

Когда пользователь нажимает на комментарий, компонент «Комментарий» выдает « события comment-selected "и компонент CommentsList прослушивают его, чтобы переслать его (выполнив также $ emit) в компонент CommentsView.

Так что в основном я должен передать событие от компонента к его родителю.

Связь между Comment и CommentsList работает, и я вижу в инструментах Vue dev, что работает и второй $ emit внутри CommentsList, но слушатель CommentsView никогда не запускается.

Однако, если я делаю то же самое $ emit в CommentsList, но где-то еще, как в 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>

Почему это не работает?

1 Ответ

1 голос
/ 12 января 2020

Хорошо, я нашел проблему, и она не имеет ничего общего с системой событий, это была ошибка в моем коде, и это было в компоненте 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>

И мне просто нужно было добавить слушателя в этот список комментариев:

<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>

Что заставляет меня задуматься, нет ли лучшего способа сделать это, но это еще одна топика c.

...