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

问题描述 投票:76回答:5

在vuejs 2.0 model.syncdeprecated

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

正如我赶在Vue的2.0的想法是,通过使用一个商店或事件总线具有同级通信。

evan

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

如果需要由多个组件来共享一个数据片,更喜欢global storesVuex

[Qazxswpoi]

和:

Link to discussion.once已被弃用。道具现在总是单向的下降。为了产生在父范围副作用,一个组件需要明确.sync而不是依靠隐式绑定的事件。

(所以,他emit是使用suggest$emit

我很担心,因为:

  • 每个$onstore具有全球知名度(纠正我,如果我错了);
  • 这得多创建为每个小细节通信的新店;

我想要的是范围莫名其妙event或兄弟姐妹组件events知名度。或许我没赶上的想法。

所以,正确的方法是如何沟通?

javascript vue.js vuejs2 vue-component vuex
5个回答
73
投票

随着Vue的2.0,我使用的eventHub机制在stores证明。

  1. 定义集中的事件枢纽。 documentation
  2. 现在,在你的组件,你可以放射事件 const eventHub = new Vue() // Single event hub // Distribute to components using global mixin Vue.mixin({ data: function () { return { eventHub: eventHub } } })
  3. 而且听你这样做 this.eventHub.$emit('update', data)

更新请看到qazxsw POI答案,它描述更简单的解决方案。


93
投票

你甚至可以把它缩短,并使用this.eventHub.$on('update', data => { // do your thing }) @alex实例作为全球事件枢纽:

第一部分:

root

第二部分:

Vue

35
投票

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


Communication types

首先要了解设计Vue的应用程序时(或实际上,任何基于组件的应用程序)是有依赖于我们正在处理哪些事务有不同的通信类型,他们需要自己的沟通渠道。

商业逻辑:指的是特定于您的应用程序,其目标的一切。

表示逻辑:任何用户与之交互或从来自用户的交互的结果。

这两个问题都涉及到这些类型的通信:

  • 应用程序状态
  • 亲子
  • 父子
  • 兄弟姐妹

每种类型应使用合适的通信信道。


Communication channels

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

道具(表示逻辑)

在Vue公司的最简单的通信通道直接亲子沟通。应该主要用来传递与表示逻辑或一组受限沿层次结构数据的数据。

参考文献和方法(表示逻辑)

当它没有意义的,使用的道具,让孩子把手从父事件,this.$root.$emit('eventing', data); 就好了。

有些人可能会说,这是家长和孩子之间的紧密耦合,但它是相同的连接,使用道具。如果我们能为道具在合同上达成一致,我们可以为方法合同上达成一致为好。

事件(表示逻辑)

mounted() { this.$root.$on('eventing', data => { console.log(data); }); } setting up a ref on the child component and calling its methods。直接亲子沟通的最简单的沟通渠道。再次,应该用于表示逻辑。

事件总线(两者)

大多数的答案给出了事件总线,这是适用于遥远的成分,或事实上任何沟通渠道的一个很好的替代品。

从很远的上下传递时的道具所有的地方,深入嵌套子组件,几乎没有其他组件需要在这之间这可以成材。

小心:随后被结合自己的事件总线组件的创建必将不止一次 - 导致多个处理程序触发泄漏。我个人从来不觉得在所有的单页的应用程序我设计在过去的事件总线的需求。

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

$on
Item

请记住删除在// A component that binds to a custom 'update' event. var Item = { template: `<li>{{text}}</li>`, props: { text: Number }, mounted() { this.$root.$on('update', () => { console.log(this.text, 'is still alive'); }); }, }; // Component that emits events var List = new Vue({ el: '#app', components: { Item }, data: { items: [1, 2, 3, 4] }, updated() { this.$root.$emit('update'); }, methods: { onRemove() { console.log('slice'); this.items = this.items.slice(0, -1); } } });生命周期挂钩的听众。

集中存储(业务逻辑)

<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script> <div id="app"> <button type="button" @click="onRemove">Remove</button> <ul> <item v-for="item in items" :key="item" :text="item"></item> </ul> </div>是去与Vue的状态管理的方式。它提供的不仅仅是事件的更多了很多,这是准备全面推广应用。

而现在destroyed

[我应该建立vuex店为每个小细节的沟通?

它真正的亮点时:

  • 处理你的业务逻辑,
  • 与后端通信

所以,你的组件能够真正专注于他们注定要的东西,管理用户界面。

这并不意味着你不能使用它的组件逻辑,但我会作用域逻辑的命名空间Vuex模块,只有必要的全球UI状态。

为了避免处理的全局状态一切弄得一塌糊涂,我们应分拆存储在多个命名空间模块。


Component types

为了编排所有这些通讯和缓解的可重用性,我们应该想到的组件两种不同类型的。

  • 应用程序特定的容器
  • 通用组件

再次,这并不意味着通用组件应该被重复使用或一个应用程序特定容器不能重复使用,但它们有不同的责任。

应用程序特定的容器

这些只是简单的Vue组件,它包装其它Vue的部件(一般的或其他的应用程序特定的容器)。这就是Vuex店沟通应该发生这种容器应通过像道具和事件监听器等简单的手段进行通信。

这些容器甚至可以有完全没有原生DOM元素,让通用组件处理这个。

不知何故范围或Vuex兄弟姐妹组件you ask知名度

这是范围界定发生。大多数组件不知道店里,此组件应(大部分)使用一个名称空间储存模块与一组有限eventsstores应用与所提供的Vuex映射器。

通用组件

这些应该从道具获得他们的数据,使自己的本地数据的变化,并发出简单的事件。大多数时候,他们不应该知道Vuex店存在。

它们也可以被称为集装箱作为自己唯一的责任可能是派遣到其他UI组件。


Sibling communication

所以,这一切后,应该怎么我们俩兄弟组件之间的沟通?

它更容易用一个例子就明白了:说我们有一个输入框和它的数据应在整个应用程序共享(在树中的不同地方的兄弟姐妹),并与后端坚持。

与最坏的情况出发,我们的组件将混合表示和业务逻辑。

getters

为了区分这两个问题,我们应该换我们的组件在应用程序特定的容器,并保持表示逻辑到我们的通用输入组件。

我们的输入组件是可重复使用的现在,不知道后端也没有兄弟姐妹。

actions

我们的应用程序特定的容器,现在可以将业务逻辑和演示沟通的桥梁。

// 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>

由于Vuex店行动对付后端沟通,我们在这里的集装箱并不需要了解爱可信和后端。


10
投票

好了,我们可以姐弟之间通过父使用// 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>

让我们假设我们要更新v-on组件时,我们在Parent |-List of items //sibling 1 - "List" |-Details of selected item //sibling 2 - "Details" 单击某个元素。


Details

模板:

List

这里:

  • Parent它是一个事件,这将在<list v-model="listModel" v-on:select-item="setSelectedItem" ></list> <details v-model="selectedModel"></details> 组件调用(见下文);
  • v-on:select-item这是一个List的更新setSelectedItem方法;

JS:

Parent

selectedModel

模板:

//...
data () {
  return {
    listModel: ['a', 'b']
    selectedModel: null
  }
},
methods: {
  setSelectedItem (item) {
    this.selectedModel = item //here we change the Detail's model
  },
}
//...

JS:

List

这里:

  • <ul> <li v-for="i in list" :value="i" @click="select(i, $event)"> <span v-text="i"></span> </li> </ul> 将通过//... data () { return { selected: null } }, props: { list: { type: Array, required: true } }, methods: { select (item) { this.selected = item this.$emit('select-item', item) // here we call the event we waiting for in "Parent" }, } //... 直接父送项目。和家长将其发送到this.$emit('select-item', item)视图

5
投票

如果我想在Vue公司为“黑客”正常的通讯模式,特别是现在select-item已过时,我通常做的是创建一个简单的EventEmitter,处理组件之间的通信。从我的最新项目之一:

Details

有了这个.sync对象,你可以再做,在任何组件:

import {EventEmitter} from 'events'

var Transmitter = Object.assign({}, EventEmitter.prototype, { /* ... */ })

以打造“接收”组件:

Transmitter

再次,这是真正的特定用途。请不要在此基础上的图案整个应用程序,使用类似import Transmitter from './Transmitter' var ComponentOne = Vue.extend({ methods: { transmit: Transmitter.emit('update') } }) 代替。

© www.soinside.com 2019 - 2024. All rights reserved.