子组件向父组件发出,父组件更新所有子组件

Posted

技术标签:

【中文标题】子组件向父组件发出,父组件更新所有子组件【英文标题】:Child component emit to parent and parent update all children components 【发布时间】:2017-07-12 16:35:12 【问题描述】:

我正在尝试使用 vue js 2 创建一个包含可扩展项目的列表。这个想法是,当我单击一个项目时,如果它尚未展开,我希望它展开(显示它的内容)并关闭所有其他展开元素。我创建了两个组件expandable-panelexpandable-item。我可以在里面有多种类型的内容,所以我想使用插槽。

我的代码:

ExpandablePanel组件:

<template>
    <div class="expandable-panel" @expanded="doStuff">
        <slot></slot>
    </div>
</template>

<script type="text/babel">
    export default 
        methods: 
            doStuff: function() 
                alert('expanded');
            
        
     
</script>

ExpandableItem 组件:

<template>
    <div class="expandable-item" @click="toggleExpand">
        <div class="expandable-item-header">
             title 
        </div>
        <div class="expandable-item-body" v-if="expanded">
            <slot></slot>
        </div>
    </div>
</template>
<script type="text/babel">
    export default 
        props: 
            title: String
            // expanded: 
            //     type: Boolean,
            //     default: true
            // 
        ,
        data: function() 
            return 
                expanded: true
            
        ,
        methods: 
            toggleExpand: function() 
                this.expanded = !this.expanded;
                this.$emit('expand');
            
        
    
</script>

还有我的 html 文件

<expandable-panel>
    <expandable-item title='title 1'>Lorem ipsum...</expandable-item>
    <expandable-item title='title 2'>Lorem ipsum...</expandable-item>
    <expandable-item title='title 3'>Lorem ipsum...</expandable-item>
</expandable-panel>

我的应用和组件是这样注册的:

Vue.component('expandable-panel',    require('./components/global/ExpandablePanel.vue'));
Vue.component('expandable-item', require('./components/global/ExpandableItem.vue'));
const app = new Vue(
    el: '#app'
);

问题: $emit 部分似乎没有到达父组件内的 @expanded="doStuff"。 即使它到达那里,我如何正确切换 expanded 值?我可以为此使用道具吗?

现在,它会切换每个元素,但我无法更新其他元素。 谢谢

【问题讨论】:

是的,您可以通过 props 控制它,也可以为此探索一些状态管理,例如 vuex。 【参考方案1】:

这里有严格的父子关系,所以你可以通过 $parent 对象发出事件。

首先,在创建父对象时,使用this.$on 监听您的事件:

Vue.component('parent', 
  template: `<div><slot></slot></div>`,
  created: function() 
    this.$on('event', function(message) 
        alert(message);
    )
  
);

然后在您的子组件内部使用$parent.$emit 发出此事件

Vue.component('child', 
  template: `<button @click="$parent.$emit('event', 'From child')">I'm slot</button>`
);

这里是工作演示:https://jsfiddle.net/rdjjpc7a/1754/

【讨论】:

【参考方案2】:

ExpandablePanel 组件中:您应该只有@expand,因为这是您从孩子发出的:

<template>
    <div class="expandable-panel" @expand="doStuff">
        <slot></slot>
    </div>
</template>

【讨论】:

感谢您的回复。我有一个问题。如果doStuff 方法不应该在ExpandablePanel 内部,我应该在哪里定义它? @NightFall 这取决于你想如何构建你的应用程序,父母是否需要知道孩子是否展开?

以上是关于子组件向父组件发出,父组件更新所有子组件的主要内容,如果未能解决你的问题,请参考以下文章

[React] 子组件向父组件通信:回调函数

从动态创建的子组件向父组件发出事件

无法从Vuejs中的子组件向父组件发出事件

Vue.js - 如何在数据对象更改时向父组件发出?

react最简单的子传父方案教学

Vue父组件向子组件传值 (props)、子组件改变父组件的值($emit)