Several methods of Vue component value transfer

01 father to son

Props: props can be an array or an object that receives data passed from the parent component through v-bind. When props is an array, it directly receives the attributes passed by the parent component; When   props   When an object is, you can set the type, default value, whether to pass and verification rules of the attribute through configuration such as type, default, required and validator.

app.vue

<template>
    <div id="app">
        Hello
        <!-- If you want to change the data passed in the past, you can modify it directly in your own component -->
        <button @click="msg = 'xxx'">modify</button>
        <hr />
        <child :msg="msg" />
    </div>
</template>

<script>
import Child from '@/Child'
export default {
    name: 'App',
    data() {
        return {
            msg: 'Hello World',
        }
    },
    components: {
        Child,
    },
}
</script>

Child.vue  

<template>
    <div>Child: {{ msg }}</div>
</template>

<script>
export default {
    name: 'Child',
    props: {
        msg: {
            type: String,
        },
    },
}
</script>

02 son to father  

$emit: during communication between parent and child components, $emit is used to trigger the parent component v-on to bind the listening of corresponding events on the child component.

App.vue

<template>
    <div id="app">
        {{ msg }}
        <hr />
        <child @changeMsg="changeMsg" />
    </div>
</template>

<script>
import Child from '@/components/Child'
export default {
    name: 'App',
    data() {
        return {
            msg: 'Fatherly Hello World',
        }
    },
    components: {
        Child,
    },
    methods: {
        changeMsg(childData) {
            this.msg = childData
        },
    },
}
</script>

Child.vue  

<template>
    <div>
        Child
        <button @click="handleChangeMsg">Modify father's data</button>
    </div>
</template>

<script>
export default {
    name: 'Child',
    methods: {
        handleChangeMsg() {
            this.$emit('changeMsg', '~~~~~~')
        },
    },
}
</script>

03 brother value transfer (status promotion)

The so-called state promotion is to put the data to be operated into a unified parent. A child component modifies the data of the parent component, and the data of the parent component is passed to another child component

Requirement: modify the data in Child2.vue in Child1.vue

App.vue

<template>
    <div id="app">
        App
        <hr />
        <child1 @changeData="changeData" />
        <child2 :msg="msg" />
    </div>
</template>

<script>
import Child1 from '@/components/Child1'
import Child2 from '@/components/Child2'
export default {
    name: 'App',
    data() {
        return {
            msg: 'Hello World',
        }
    },
    components: {
        Child1,
        Child2,
    },
    methods: {
        changeData(childData) {
            // If you modify your own data directly, the data in the other son will naturally change
            this.msg = childData
        },
    },
}
</script>

Child1.vue

<template>
    <div>
        Child1
        <button @click="handleClick">modify Child2 Data</button>
    </div>
</template>

<script>
// Want to modify the data in Child2 in Child1
export default {
    name: 'Child1',
    methods: {
        handleClick() {
            this.$emit('changeData', '~~~~')
        },
    },
}
</script>

Child2.vue  

<template>
    <div>Child2: {{ msg }}</div>
</template>

<script>
export default {
    name: 'Child2',
    props: ['msg'],
    data() {
        return {}
    },
    methods: {},
}
</script>

04   Brother communication (EventBus)

eventBus, also known as event bus, registers a new Vue instance, listens to and triggers the events of this instance by calling $emit and $on of this instance, and realizes the global communication of components by passing in parameters.

main.js

import Vue from 'vue'
import App from './App.vue'

// # 1 event bus
Vue.prototype.$hub = new Vue()

Vue.config.productionTip = false

new Vue({
    render: (h) => h(App),
}).$mount('#app')

App.vue

<template>
    <div id="app">
        App
        <hr />
        <child1 />
        <child2 />
    </div>
</template>

<script>
import Child1 from '@/components/Child1'
import Child2 from '@/components/Child2'

export default {
    name: 'App',
    components: {
        Child1,
        Child2,
    },
}
</script>

Child1.vue  

<template>
    <div>
        Child1
        <button @click="handleClick">change Child2 Data in</button>
    </div>
</template>

<script>
export default {
    name: 'Child1',
    methods: {
        handleClick() {
            // !#2
            this.$hub.$emit('changeData', '~~~~')
        },
    },
}
</script>

Child2.vue  

<template>
    <div>Child2: {{ msg }}</div>
</template>

<script>
export default {
    name: 'Child2',
    data() {
        return {
            msg: 'Hello World',
        }
    },
    mounted() {
        // # 3 prepare an event monitor
        this.$hub.$on('changeData', (child1Data) => {
            this.msg = child1Data
        })
    },
}
</script>

  Note: This is abandoned in Vue3

05 Vuex

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        username: 'Tom',
    },
    mutations: {
        changeUserName(state, uname) {
            state.username = uname
        },
    },
})

Child1.vue  

<template>
    <div>
        Child1
        <button @click="handleChange">change</button>
    </div>
</template>

<script>
export default {
    name: 'Child1',
    methods: {
        handleChange() {
            this.$store.commit('changeUserName', '~~~~~')
        },
    },
}
</script>

Child2.vue  

<template>
    <div>Child2: {{ username }}</div>
</template>

<script>
import { mapState } from 'vuex'
export default {
    name: 'Child2',
    computed: {
        ...mapState(['username']),
    },
}
</script>

06 Refs

$refs: in implementing component communication, you can  $ refs   Bind to the sub component to get the sub component instance.

App.vue

<template>
    <div id="app">
        App
        <button @click="handleClick">change</button>
        <hr />
        <child ref="c" />
    </div>
</template>

<script>
// Requirement: data from parent to child
import Child from './components/Child.vue'

export default {
    name: 'App',
    components: {
        Child,
    },
    methods: {
        handleClick() {
            // Operation data
            // this.$refs.c.msg = '~~~~~~';
            this.$refs.c.changeData()
        },
    },
}
</script>

 Child.vue

<template>
    <div>Child: {{ msg }}</div>
</template>

<script>
export default {
    name: 'Child',

    data() {
        return {
            msg: 'Hello World',
        }
    },

    methods: {
        changeData() {
            this.msg = '~~~~~'
        },
    },
}
</script>

07 $parent / $children (parent to child, child to parent)

$parent: you can   Vue   Get the parent component instance (if any) of the current component directly through this.$parent.

$children: you can also   Vue   Get the array of sub component instances of the current component directly through this.$children. However, it should be noted that the element subscripts in this.$children array do not necessarily affect the order of child components referenced by parent components. For example, child components loaded asynchronously may affect their   children   The order in the array. Therefore, you need to find the corresponding sub component according to certain conditions, such as the name of the sub component.

App.vue

<template>
    <div id="app">
        {{ msg }}
        <button @click="handleClick">change</button>
        <hr />
        <child ref="c" />
    </div>
</template>

<script>
// Requirement: data from parent to child
import Child from './components/Child.vue'

export default {
    name: 'App',
    components: {
        Child,
    },
    data() {
        return {
            msg: 'H',
        }
    },
    methods: {
        handleClick() {
            // Operation data
            // this.$refs.c.msg = '~~~~~~';
            // this.$refs.c.changeData();
            // console.log(this.$children[0] === this.$refs.c); // true
            this.$children[0].changeData()
        },
    },
}
</script>

Child.vue  

<template>
    <div>
        Child: {{ msg }}
        <button @click="handleClick">Son to father</button>
    </div>
</template>

<script>
export default {
    name: 'Child',

    data() {
        return {
            msg: 'Hello World',
        }
    },

    methods: {
        changeData() {
            this.msg = '~~~~~'
        },
        handleClick() {
            // If you can get your father's data, you can get your father's method. I won't demonstrate it any more
            this.$parent.msg = '~~~~~~~~~~~~'
        },
    },
}
</script>

08 provide / inject

provide: is an object or a function that returns an object. The object contains information that can be injected into its descendants   property  , That is, the attributes and attribute values to be passed to descendants.

injcet: an array of strings, or an object. When it is a string array, the usage is very similar to props, except that the received attribute changes from data to the attribute in provide. When it is an object, it is also similar to props. You can set the default value by configuring attributes such as default and from, and use new named attributes in sub components.

App.vue

<template>
    <div id="app">
        App
        <button @click="handleClick">Change data</button>
        <hr />
        <child1 />
    </div>
</template>

<script>
import Child1 from './components/Child1.vue'

export default {
    name: 'App',
    data() {
        return {
            username: 'ifer',
            info: {
                age: 18,
            },
        }
    },
    components: {
        Child1,
    },
    // Cannot access data in data
    /* provide: {
        username: 'ifer',
    } */
    // Not responsive
    /* provide() {
        return {
            username: this.username,
        }
    } */
    // The incoming object is responsive
    provide() {
        return {
            info: this.info,
        }
    },
    methods: {
        handleClick() {
            this.info.age = '~~~~~~'
        },
    },
}
</script>

Child3.vue  

<template>
    <div>
        <p>Child3: {{ info.age }}</p>
    </div>
</template>

<script>
export default {
    name: 'Child3',
    inject: ['info'],
}
</script>

09 $attrs

$attrs: used to receive the information that is not in the parent scope   prop   Identified   attribute   Attributes, and you can pass in internal components through v-bind="$attrs" -- very useful when creating high-level components.

App.vue

<template>
    <div id="app">
        App
        <button @click="changeData">Change data</button>
        <hr />
        <child1 class="box" :username="username" :age="age" />
    </div>
</template>

<script>
import Child1 from './components/Child1.vue'

export default {
    name: 'App',
    data() {
        return {
            username: 'ifer',
            age: 18,
        }
    },
    components: {
        Child1,
    },
    methods: {
        changeData() {
            this.username = '~~~~~~~~'
            this.age = '188888888'
        },
    },
}
</script>

Child1.vue  

<template>
    <div class="child1">
        Child1{{ $attrs }}
        <hr />
        <child2 v-bind="$attrs" />
    </div>
</template>

<script>
import Child2 from './Child2'
export default {
    name: 'Child1',
    components: {
        Child2,
    },
    props: ['username'],
    // ! The non Props attribute will act on the root node of the component by default, except class and style
    inheritAttrs: false,
}
</script>

Child2.vue  

<template>
    <div class="child2">Child2: {{ $attrs }}</div>
</template>

<script>
export default {
    name: 'Child2',
}
</script>

 10  $listeners

$listeners: contains the in the parent scope   v-on   Event listener. It can pass   v-on="$listeners"   Incoming internal components

App.vue

<template>
    <div id="app">
        {{ msg }}
        <hr />
        <child1 @test1="test1" @test2="test2" />
    </div>
</template>

<script>
import Child1 from './components/Child1.vue'

export default {
    name: 'App',
    data() {
        return {
            msg: 'H',
        }
    },
    components: {
        Child1,
    },
    methods: {
        test1(msg) {
            this.msg = msg
        },
        test2() {
            console.log('test2')
        },
    },
}
</script>

Child1.vue  

<template>
    <div>
        Child1
        <hr />
        <child2 v-on="$listeners" />
    </div>
</template>

<script>
import Child2 from './Child2'
export default {
    name: 'Child1',
    components: {
        Child2,
    },
}
</script>

Child2.vue

<template>
    <div>
        Child2
        <button @click="handleClick">Change grandpa's data</button>
    </div>
</template>

<script>
export default {
    name: 'Child2',
    methods: {
        handleClick() {
            // The first way to trigger
            // this.$listeners.test1('~~~~~~~~')
            // The second way to trigger
            this.$emit('test1', '~~~~~~~~')
        },
    },
}
</script>

Tags: Javascript Front-end Vue.js

Posted on Tue, 26 Oct 2021 09:44:01 -0400 by shage