为了账号安全,请及时绑定邮箱和手机立即绑定

VueJs 2.0中兄弟组件之间的通信

/ 猿问

VueJs 2.0中兄弟组件之间的通信

撒科打诨 2019-09-20 17:07:41

在vuejs 2.0 model.sync中将被弃用。


那么,在vuejs 2.0中兄弟组件之间进行通信的正确方法是什么?


我在Vue 2.0中发现的想法是通过使用商店或事件总线进行兄弟姐妹的沟通。


据埃文说:


值得一提的是“在组件之间传递数据”通常是一个坏主意,因为最终数据流变得无法跟踪并且很难调试。


如果一个数据需要由多个组件共享,则更喜欢 全局存储或Vuex。


[ 链接到讨论 ]


和:


.once并且.sync已弃用。道具现在总是单向下降。要在父作用域中产生副作用,组件需要显式地emit显示事件而不是依赖于隐式绑定。


(所以,他建议使用$emit和$on)


我很担心因为:


每个store并event具有全球知名度(纠正我,如果我错了);

为每个次要的沟通创建一个新的商店是很重要的;

我想要的是以某种方式或兄弟姐妹组件的可见性范围。或者也许我没有抓住这个想法。eventsstores


那么,如何以正确的方式沟通?


查看完整描述

3 回答

?
眼眸繁星

使用Vue 2.0,我正在使用文档中演示的eventHub机制。


定义集中式事件中心。


const eventHub = new Vue() // Single event hub


// Distribute to components using global mixin

Vue.mixin({

    data: function () {

        return {

            eventHub: eventHub

        }

    }

})

现在在您的组件中,您可以发布事件


this.eventHub.$emit('update', data)

并且倾听你的意思


this.eventHub.$on('update', data => {

// do your thing

})


查看完整回答
反对 回复 2019-09-20
?
慕仙森

您甚至可以缩短它并将根 Vue实例用作全局事件中心:


第1部分:


this.$root.$emit('eventing', data);

第2部分:


mounted() {

    this.$root.$on('eventing', data => {

        console.log(data);

    });

}


查看完整回答
反对 回复 2019-09-20
?
宝慕林4294392

我知道这是一个老问题,但我想揭露其他沟通渠道以及如何从更高的角度查看应用和通信。


沟通类型

在设计Vue应用程序(或实际上是任何基于组件的应用程序)时要首先理解的是,有不同的通信类型取决于我们正在处理的问题,并且它们需要自己的通信通道。


业务逻辑:指特定于您的应用及其目标的所有内容。


表示逻辑:用户与之交互或由用户交互产生的任何内容。


这两个问题与这些类型的沟通有关:


申请状态

亲子

父子

兄弟姐妹

每种类型都应使用正确的通信渠道。


沟通渠道

一个频道是一个松散的术语,我将用它来指代围绕Vue应用程序交换数据的具体实现。


道具(演示逻辑)

Vue中最简单的通信通道,用于直接的父子通信。它主要用于传递与表示逻辑有关的数据或在层次结构中传递受限制的数据集。


参考和方法(演示逻辑)

当使用prop让子进程处理来自父进程的事件没有意义时,在子组件上设置一个ref并调用它的方法就没问题了。


有些人可能会说这是父母和孩子之间的紧密耦合,但它与使用道具的耦合相同。如果我们可以就道具合同达成一致,我们也可以就方法合同达成一致。


事件(演示逻辑)

$emit和$on。直接的儿童 - 家长沟通的最简单的沟通渠道。同样,应该用于表示逻辑。


活动巴士(两者)

大多数答案为事件总线提供了很好的替代方案,事件总线是远程组件可用的通信通道之一,或者事实上的任何东西。


当将道具从远处向上传递到深层嵌套的子组件时,这可以变得有用,几乎没有其他组件需要这些组件。


注意:后续创建绑定到事件总线的组件将被绑定多次 - 导致多个处理程序被触发和泄漏。在我过去设计的所有单页应用程序中,我个人从未觉得需要事件总线。


下面演示了一个简单的错误如何导致泄漏,Item即使从DOM中删除组件仍然会触发。


显示代码段


请记住在destroyed生命周期钩子中删除侦听器。


集中存储(业务逻辑)

Vuex是Vue用于状态管理的方式。它提供的不仅仅是事件,它已经准备好进行全面的应用。


现在你问:


我应该为每次小型沟通创建vuex的商店吗?


它真的很棒:


处理您的业务逻辑,

与后端通信

因此,您的组件可以真正专注于他们想要的事情,管理用户界面。


这并不意味着您不能将它用于组件逻辑,但我会将该逻辑范围限定为仅具有必要全局UI状态的命名空间Vuex模块。


为了避免处理全局状态中的所有内容,我们应该将存储拆分为多个命名空间模块。


组件类型

为了协调所有这些通信并简化可重用性,我们应该将组件视为两种不同的类型。


应用特定容器

通用组件

同样,它并不意味着应该重用通用组件或者不能重用特定于应用程序的容器,但它们具有不同的职责。


应用特定容器

这些只是简单的Vue组件,它包装其他Vue组件(通用或其他特定于应用程序的容器)。这是Vuex商店通信应该发生的地方,这个容器应该通过其他更简单的方式,如道具和事件监听器进行通信。


这些容器甚至可以根本没有本机DOM元素,让通用组件处理这个问题。


范围以某种方式events或stores兄弟姐妹组件的可见性


这是范围发生的地方。大多数组件都不知道存储,并且该组件应该(大多数)使用一个带有限制的命名空间存储模块,getters并actions应用提供的Vuex映射器。


通用组件

这些应该从props接收数据,对自己的本地数据进行更改,并发出简单的事件。大多数时候,他们不应该知道Vuex商店存在。


它们也可以称为容器,因为它们唯一的责任可能是调度到其他UI组件。


兄弟姐妹的沟通

那么,在这之后,我们应该如何在两个兄弟组件之间进行通信?


通过一个例子更容易理解:说我们有一个输入框,它的数据应该在应用程序(树中不同位置的兄弟姐妹)之间共享,并持有后端。


从最糟糕的情况开始,我们的组件将混合表示和业务逻辑。


// MyInput.vue

<template>

    <div class="my-input">

        <label>Data</label>

        <input type="text"

            :value="value" 

            :input="onChange($event.target.value)">

    </div>

</template>

<script>

    import axios from 'axios';


    export default {

        data() {

            return {

                value: "",

            };

        },

        mounted() {

            this.$root.$on('sync', data => {

                this.value = data.myServerValue;

            });

        },

        methods: {

            onChange(value) {

                this.value = value;

                axios.post('http://example.com/api/update', {

                        myServerValue: value

                    })

                    .then((response) => {

                        this.$root.$emit('update', response.data);

                    });

            }

        }

    }

</script>

为了区分这两个问题,我们应该将我们的组件包装在特定于应用程序的容器中,并将表示逻辑保存到我们的通用输入组件中


我们的输入组件现在可以重复使用,并且不了解后端和兄弟姐妹。


// MyInput.vue

// the template is the same as above

<script>

    export default {

        props: {

            initial: {

                type: String,

                default: ""

            }

        },

        data() {

            return {

                value: this.initial,

            };

        },

        methods: {

            onChange(value) {

                this.value = value;

                this.$emit('change', value);

            }

        }

    }

</script>

我们的应用程序专用容器现在可以成为业务逻辑和表示通信之间的桥梁。


// MyAppCard.vue

<template>

    <div class="container">

        <card-body>

            <my-input :initial="serverValue" @change="updateState"></my-input>

            <my-input :initial="otherValue" @change="updateState"></my-input>


        </card-body>

        <card-footer>

            <my-button :disabled="!serverValue || !otherValue"

                       @click="saveState"></my-button>

        </card-footer>

    </div>

</template>

<script>

    import { mapGetters, mapActions } from 'vuex';

    import { NS, ACTIONS, GETTERS } from '@/store/modules/api';

    import { MyButton, MyInput } from './components';


    export default {

        components: {

            MyInput,

            MyButton,

        },

        computed: mapGetters(NS, [

            GETTERS.serverValue,

            GETTERS.otherValue,

        ]),

        methods: mapActions(NS, [

            ACTIONS.updateState,

            ACTIONS.updateState,

        ])

    }

</script>

由于Vuex存储操作处理后端通信,因此我们的容器不需要知道axios和后端。


查看完整回答
反对 回复 2019-09-20

添加回答

回复

举报

0/150
提交
取消
意见反馈 邀请有奖 帮助中心 APP下载
官方微信