Vue components communication
I have tw开发者_StackOverflow社区o Vue components:
Vue.component('A', {});
Vue.component('B', {});
How can I access component A from component B? How does the communication work between the components?
Cross-component communication doesn't get much attention in the Vue.js docs, nor are there many tutorials that cover this subject. As components should be isolated, you should never "access" a component directly. This would tightly couple the components together, and thats exactly what you want to prevent doing.
Javascript has an excellent method for communication: events. Vue.js has a built-in event system, mainly used for parent-child communication. From the docs:
Although you can directly access a Vue instance’s children and parent, it is more convenient to use the built-in event system for cross-component communication. It also makes your code less coupled and easier to maintain. Once a parent-child relationship is established, you can dispatch and trigger events using each component’s event instance methods.
Their example code to illustrate the event system:
var parent = new Vue({
template: '<div><child></child></div>',
created: function () {
this.$on('child-created', function (child) {
console.log('new child created: ')
console.log(child)
})
},
components: {
child: {
created: function () {
this.$dispatch('child-created', this)
}
}
}
}).$mount()
Dan Holloran has recently written a piece on his "struggle" with cross-component messaging, in two pieces. This might be helpful to you if you need communication between components that have no parent-child relationship.
Another approach I have experience with (other than using events for communication), is using a central component registry that has a reference to the public API with an instance of a component bound to it. The registry handles requests for a component and returns its public API.
In the context of Vue.js, events would by my weapon of choice.
In addition to pesla' answer take a look at the guide's State Management section under Building large scale apps: http://vuejs.org/guide/application.html#State_Management . I've created a jsfiddle based on that here: https://jsfiddle.net/WarwickGrigg/xmpLg92c/.
This technique works for components too: parent-child, sibling-sibling component relationships etc.
var hub = {
state: {
message: 'Hello!'
}
}
var vmA = new Vue({
el: '#appA',
data: {
pState: {
dA: "hello A"
},
hubState: hub.state
}
})
var vmB = new Vue({
el: '#appB',
data: {
pState: {
dB: "hello B"
},
hubState: hub.state
}
})
Communication between the components can also be established by creating a single global event hub in your Vue application. Something like this:-
var bus = new Vue();
Now you can create custom events and listen to them from any component.
// A.vue
// ...
doThis() {
// do the job
bus.$emit('done-this');
}
// B.vue
// ...
method:{
foo: function()
}
created() {
bus.$on('done-this', foo);
}
More about this can be found from official documentation..
It's best practice to use props
and events
.
There are many examples online, like:
- https://v2.vuejs.org/v2/guide/components.html
- https://alligator.io/vuejs/component-communication
I recommend some reading on the topic.
If the components are siblings and have no parent-child relationship it might be worth checking the architecture of your app.
- Do
A
andB
have a parent child relationship? - Is there a component
C
that is possibly the parent ofA
andB
?
If A
and B
are children of C
, consider using props and events.
Another way is to use props
and sync
, which can be helpful for form data:
- https://medium.com/front-end-hacking/vues-v-model-directive-vs-sync-modifier-d1f83957c57c
For sibling to sibling communication, I found using the parent as an event bus made the logic fairly trivial. Using $root
as an event bus meant additional code to check the scope of components that may not be direct siblings. Using the $parent
means that the scope of the events emitted can be controlled.
The following example is for a TableHeader
component. When clicked it re-orders the data in a table, other headers are no longer active and should not be displayed as such, a computed property cssClass
is used for this.
export default {
name: 'TableHeader',
props: ['sort'],
data() {
return {
direction: this.sort
}
},
computed: {
cssClass() {
if (this.direction === 'none') return '';
return (this.direction === 'descending') ? 'headerSortUp': 'headerSortDown';
}
},
methods: {
clickHeader(event) {
this.direction = (this.direction === 'none' || this.direction === 'descending') ? 'ascending' : 'descending';
//We use the parent as an event bus
this.$parent.$emit('TableHeader:sortChanged', this);
},
sortChanged(element) {
//Dont reset if this is the emitter
if (this === element) return;
this.direction = 'none';
}
},
created() {
this.$parent.$on('TableHeader:sortChanged', this.sortChanged);
},
beforeDestroy: function () {
this.$parent.$off('TableHeader:sortChanged', this.sortChanged)
}
}
Communicate between two Vuejs components has many options. If your components are parent and child then you should use "props" to send data from parent to child and use "events" to communicate from child to parent. If your components are sibling then you need to use "store" else you can use "$root" property.
Parent to child
parent component
<ChildComponent :propsData="dataToPassToChild" />
child component must have property
props: ['propsData']
Child to Parent
child component
this.$emit('messegeToParent', arg1, arg2, ...);
parent component
<ChildComponent @messageToParent="messageReceivedFromChild" />
The below method should be in child component
messageReceivedFromChild(arg1, arg2, ...) {
}
Sibling components
component 1
this.$root.$emit('message1', arg1, arg2, ...);
component 2
this.$root.$on('message1', (arg1, arg2, ...) => {
});
精彩评论