v-on 侦听器中的 Vue $emit 不起作用
Vue $emit inside a v-on listener doesn't work
我有 3 个组件,一个显示评论,一个显示评论列表,一个管理应显示的内容。
当用户单击评论时,Comment 组件会发出一个 "comment-selected" 事件,而 CommentsList 组件会侦听它以将其转发(也通过执行 $emit)到 CommentsView 组件。
所以基本上我必须将一个事件从一个组件传递给它的祖父。
Comment 和 CommentsList 之间的通信正常,我可以在 Vue 开发工具中看到 CommentsList 中的第二个 $emit 也正常工作,但从未触发 CommentsView 上的侦听器。
但是,如果我在 CommentsList 中但在其他地方执行相同的 $emit,例如在 mounted() 而不是 "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>
为什么这不起作用?
好的,我找到了问题,它与事件系统无关,它是我的代码中的一个错误,它在评论组件中。
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>
这让我想知道是否有更好的方法来做到这一点,但这是另一个话题。
我有 3 个组件,一个显示评论,一个显示评论列表,一个管理应显示的内容。
当用户单击评论时,Comment 组件会发出一个 "comment-selected" 事件,而 CommentsList 组件会侦听它以将其转发(也通过执行 $emit)到 CommentsView 组件。
所以基本上我必须将一个事件从一个组件传递给它的祖父。
Comment 和 CommentsList 之间的通信正常,我可以在 Vue 开发工具中看到 CommentsList 中的第二个 $emit 也正常工作,但从未触发 CommentsView 上的侦听器。
但是,如果我在 CommentsList 中但在其他地方执行相同的 $emit,例如在 mounted() 而不是 "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>
为什么这不起作用?
好的,我找到了问题,它与事件系统无关,它是我的代码中的一个错误,它在评论组件中。
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>
这让我想知道是否有更好的方法来做到这一点,但这是另一个话题。