Engineering of VUE Front End (I) (Mastering Multiple Communication and Data Synchronization of Components)

Keywords: Javascript Vue Attribute

Component Communication

Parent-child component communication
Parent-child props attribute
 Son heir $emit event

These two official documents contain very detailed descriptions that are not explained.
Or raise a chestnut:

//parent.vue parent component
<template>
    <div>
        parent: {{money}}
        <Son1 v-model="money"></Son1>
        <!-- <Son1 :value.sync = "money"></Son1> -->
        //Both can be written in grammar;.sync means synchronization, if you only pass value, you can use v-model.
        
    </div>
</template>

<script>
import Son1 from './Son1'
export default {
    components:{
        Son1
    },
    data(){
        return{
            money:100
        }
    }
}
</script>
//Subcomponent SON
//Single data stream, parent binds an event to child
<template>
    <div>
        son:{{value}}
        <button @click="change">click</button>
    </div>
    
</template>
<script>
export default {
    methods:{
        change(){
            this.$emit('input', this.value+100)
        }
    },
    props:{
        value:{
            type:Number,
            default:1
        }
    },
    data(){
        return{

        }
    }
}
</script>
    • *
Multilevel Data Transfer
$dispatch and $broadcast (Vue1 can be used to implement event flow communication based on component tree structure, vue2 has been removed)

(Father to Sun; Sun to Father;)

dispatch is an event that first triggers on its instance itself and then propagates up the parent chain.
broadcast is an event that propagates down to all descendants of the current instance. As future generations expand into multiple subtrees, event propagation will follow many different "paths". Unless the callback returns true, when the listener callback is triggered along the path, propagation of each path will stop.
//grandoon.vue component
<template>
    <div>
        grandson:{{value}}
        <button @click="changeParent">modify parent</button>
    </div>
    
</template>
<script>
export default {
    methods:{
        changeParent(){
            // this.$parent.$emit('input',300)
            // this.$parent.$parent.$emit('input',300)
            this.$dispatch('input',300)
        }
    },
    props:{
        value:{
            type:Number
        }
    }
}
</script>
//dispatch implementation
/**
 * Recursively propagate an event up the parent chain.
 * Propagate events recursively on the parent chain.
 * @param {String} event
 * @param {...*} additional arguments
 */
// The $dispatch method is defined on the prototype of Vue
// Accept the event name of a string type
Vue.prototype.$dispatch = function (event) {
 // First, execute the $emit trigger event and save the return value in shouldPropagate
 var shouldPropagate = this.$emit.apply(this, arguments)
  
 // If the value returned by the first execution of the $emit method is not true, it is returned directly
 // If the return value is not true, the component logic does not want the event to continue to pass to the parent component.
 if (!shouldPropagate) return
  
 // Get the parent component instance of the current component if the return value of the $emit method is true for the first time
 var parent = this.$parent
  
 // Converting the parameters accepted by the function into arrays
 var args = toArray(arguments)
  
 // use object event to indicate non-source emit on parents
 // Assemble object s based on the parameters of the incoming event name
 args[0] = { name: event, source: this }
  
 // The loop knows the parent component of the component
 while (parent) {
 // Execute the $emit trigger event in the parent component
 shouldPropagate = parent.$emit.apply(parent, args)
  
 // If the parent component $emit returns true, continue to recurse the grandparent component, or stop the loop
 parent = shouldPropagate ? parent.$parent : null
 }
  
 // Finally, return the current component instance
 return this
}
broadcast Realization
Vue.prototype.$broadcast = function (event) {
 // Gets the type of incoming event to determine whether it is a string
 var isSource = typeof event === 'string'
  
 // Correct the value of event, which is used directly when accepting the type of event as a string, or the name attribute on event if it is not a string 
 event = isSource ? event : event.name
  
 // if no child has registered for this event,
 // then there's no need to broadcast.
 // If the subcomponent of the current component does not register the event, it returns directly without broadcast.
 if (!this._eventsCount[event]) return
  
 // Get the subcomponents of the current component
 var children = this.$children
  
 // Converting the parameters accepted by the function into arrays
 var args = toArray(arguments)
  
 // If the incoming event is a string
 if (isSource) {
  // use object event to indicate non-source emit
  // on children
  // Assemble object s based on the parameters of the incoming event name
  args[0] = { name: event, source: this }
 }
    • *
Components pass values, especially ancestor components with span.

Now let's talk about a case, how does component A communicate with component C? How many solutions do we have?

  1. We use VueX for data management, but if there are fewer shared states of multiple components, smaller projects and fewer global states in the project, the use of VueX to achieve this function does not exert the power of VueX.
  2. Using B as a transit station, when A component needs to pass information to C component, B accepts the information of A component, and then uses attributes to pass it to C component. This is a solution, but if there are too many nested components, it will lead to cumbersome code and difficult code maintenance. If the change of state in C needs to be passed to A, use event system. Unified level up transfer.
  3. Customize a Vue central data bus. This situation is suitable for cross-level messaging of components, but it feels a little wasteful to use VueX in projects. But the disadvantage is that when many people cooperate, the code maintainability is low and the code readability is low.
$attrs $listeners

In Vue 2.4, to address this requirement, $attrs and $listeners were introduced, and the inherit Attrs option was added.

$attrs  (Attribute Set)
$listeners (Method Set)
v-bind="$attrs", v-on="$listeners"

$attrs Including inaction in parent scope prop Recognized (And obtain) Feature binding (class and style Except)

provide inject

1.provide is equivalent to the enhanced version parent component prop
2. Inj is equivalent to props for enhanced version subcomponents

Because both of the above can interact with parent component and child component, grandchild component, great-grandson.... component data, that is to say, not limited to the parent-child component data interaction of prop, as long as the declaration provided at the upper level, then the next level can access provide data through inject ion no matter how deep.

//Parent component
<template>
    <div class="test">
        <son prop="data"></son>
    </div>
</template>
 
<script>
export default {
    name: 'Test',
    provide: {
        name: 'Garrett'
    }
//Sun component (parent component -- child component -- root component)
<template>
    <div>
        {{name}}
    </div>
</template>
 
<script>
export default {
    name: 'Grandson',
    inject: [name]
}
</script>

Disadvantages:
There are also obvious drawbacks. Access at any level makes data tracing more difficult. It is not known which level declares this or which level or several levels are used. Therefore, this attribute is not usually recommended to use vuex with vuex, but it is not recommended to use multi-reference layers with vuex. When developing component libraries, it can be used well without depending on vuex and without knowing the user's environment.

event bus

The way to achieve this is to introduce a new instance of vue into the brothers'components to communicate with each other, and then realize communication and parameter transfer by calling event triggering and monitoring of the instance separately.

With Evetbus

In the Send Component
`
EventBus.$emit("hello", this.number);`

In the Acceptance Component
`
EventBus.$on("hello", (number) = > {

console.log(number)

});`

Use case

Be careful

  1. $bus.on should be used within the create hook, and if mounted, it may not receive events from other components within the create hook.

    1. With $bus.on, you should use $bus.off again in the beforeDestroy hook, because after the component is destroyed, there is no need to store the listener handle in vue-bus.

Posted by kind on Tue, 20 Aug 2019 03:22:52 -0700