Component communication
Parent child component value transfer
Pass data to subcomponents through props
Parent
<template> <div> <h1>Pass values from parent to child</h1> <child title="My journey with Vue"></child> </div> </template> <script> import child from './Child' export default { components: { child } } </script>
Child
<template> <div> <h1>Props Down Child</h1> <h2>{{ title }}</h2> </div> </template> <script> export default { // props: ['title'], props: { title: String } } </script>
Child parent component value transfer
By listening for subcomponent events
Parent
<template> <div> <h1>Pass value from child to parent</h1> There is no need to change the text here <child :fontSize="hFontSize" @enlargeText="enlargeText"></child> </div> </template> <script> import child from './Child' export default { components: { child }, data () { return { hFontSize: 1 } }, methods: { enlargeText (size) { this.hFontSize += size } } } </script>
Child
<template> <div> <h1 :style="{ fontSize: fontSize + 'em' }">Props Down Child</h1> <button @click="handler">Text increase</button> </div> </template> <script> export default { props: { fontSize: Number }, methods: { handler () { this.$emit('enlargeText', 0.1) } } } </script>
Value transfer of unrelated components
Via EventBus
EventBus is also called event bus. In Vue, you can use the concept of EventBus as a communication bridge, just like all components share the same event center. You can register with the center to send or receive events, so components can notify other components in parallel up and down, but it is too convenient. If you use it carelessly, it will cause a "disaster" that is difficult to maintain, Therefore, a more perfect Vuex is needed as the state management center to raise the concept of notification to the shared state level.
- initialization
First, you need to create an event bus and export it so that other modules can use or listen to it. We can deal with it in two ways. First, create a new. js file, such as eventbus.js
import Vue from 'vue' export default new Vue()
Another way, You can directly initialize the global EventBus in main.js in the project
- Send event
Now there are two unrelated components 01 and 02. When the corresponding operation in component 01 triggers a value change, the numchange event is sent
<!-- 01 --> <template> <div> <h1>Unrelated components-01</h1> <div class="number" @click="sub">-</div> <input type="text" style="width: 30px; text-align: center;" :value="value"> <div class="number" @click="add">+</div> </div> </template> <script> import bus from './eventbus' export default { props: { num: Number }, created () { this.value = this.num }, methods: { sub () { if (this.value > 1) { this.value-- bus.$emit('numchange', this.value) } }, add () { this.value++ bus.$emit('numchange', this.value) } } } </script> <style> .number { display: inline-block; cursor: pointer; width: 20px; text-align: center; } </style>
- Receive event
<!--02--> <template> <div> <h1>Unrelated components-02</h1> <div>{{ msg }}</div> </div> </template> <script> import bus from './eventbus' export default { data () { return { msg: '' } }, created () { bus.$on('numchange', (value) => { this.msg = `You have chosen ${value}Pieces of goods` }) } } </script>
Other means of communication
Operate subcomponents through ref
Parent
<template> <div> <h1>ref Parent</h1> <child ref="c"></child> </div> </template> <script> import child from './Child' export default { components: { child }, mounted () { this.$refs.c.test() this.$refs.c.value = 'hello input' } } </script>
Child
<template> <div> <h1>ref Child</h1> <input ref="input" type="text" v-model="value"> </div> </template> <script> export default { data () { return { value: '' } }, methods: { test () { this.$refs.input.focus() } } } </script>
Vuex
What is Vuex?
State
Vuex uses a single state tree and contains all application level states with one object.
Use mapState to simplify the use of State in view, and mapState returns calculated properties
- Array parameters
// This method is provided by vuex, so you should import it before using it import { mapState } from 'vuex' // mapState returns a calculated property named count and msg // Use count and msg directly in the template computed: { ...mapState(['count', 'msg']), }
- Object parameters
// This method is provided by vuex, so you should import it before using it import { mapState } from 'vuex' // By passing in an object, you can rename the returned calculated property // Use num and message directly in the template computed: { ...mapState({ num: state => state.count, message: state => state.msg }) }
Getter
Getter is the calculation property in the store. mapGetter is used to simplify the use in the view
import { mapGetter } from 'vuex' computed: { ...mapGetter(['reverseMsg']), // Rename and use reverse in the template ...mapGetter({ reverse: 'reverseMsg' }) }
Mutation
The only way to change the state in Vuex's store is to submit the mutation. The mutation in Vuex is very similar to the event: every
Each mutation has a string event type and a callback function (handler). This callback function is us
Where the state change is actually made, and it accepts state as the first parameter
The advantage of using Mutation to change the state is that the state changes can be tracked no matter where they are modified
Modification of status. It can realize advanced time travel debugging function
import { mapMutations } from 'vuex' methods: { ...mapMutations(['increate']), // Pass object to solve the problem of duplicate name ...mapMutations({ increateMut: 'increate' }) }
Action
Action is similar to mutation in that:
- The Action submits the mutation instead of directly changing the status.
- An Action can contain any asynchronous Action.
import { mapActions } from 'vuex' methods: { ...mapActions(['increate']), // Pass object to solve the problem of duplicate name ...mapActions({ increateAction: 'increate' }) }
Module
Due to the use of a single state tree, all the states of the application will be concentrated in a relatively large object. When the application becomes very complex, the store pair
Elephants can become quite bloated.
To solve the above problems, Vuex allows us to divide the store into modules. Each module has its own state
mutation, action, getter, and even nested sub modules
Vuex plug-in
Vuex's store accepts the plugins option, which exposes the hook of each mutation. The vuex plug-in is a function that receives store as a unique parameter:
It is not allowed to modify the state directly in a plug-in -- similar to a component, the change can only be triggered by submitting a mutation.
const myPlugin = store => { // When store is initialized, it is called. store.subscribe((mutation, state) => { // After each mutation, the call is made. // The format of mutation is {type, payload} }) } // use const store = new Vuex.Store({ // ... plugins: [myPlugin] })
Strict mode
In strict mode, whenever a state change occurs and is not caused by the mutation function, an error will be thrown. This ensures that all state changes can be tracked by the debugging tool.
const store = new Vuex.Store({ // ... strict: true })
Simulation Implementation
Implement the install method
- Vuex is a Vue plug-in. First implement the install method agreed by the Vue plug-in
Implement Store class
- Implement the constructor and receive options
- Responsive processing of state
- Implementation of getter
- commit and dispatch methods
install method
function install(Vue) { _Vue = Vue; _Vue.mixin({ beforeCreate() { if (this.$options.store) { _Vue.prototype.$store = this.$options.store; } }, }); }
Store class
class Store { constructor(options) { const { state = {}, getters = {}, mutations = {}, actions = {} } = options; this.state = _Vue.observable(state); this.getters = Object.create(null); Object.keys(getters).forEach((key) => { Object.defineProperty(this.getters, key, { get: () => getters[key](state), }); }); this._mutations = mutations; this._actions = actions; } commit(type, payload) { this._mutations[type](this.state, payload); } dispatch(type, payload) { this._actions[type](this, payload); } }