如何将 Vue.js 事件沿组件链传播?

Posted

技术标签:

【中文标题】如何将 Vue.js 事件沿组件链传播?【英文标题】:How to propagate a Vue.js event up the components chain? 【发布时间】:2017-09-19 10:49:29 【问题描述】:

我确实有三个组件。

我对 Datatable 组件的作用没有任何影响,因为我从 npm 获得它。

现在我想从EditButton 向我的Zonelist 发送一个事件。

Zonelist组件:

<template>
<datatable :columns="table_columns" :data="table_rows" filterable paginate v-on:remove="removeItem"></datatable>
</template>
<script>
import datatable from 'vuejs-datatable';
import moment from 'moment';
export default 
    data() 
        return 
            table_columns: [
                label: "Zone", component: 'ZoneLink',
                label: "Last updated", callback (row) 
                    let locale = $('html').closest('[lang]').attr('lang') || 'en';
                    moment.locale(locale);
                    return moment(row.last_updated).format('D. MMM YYYY');
                ,
                label: '', component: 'EditButton'
            ],
            table_rows: [
                
                    "name": "xyz.de",
                    "last_updated": "2017-10-21 17:29:50"
                
            ],
            form: 
                name: '',
                errors: []
            
        ;
    ,
    components: 
        datatable
    ,
    methods: 
            removeItem (item) 
                this.table_rows.forEach((value, index, array) => 
                    if (value.name === item) 
                        Vue.delete(array, index);
                    
                );
            
      

</script>

现在我的EditButton 组件$emit() 是带有参数的remove 事件。

但是什么也没发生。所以我认为vue无法定位到监听器。

(我在这里使用的是 ES6 的方法简写)

如果不通过this.$parent.$parentEditButton 改变Zonelist 的状态,我怎么能正确地做到这一点?

【问题讨论】:

【参考方案1】:

Vue 中的Non parent-child communication 通常通过事件总线或状态管理系统进行处理。

在这种情况下,除非您的应用程序更复杂,否则您可能只需要事件总线。由于您使用的是单文件组件,您可能需要在窗口上声明总线,可能在您的主脚本中。

window.bus = new Vue()

然后在您的EditButton 中,您可以发出事件

bus.$emit('some-event', someData)

您可以在ZoneList 中收听。

bus.$on('some-event', someData => this.doSomething(someData))

【讨论】:

这并没有回答如何通过组件结构传播事件的问题。 @Ryuk 标题中有问题,OP 真正想要的是如何与两个不直接相关的组件进行通信。所以我想如果你只阅读标题并特别想要一种方法来捕获并重新发送到父链,你会是正确的;这个答案没有显示如何做到这一点。 是的,imo 标题应该更新。您确实回答了 OP 的细节。【参考方案2】:

另一种选择是要求DataTable 通过向其添加v:on="$listeners" 属性来传递所有事件。

有关更详细的说明,请参阅https://***.com/a/61329264/578318。

编辑:

更安全的选择是简单地在父类中侦听事件并将其传递...

    <ancestor @message="console.log($event)"> <!-- cute trick see * -->
    ...
    <parent @message="$emit('message', $event)"> <!-- passes it on -->
    ...
    <child @click="$emit('Hello World')"> <!-- creates the event -->

* computed: 'console' : () =&gt; console

【讨论】:

这个答案真的被低估了! Vue 太酷了!【参考方案3】:

默认情况下,如果一个 Vue 组件中只有一个节点(即没有子节点),那么你从父节点附加到它的所有事件都会触发,就像它是一个普通的 HTML 元素一样。 但是,如果您有一个有子节点的子节点怎么办?在这种情况下,您想使用v-on="$listeners"

例子:

<template>
  <div v-on="$listeners">
    <button>Hello world</button>
  </div>
</template>

文档:https://vuejs.org/v2/guide/components-custom-events.html#Binding-Native-Events-to-Components

【讨论】:

以上是关于如何将 Vue.js 事件沿组件链传播?的主要内容,如果未能解决你的问题,请参考以下文章

如何在使用 Vue.js 触发任何事件时创建新组件?

Vue JS 访问“父组件的兄弟组件”的对象

如何在组件 vue.js 内的标签中发出事件

Vue.js - 从孙插槽组件发射没有将 $emit 事件冒泡到父级

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

Vue.js父组件事件处理方法无法正常访问自己的数据