There are father-child relationship, brother relationship, and generational relationship between components. For different scenarios, choose a more suitable communication mode.

Method 1. Props /$emit

Data communication between parent and child components

  • The props is basically the child component receiving data passed by the parent component
  • $emitIs a method by which a child triggers a parent, passing data to the parent via arguments
Parent component parent. vue <template><div class="parent">
        <Child :obj="obj" @my-event="myEventHandle"></Child>
    </div>
</template>
<script>
import Child from "./Child.vue"
export default {
    data () {
        return {
            obj: {
                a: 1.b: 2}}},components: {
        Child
    },
    methods: {
        myEventHandle (data) {
            console.log(data)
        }
    }
}
</script>

Copy the code
Child component child.vue <template><div class="child">
        <button @click=$emit('my-event', 'data sent from child to parent ')>click me</button>
    </div>
</template>
<script>
export default {
    props: {
        obj: {
            type: Object.default: () = > ({}) / / {}
            // default: function () {
            // return {}
            / / / /} {}
            // default: () => {} // undefined}}}</script>

Copy the code

Default: () => {}. If obj is not passed, obj is undefined. Use either method

The sync modifier

Shorthand for simulating a two-way data flow between components, the schema triggering event of Update :myPropName is recommended.

The parent component < template ><div class="about">
        <div>The sync modifier</div>
        <! -- <SyncDemo :title="title" @update:title="title = $event"></SyncDemo> -->
        <SyncDemo :title.sync="title"></SyncDemo>
    </div>
</template>
<script>
import SyncDemo from "./SyncDemo.vue"
export default {
    data () {
        return {
            title: "sync demo"}},components: {
        SyncDemo
    }
}
</script>

Copy the code
Subcomponents < template ><div>
        <div>{{title}}</div>
        <button @click="$emit('update:title', 'change title')">change title</button>
    </div>
</template>
<script>
export default {
    props: ["title"]}</script>
Copy the code

Note with.syncThe modifierv-bindCannot be used with expressions. Multiple attributes can be used at the same time

v-model

A V-Model on a component makes use of a prop named Value and an event named Input by default

The parent component < template ><div class="about">
        <div>V-model Component Custom input component {{cval}}</div>
        <! -- <VmodelComponent :value="cval" @input="cval = $event"></VmodelComponent> -->
        <VmodelComponent v-model="cval"></VmodelComponent>
    </div>
</template>
<script>
import VmodelComponent from "./VmodelComponent.vue"
export default {
    data () {
        return {
            val: ""}},components: {
        VmodelComponent
    }
}
</script>
Copy the code
Subcomponents < template ><div class="about">
        <input :value="value" @input="$emit('input', $event.target.value)"/>
    </div>
</template>
<script>
export default {
    props: ["value"]}</script>

Copy the code

eventBus

An empty Vue instance acts as the central event bus (event hub), which is used to trigger and listen for events, enabling communication between any component, including parent, sibling, and cross-level, in a clever and lightweight way.

Global registration

main.js
// Define the event car
const bus = new Vue()
Vue.prototype.$bus = bus
Copy the code

Local registration

eventBus.js
import Vue from 'vue'
export default const bus = new Vue()
Copy the code

implementation

Trigger the eventHandle event with parametersthis.$bus.$emit("eventHandle"."Sibling components pass data") listens for the custom event eventHandle on the current instance, receiving collateral arguments via a callbackthis.$bus.$on("eventHandle".function (data) {
    console.log(data)}) removes custom event listeners in beforeDestorythis.$bus.$off("eventHandle")
Copy the code

Method 3: Vuex

Please refer to the Vuex website

Shopping cart instance

Provide /inject

This pair of options needs to be used together to allow an ancestor component to inject a dependency into all of its descendants, regardless of how deep the component hierarchy is, and remain in effect for as long as its upstream and downstream relationships are established.

The ancestor component injection relies on provideVal, and when the button is clicked to modify the data val in data, the descendant component is not updated in real time.

Ancestor component Provide. Vue <template><div>
        {{val}}
        <button @click="changeHandle">change val</button>
        <Inject />
    </div>
</template>
<script>
import Inject from './Inject.vue'
export default {
    data () {
        return {
            val: "Parent component data val"
        }
    },
    provide () {
        return {
            provideVal: this.val
        }
    },
    methods: {
        changeHandle () {
            this.val = "Change the parent component's data val"}},components: {
        Inject
    }
}
</script>

Copy the code
Descendant component inject.vue <template><div>
        <div>Receive injection dependencies: {{provideVal}}</div>
    </div>
</template>
<script>
export default {
    inject: ["provideVal"]}</script>

Copy the code

Provide and inject binding are not responsive. This is intentional. However, if you pass in a listening object (via function injection), the object’s property is still responsive.

Ancestor component Provide. Vue <template><div>
        {{val}}
        <button @click="changeHandle">change val</button>
        <Inject />
    </div>
</template>
<script>
import Inject from './Inject.vue'
export default {
    data () {
        return {
            val: "Parent component data val"
        }
    },
    provide () {
        return {
            provideVal: () = > this.val
        }
    },
    methods: {
        changeHandle () {
            this.val = "Change the parent component's data val"}},components: {
        Inject
    }
}
</script>

Copy the code
Descendant component inject.vue <template><div>
        <div>Receive injection dependencies: {{provideVal()}}</div>
        <div>{{provideValNew}}</div>
    </div>
</template>
<script>
export default {
    inject: {
        provideVal: {
            default: () = >({})}},computed: {
        provideValNew () {
            return this.provideVal()
        }
    }
}
</script>

Copy the code

inject

Value has two attributes when inject is an object

  • The from injection dependency searches for the source key
  • Default Default value after the degradation

Methods five,$children/$parent

$parent/$children accesses instances of parent/ child components

There can be more than one child. This.$children is an array type

The grandchild component can trigger methods passed from parent to child via this.$parent.$emit(‘my-event’)

Provide/Inject is recommended for deeper component layers

Parent component parent. vue <template><div class="parent">
        <Child @my-event="myEventHandle"></Child>
    </div>
</template>
<script>
import Child from "./Child.vue"
export default {
    data () {
        return {
            val: "I am the parent component data!"
        }
    },
    mounted () {
        console.log(this.$children[0].val)
        console.log(this.$children[0].$children[0].val)
    },
    methods: {
        myEventHandle () {
            console.log("myEventHandle")}},components: {
        Child
    }
}
</script>

Copy the code
Child component child.vue <template><div class="child">
        <Grandson />
    </div>
</template>
<script>
import Grandson from "./Grandson.vue"
export default {
    data () {
        return {
            val: "I am child component data"
        }
    },
    mounted () {
        console.log(this.$parent.val)
    },
    components: {
        Grandson
    }
}
</script>

Copy the code
Grandson module Grandson <template><div class="grandson">
        <button @click="$parent.$emit('my-event')">click me</button>
    </div>
</template>
<script>
export default {
    data () {
        return {
            val: "I am sun Tzu component data"}}}</script>

Copy the code

$dispatch

Implements a method that notifies a child component to trigger its parent

Vue.prototype.$dispatch = function (eventName, componentName, ... args) {
    let parent = this.$parent
    while (parent) {
        // Events are triggered only by specific components. It doesn't go all the way up, all the way up
        const isSpecialComponent = parent.$options.name === componentName
        if (isSpecialComponent) {
            // If triggered, the loop is terminatedparent.$emit(eventName, ... args)return
        }
        parent = parent.$parent
    }
}
Copy the code

$broadcast

Notifies a child of the method that triggers its parent

Vue.prototype.$broadcast = function (eventName, componentName, ... args) {
    // Children are the children of all components
    const children = this.$children
    broadcast(children)
    // Note here that the extraction of the new method is recursive, not recursive $broadcast
    function broadcast (children) {
        for (let i = 0; i < children.length; i++) {
            const child = children[i]
            const isSpecialComponent = child.$options.name === componentName
            if (isSpecialComponent) {
                // If triggered, the loop is terminatedchild.$emit(eventName, ... args)return
            }
            // If not, see if there are any child components, then recursechild.$children.length && child.$broadcast(eventName, componentName, ... args) } } }Copy the code

Source: Yan Jiang

Method 6: Ref

If used on a normal DOM element, the reference refers to the DOM element. If used on a child component, the reference refers to the component instance.

The parent triggers the child’s input box focus via ref:

Parent component parentrefdemo. vue <template><div>
        <ChildRefDemo ref="childRefs" />
    </div>
</template>
<script>
import ChildRefDemo from "./ChildRefDemo.vue"
export default {
    mounted () {
        // this.$refs.childRefs gets the child component instance
        this.$refs.childRefs.focusHandle()
    },
    components: {
        ChildRefDemo
    }
}
</script>

Copy the code
Child component ChildrefDemo. vue <template><div>
        <input ref="inputRefs" />
    </div>
</template>
<script>
export default {
    methods: {
        focusHandle () {
            this.$refs.inputRefs.focus()
        }
    }
}
</script>

Copy the code

$refs only takes effect after the component has rendered, and it is not reactive and should be avoided in templates and computed properties

Methods seven,$attrs/$listeners

$attrs

Attribute bindings (except class and style) that are not recognized (and retrieved) as prop in the parent scope are bound by default to the root element of the child component. How do you bind to a child component that is not a root element?

InheritAttrs: False prevents default behavior, but does not affect class and style bindings; V-bind =”$attrs” is also required to pass in the internal component

The parent component < template ><div>
        <Child type="checkbox" />
    </div>
</template>
<script>
import Child from "./Child.vue"
export default {
    components: {
        Child
    }
}
</script>
Copy the code
Subcomponents < template ><div>
        <input v-bind="$attrs" />
    </div>
</template>
<script>
export default {
    inheritAttrs: false
}
</script>
Copy the code

$listeners

A native event is listened on the root element of the component. You can use the v-on modifier. Native, where the root element of the component should be the input, and if the root element changes, the parent. Native listener will silently fail. So how do you bind native events to child elements?

Contains v-ON event listeners in the parent scope (without the.native modifier). It can be passed into internal components via V-on =”$Listeners”

The parent component < template ><div class="about">
        <VmodelEvent @focus="myFocus"></VmodelEvent>
    </div>
</template>
<script>
import VmodelEvent from "./VmodelEvent.vue"
export default {
    methods: {
        myFocus () {
            console.log("focus")}},components: {
        VmodelEvent
    }
}
</script>

Copy the code
Subcomponents < template ><div>
        <input v-on="$listeners" />
        <Grandson v-on="$listeners" />
    </div>
</template>
<script>
import Grandson from "./Grandson.vue"
export default {
    components: {
        Grandson
    }
}
</script>
Copy the code

Useful for creating higher-level components, $attrs/$Listeners layer by layer

Vue. Observable (Object)

Internally, Vue processes data within data by making Object responsive.

The returned object can be used directly in rendering functions and computed properties, and will trigger an update when changes occur. It can also serve as a minimal cross-component state store for simple scenarios.

Calculate attribute

Reactive communication using computed attributes

<template>
    <div>
        <div>{{msg}}</div>
        <button @click="change">change msg</button>
    </div>
</template>
<script>
import Vue from 'vue'
const state = Vue.observable({ msg: "Hello Observable" })
export default {
    computed: {
        msg () {
            return state.msg
        }
    },
    methods: {
        change () {
            state.msg = "change msg"}}}</script>
Copy the code

Rendering function

Reactive communication using rendering functions

<script>
import Vue from 'vue'
const state = Vue.observable({ msg: "Hello Observable" })
export default {
    render (h) {
        return h('button', {
            on: { click: () = > { state.msg = 'change msg'}}},`count is: ${state.msg}`)
    }
}
</script>
Copy the code

Methods nine,$root

All child components can access the root instance’s data, calculated properties, and methods through this.$root, and can also change the root instance’s data. For demo or small applications with a small number of components, it is recommended to use Vuex to manage application state for medium to large projects. This instance can be accessed or used as a global store.

new Vue({
    data () {
        return {
            rootVal: $root gets the value, calculated properties, and methods of the root instance}},computed: {},
    methods: {},
    render: h= > h(App)
}).$mount('#app')
Copy the code

Method 10. Other ways

Slot value transmission, route parameter transmission, local storage