【问题标题】:Vue.js emit event from child component not catchedVue.js 从未捕获的子组件发出事件
【发布时间】:2018-05-11 05:18:33
【问题描述】:

我有一个子组件从我的服务器获取一些数据,在获取之前我将加载状态更改为 true,并且我想在获取完成后将其设置为 false。所以我在我的子组件中做了类似的事情:

mounted() {
    this.$emit('update:loadingMessage', 'Loading version options from Artifactory...');
    this.$emit('update:isLoading', true);
    this.fetchVersions();
},

methods: {
    fetchVersions() {
        const promises = [
            this.$http.get(`${process.env.API_URL}/version/front`),
            this.$http.get(`${process.env.API_URL}/version/back`),
        ];
        Promise.all(promises)
            .then((values) => {
                // Do some stuff
            })
            .then(() => {
                this.$emit('update:isLoading', false);
            })
            .catch(requestService.handleError.bind(this));
    },
},

在我的父组件中,我像这样收听这个事件:

<version-selector
    :form="form"
    @update:loadingMessage="updateLoadingMessage"
    @update:isLoading="updateLoadingStatus"
    :isSnapshotVersion="isSnapshotVersion">
</version-selector>

最后在updateLoadingStatus 中,我将isLoading 的值相应地设置为truefalse

updateLoadingMessage(message) {
  this.$log.debug(message);
  this.loadingMessage = message;
},
updateLoadingStatus(status) {
  this.$log.debug(status);
  this.isLoading = status;
},

这对显示或不显示我的loading 组件很有用:

<loading
    v-if="isLoading"
    :loadingMessage="loadingMessage"
    :isGiphy="true">
</loading>

我的问题是第一个发射工作正常,isLoading 值设置为true,但第二个发射不工作,我的isLoading 值永远保持在true...在我的方法中@ 987654335@ 我记录了status 的值,我发现这个方法只被调用了一次。

【问题讨论】:

  • 重要注意事项:首先,您在 .then() 上下文中使用 this.$emit()。您可能会遇到this 引用与 Vue 实例不同的上下文的问题。考虑在输入Promise 之前执行var this_vue_instance = this; 之类的操作,然后改用this_vue_instance.$emit()。至于你的发射捕获问题,我自己没有测试过,但也许在你的事件中使用冒号会产生问题?我会尝试消除它作为一个快速测试,以确保它没有冲突的语法。
  • 他使用箭头语法自动将 this 绑定到外部范围。事件中的冒号不会成为问题,因为 Vue 本身实际上在最新版本之一的 Vue 的 .sync 中将冒号用于它自己的事件。您使用的是哪个版本的 Vue?编辑:带有冒号的属性键可能是个问题。
  • "vue": "^2.5.8"
  • 您所描述的功能与.sync 在Vue 及更高版本的2.3.0 中提供的功能几乎相同。 vuejs.org/v2/guide/components.html#sync-Modifier 实际上 Vue 本身使用了 @update:key 事件,这可能是你问题的根源。
  • 我也尝试过类似v-on:loadingMessage="updateLoadingMessage($event)" v-on:isLoading="updateLoadingStatus($event)" 的方法,但也没有用。

标签: javascript vue.js


【解决方案1】:

我通过在模板中使用v-show 而不是v-if 解决了这个问题。

<loading
  v-show="isLoading"
  :loadingMessage="loadingMessage"
  :isGiphy="true">
</loading>

【讨论】:

  • 非常感谢,从昨天开始我一直在为类似的问题苦苦挣扎。我无法理解 v-if 与此有什么关系。你是自己想出来的还是收到了 VueJS 社区的官方回复?再次感谢!
【解决方案2】:

我知道这是一个老问题,但是我今天偶然发现了类似的情况,终于明白为什么该机制与v-show而不是v-if一起工作。

如果你得到以下&lt;template&gt;标签:

<div>
    <component-a v-if="isLoading" />
    <component-b v-else @set-loading-status="setIsLoading" />
</div>

还有下面的&lt;script&gt;标签:

import ComponentA from './ComponentA'
import ComponentB from './ComponentB'
export default {
    name: 'ParentComponent',
    components: { ComponentA, ComponentB },
    data() {
        return {
            isLoading: false,
        }
    },
    methods: {
        setIsLoading(isLoading) {
            this.isLoading = isLoading
        },
    },
}

看起来不错,对吧?您可以从&lt;component-b&gt; 捕获set-loading-status 事件并将其设置为true。但是您无法再次捕获它以将其设置回false

但是,让我们看看官方Vue docs about v-if and v-show

v-if 是“真正的”条件渲染,因为它确保条件块内的事件侦听器和子组件在切换期间被正确销毁和重新创建。

现在您可以看到,当 isLoading 设置为 true 时,component-b 被销毁,并且您将无法捕获发出的事件以将其更改回 false

因此,在这种特殊情况下,您必须使用v-show 来处理加载状态。

【讨论】:

  • 如果 VueJs v-if 处理组件销毁和重新创建,框架不应该再次创建组件并附加相应的事件吗?我无法用该指令弄清楚这种行为。
  • 是的,我的想法是一样的。但是,捕获该事件的组件是component-b。当isLoading 设置为true 时,component-b 不在模板中,并且无法从子组件简单地捕获事件,因为它不存在。这就是它与 v-show 一起使用的原因。
猜你喜欢
  • 2020-08-07
  • 1970-01-01
  • 2019-05-22
  • 2021-07-18
  • 1970-01-01
  • 1970-01-01
  • 2018-02-20
  • 2018-10-21
  • 2019-07-18
相关资源
最近更新 更多