Javascript Vue2事件总线在第二次调用后工作

Javascript Vue2事件总线在第二次调用后工作,javascript,html,vue.js,event-handling,vuejs2,Javascript,Html,Vue.js,Event Handling,Vuejs2,我有一个嵌套组件,子组件应该从主实例接收一个参数,但问题是我必须调用事件两次以获取参数 index.html <div id="app"> <button @click="displayComponent">Display</button><br/><hr/> {{ message }} <mycomponent v-if="showComponent" @hide="hideComponents">

我有一个嵌套组件,子组件应该从主实例接收一个参数,但问题是我必须调用事件两次以获取参数

index.html

<div id="app">
    <button @click="displayComponent">Display</button><br/><hr/>
    {{ message }}

    <mycomponent v-if="showComponent" @hide="hideComponents"></mycomponent>
</div>

显示

{{message}}
code.js

window.bus = new Vue();

Vue.component('mycomponent', {
    template: `
        <div>
            <h3>Im the parent component</h3>
            <childcomponent></childcomponent>
            <button @click="$emit('hide')">Hide components</button>
        </div>
    `
});

Vue.component('childcomponent', {
    template:`
        <div>
            <h4>Im the child component</h4>
            <p>{{ data }}</p>
        </div>
    `,

    data() {
        return {
            text: 'Nothing loaded'
        };
    },

    methods: {
        test() {
            alert('hello');
        },

        getData(x) {
            this.text = x;
        }
    },

    created(){
        bus.$on('extraCall', data => {
            this.getData(data);
            this.test();
        });
    }
});

const app = new Vue({
    el: '#app',

    data: {
        message: 'hello world!',
        showComponent: false
    },

    methods: {
        displayComponent() {        
            bus.$emit('extraCall', 'this is some extra text');
            this.showComponent = true;
        },

        hideComponents() {
            this.showComponent=false;
        }
    }
});
window.bus=new Vue();
Vue.component('mycomponent'{
模板:`
Im是父组件
隐藏组件
`
});
Vue.component('childcomponent'{
模板:`
Im是子组件
{{data}}

`, 数据(){ 返回{ 文本:“未加载” }; }, 方法:{ 测试(){ 警惕(“你好”); }, getData(x){ this.text=x; } }, 创建(){ 总线。$on('Extrall',数据=>{ 这个.getData(数据); 这个。test(); }); } }); const app=新的Vue({ el:“#应用程序”, 数据:{ 信息:“你好,世界!”, showComponent:false }, 方法:{ displayComponent(){ 总线。$emit('extraCall','这是一些额外的文本'); this.showComponent=true; }, hideComponents(){ this.showComponent=false; } } });
子组件元素内的文本值被设置为默认值,单击显示按钮后,它将触发
总线。$emit
使用
extraCall
事件并将一些文本作为参数,这将更新文本值,并且仅在第二次单击显示按钮后才会发生

我缺少什么?

(及其子项
)在单击显示按钮时未实例化,因为
v-if=“showComponent”

第一次点击:

  • extraCall
    在总线上发出,但没有该事件的侦听器,因此将忽略该事件
  • 在将
    showComponent
    设置为true后实例化
  • 在其
    创建的
    钩子中注册
    extraCall
    事件的侦听器
  • 第二次点击:

  • extraCall
    在总线上发出,并由
    处理
  • 您可能认为应该交换
    总线。$emit()
    this.showComponent=true
    行,以便在发出事件之前实例化
    ,但这仍然不起作用,因为Vue将组件的创建延迟到更新视图时的下一个微任务

    这可能会奏效:

    displayComponent() {
      this.showComponent = true;
    
      // Wait for child component to be instantiated
      this.$nextTick(() => {  
        bus.$emit('extraCall', 'this is some extra text');
      });
    }
    

    如果上面的代码适合你,我还是不推荐它。在发出事件之前,不需要考虑子组件的创建(它将组件耦合在一起)。您应该以其他方式共享数据,检查关于跨组件共享数据的最佳方式的其他SO问题。

    好的,这确实有效,但正如您所说的,不是最优的,必须有更好的解决方案。但既然它解决了主要问题,我就把它作为一个解决方案,如果我找到一个更好的,我会把它贴在这里。谢谢!好吧,既然你真的很好而且很合作,我想问你,前一段时间我做了一些类似的事情,它工作了,但现在没有,我发现唯一的区别是html文件,显示组件而不是v-if的条件是v-show,当我更改它时,它就工作了。。。使用这个会有任何附带损害吗?。。。AFAIK v-show需要加载更多的内容,但随后只显示右侧,并且每次调用组件时v-if都会创建组件。
    v-show
    仅切换元素上的样式。如果
    v-show
    为false,则组件仍然被创建,只是因为样式而被隐藏(您可以在开发工具中看到)
    v-if
    将实际销毁/创建元素。如果在此处使用
    v-show
    而不是
    v-If
    ,它将与原始代码一起工作。要在<代码> V-IF <代码>和<代码> V-Studio之间进行判断(1)是否需要始终创建的元素?(2) 将元素隐藏在DOM中会影响任何
    :n个子
    CSS选择器吗?(3) 使用
    v-show
    使元素保持活动状态将占用更多内存等。非常感谢您的时间,现在我已经很清楚了。它对我不起作用。