在vuejs 2.0 model.sync
将deprecated。
那么,什么是vuejs 2.0兄弟组件之间的通信的正确方法?
正如我赶在Vue的2.0的想法是,通过使用一个商店或事件总线具有同级通信。
据evan:
另外值得一提的“组件之间传递数据”通常是一个坏主意,因为最终的数据流变得无法跟踪的,非常难以调试。
如果需要由多个组件来共享一个数据片,更喜欢global stores或Vuex。
[Qazxswpoi]
和:
Link to discussion和
.once
已被弃用。道具现在总是单向的下降。为了产生在父范围副作用,一个组件需要明确.sync
而不是依靠隐式绑定的事件。
(所以,他emit
是使用suggest和$emit
)
我很担心,因为:
$on
和store
具有全球知名度(纠正我,如果我错了);我想要的是范围莫名其妙event
或兄弟姐妹组件events
知名度。或许我没赶上的想法。
所以,正确的方法是如何沟通?
随着Vue的2.0,我使用的eventHub机制在stores
证明。
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)
更新请看到qazxsw POI答案,它描述更简单的解决方案。
我知道这是一个老问题,但我想揭露其他沟通渠道,以及如何从一个更高的角度查看应用程序和通信。
首先要了解设计Vue的应用程序时(或实际上,任何基于组件的应用程序)是有依赖于我们正在处理哪些事务有不同的通信类型,他们需要自己的沟通渠道。
商业逻辑:指的是特定于您的应用程序,其目标的一切。
表示逻辑:任何用户与之交互或从来自用户的交互的结果。
这两个问题都涉及到这些类型的通信:
每种类型应使用合适的通信信道。
的信道是一个松散的术语我将使用来指代具体实现为围绕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状态。
为了避免处理的全局状态一切弄得一塌糊涂,我们应分拆存储在多个命名空间模块。
为了编排所有这些通讯和缓解的可重用性,我们应该想到的组件两种不同类型的。
再次,这并不意味着通用组件应该被重复使用或一个应用程序特定容器不能重复使用,但它们有不同的责任。
这些只是简单的Vue组件,它包装其它Vue的部件(一般的或其他的应用程序特定的容器)。这就是Vuex店沟通应该发生这种容器应通过像道具和事件监听器等简单的手段进行通信。
这些容器甚至可以有完全没有原生DOM元素,让通用组件处理这个。
这是范围界定发生。大多数组件不知道店里,此组件应(大部分)使用一个名称空间储存模块与一组有限events
和stores
应用与所提供的Vuex映射器。
这些应该从道具获得他们的数据,使自己的本地数据的变化,并发出简单的事件。大多数时候,他们不应该知道Vuex店存在。
它们也可以被称为集装箱作为自己唯一的责任可能是派遣到其他UI组件。
所以,这一切后,应该怎么我们俩兄弟组件之间的沟通?
它更容易用一个例子就明白了:说我们有一个输入框和它的数据应在整个应用程序共享(在树中的不同地方的兄弟姐妹),并与后端坚持。
与最坏的情况出发,我们的组件将混合表示和业务逻辑。
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店行动对付后端沟通,我们在这里的集装箱并不需要了解爱可信和后端。
好了,我们可以姐弟之间通过父使用// 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)
视图如果我想在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')
}
})
代替。