title: Discussing Vue Component Communication Methods
date: 2020-07-09 22:07:47
tags:
- Vue
- Component
Components are the most powerful feature of modern front-end frameworks, but the scope of components is independent of each other. So how do different components communicate with each other?
To build large-scale web applications, modern front-end frameworks have introduced component systems, which abstract templates and logic into reusable components, improving project development efficiency and maintainability. Component communication has always been a frequently discussed topic. Today, let's discuss component communication in Vue.
props#
Props can be used to pass data from a parent component to a child component. Props are custom attributes defined on a component and need to be declared in the props section of the child component.
// Child component
<template>
<div>{{text}}</div>
</template>
<script>
export default {
name: 'Confirm',
props: {
text: {
type: String,
default: ''
},
}
}
</script>
// Parent component
<template>
<confirm :text="text">
</template>
Custom Events#
Custom events can be used to pass data from a child component to a parent component.
// Child component
<template>
<button @click="confirm">Click</button>
</template>
<script>
export default {
name: 'Confirm',
methods: {
confirm() {
this.$emit('confirm',"data")
}
}
}
</script>
// Parent component
<template>
<confirm @confirm="handleConfirm">
</template>
<script>
export default {
methods: {
confirm(data) {
console.log(data);
}
}
}
</script>
The child component can trigger a custom event using this.$emit
, where the first parameter is the custom event name and the second parameter is the data to be passed (optional). The parent component uses @
to listen to the child component's custom event.
Event Bus#
Props are only suitable for data communication between parent and child components. For communication between sibling components, the event bus approach can be used. Here is how it works:
Create eventBus.js
:
import Vue from 'vue';
export default new Vue();
Component that triggers the event:
import eventBus from './eventBus.js';
methods: {
onClick(event) {
eventBus.$emit('clickEvent', event.target);
}
}
Component that listens to the event:
import eventBus from './eventBus.js';
methods: {
onClick(event) {
eventBus.$on('clickEvent', (data) => {
console.log(data);
});
}
}
The event bus provides a global state management system that allows easy data communication between any components.
Vuex#
In large-scale web applications, the above component communication methods may not meet the actual requirements. Vue provides a global state management library called Vuex. Please refer to the official documentation for more details.
$root and $parent#
In each child component of a new Vue instance, the root instance can be accessed through the $root
property. All child components can access or use this instance as a global store. Similar to $root
, $parent
can be used to access the parent component's instance from a child component. Therefore, $root
or $parent
can be used as a bridge to pass data between child components.
Component that triggers the event:
methods: {
onClick(event) {
this.$root.$emit('clickEvent', event.target);
}
}
Component that listens to the event:
methods: {
onClick(event) {
this.$root.$on('clickEvent', (data) => {
console.log(data);
});
}
}
$children#
The parent component can also use $children
to access child components and achieve communication between parent and child components.
this.$children
refers to the direct child components of the current instance. Please note that $children
does not guarantee order and is not reactive.
Be cautious when using
$parent
and$children
. They are mainly used as emergency methods to access components. It is recommended to use props and events for parent-child component communication.
// Parent component
this.$children[0].xx = xx;
$refs#
$refs
can create a reference to a child element or component. $refs
can be used to easily call methods of a child component or access data of a child component.
// Parent component
<template>
<base-input ref="usernameInput"></base-input>
</template>
<script>
export default {
methods: {
focus() {
this.$refs.usernameInput.focus();
}
}
}
</script>
// Child component
<template>
<input ref="input">
</template>
<script>
export default {
methods: {
focus: function () {
this.$refs.input.focus()
}
}
}
</script>
$attrs and $listeners#
$attrs
contains the attributes passed from the parent component to the child component that are not defined in the child component's props (except for class
and style
). $attrs
will be automatically added to the root element of the child component. If you don't want the root element of the component to inherit attributes, you can set inheritAttrs: false
in the component options.
// Child component
Vue.component('base-input', {
inheritAttrs: false,
props: ['label', 'value'],
template: `
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
`
})
// Parent component
<base-input
v-model="username"
required
placeholder="Enter your username"
></base-input>
Similarly, $listeners
can be used to direct all event listeners passed from the parent component to a specific child element of the child component.
Vue.component('base-input', {
inheritAttrs: false,
props: ['label', 'value'],
computed: {
inputListeners: function () {
var vm = this
return Object.assign({},
{
input: function (event) {
vm.$emit('input', event.target.value)
}
}
)
}
},
template: `
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on="inputListeners"
>
</label>
`
})
provide/inject#
provide
and inject
are the implementation of dependency injection in Vue. The provide
option allows us to specify the data/methods we want to provide to descendant components.
// Component providing data
<script>
export default {
provide() {
return {
form: this
};
},
}
</script>
Then, in any descendant component, we can use the inject
option to receive the specified properties we want to add to the component.
<script>
export default {
inject: ["form"],
methods: {
validate() {
console.log(this.form);
}
}
</script>
The principle of Vuex, Vue's official state management library, is also based on provide
and inject
.
Conclusion#
These are the component communication methods in Vue. Different methods are suitable for different scenarios. There is no silver bullet, and you need to choose the appropriate method based on the project requirements.