Vue adopts the component-based development method, so the communication between components is essential: for example, the parent component needs to transfer data to the child component, and the child component informs the parent component of what happens inside it. Therefore, it is particularly important to define a good interface and decouple the components as much as possible, which ensures that different components can develop and test in a relatively independent environment, And it is more convenient to read and understand and reuse components.
Vue communication between as like as two peas is mainly in two ways, usually summarized as props down and events up. Parent components transmit data to child components through props, and sub components send messages to parent components through events, which is exactly the same as React.
Vue2.0 discards events, dispatch and broadcast. It is officially recommended to use global event driven or vuex instead. At present, there are only vm.on, vm.once, vm.off and vm.emit.
props down
The scopes of Vue components are isolated from each other. The parent component can only pass values to the child component through props, and the child component cannot directly call the data of the parent component. In the child component, if you need to call the parameters passed by the parent component, you must explicitly declare props.
Vue.component('child', { props: ['message'], template: '<span>{{ message }}</span>' })
Parent component passes value to child component
<child message="hello!"></child>
Unidirectional data flow
Props transfer value can only be transferred from parent component to child component, and cannot be reversed. Whenever the parent component is updated, props in the child component will be updated automatically. If props is changed in the subcomponent, the Vue console will give a warning. Therefore, if you need to change props in a sub component, you usually assign it as the initial value to a variable, and then the value of the variable, or define a props based value in the calculation attribute.
events up
If the child component needs to convey information to the parent component, you can use v-on binding to customize the event
<div id="counter-event-example"> <p>{{ total }}</p> <button-counter v-on:increment="incrementTotal"></button-counter> <button-counter v-on:increment="incrementTotal"></button-counter> </div>
We bind a custom event increment to the button counter, and the v-on binding event can also be abbreviated as @ increment = "".
Vue.component('button-counter', { template: '<button v-on:click="increment">{{ counter }}</button>', data: function () { return { counter: 0 } }, methods: { increment() { this.counter += 1 this.$emit('increment') } }, }) new Vue({ el: '#counter-event-example', data: { total: 0 }, methods: { incrementTotal() { this.total += 1 } } })
The template of the button counter component contains a button, and its click event will trigger the ($emit) custom event increment. Therefore, each time a button is clicked in the child component, the incrementTotal() method will be called in the parent component.
Non parent-child component communication
The two methods mentioned above are communication between parent-child components, and sometimes non parent-child components also need communication. In the Vue1.0 era, it can be solved through dispatch and broadcast. First dispatch to the root component, and then broadcast to the sub component. In Vue2.0, event bus or vuex is officially recommended. The essence of event bus is a publisher subscriber mode.
- Use an empty Vue instance as the central event bus var bus = new Vue()
- Trigger events in component A (publish messages) bus.$emit('id-selected', 1)
- Listen for events (subscription messages) in the hook created by component B bus.$on('id-selected', function (id) {})
Here is stackoverflow The above example
<div id="example"> <Display></Display> <Increment></Increment> </div>
var bus = new Vue() Vue.component('Increment', { template: `<button @click="increment">+</button>`, data: function() { return {count: 1} }, methods: { increment: function(){ var increment = this.count++ bus.$emit('inc', increment) } } }) Vue.component('Display', { template: `<h3>Clicked: {{count}} times</h3>`, data: function(){ return {count: 0} }, created: function(){ bus.$on('inc', function(num){ this.count = num }.bind(this)) } }) new Vue({ el: "#example", })
Global state management Vuex
Vuex is a state manager of Vue components, which is equivalent to a state manager that only serves Vue Redux . The following figure can well reflect how Vuex enables communication between components.
The following is an example given on Vuex's official website Examples of counters
<div id="app"> <p>{{ count }}</p> <p> <button @click="increment">+</button> <button @click="decrement">-</button> </p> </div>
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment: state => state.count++, decrement: state => state.count-- } }) const app = new Vue({ el: '#app', computed: { count() { return store.state.count } }, methods: { increment() { store.commit('increment') }, decrement() { store.commit('decrement') } } })
In Vuex, the store is a container for component states. An initial state object and two changes functions are defined in the above store. We can obtain the state object through store.state and trigger the state change through the store.commit method. It should be noted that we cannot directly change the state in the store. The only way to change the state in the store is to explicitly commit changes.
summary
- The parent component passes information to the child component using props down
- The child component passes information to the parent component using event up
- global event bus is used for communication of other relationship type components
- Communication between large SPA components use Vuex to manage component status
If you want to use dispatch and broadcast in vue2, you can refer to vue2 component communication -- using dispatch and broadcast