Vue3 communication uses writing method
1. props
Method 1: mixed writing
// Parent.vue transfer <child :msg1="msg1" :msg2="msg2"></child> <script> import child from "./child.vue" import { ref, reactive } from "vue" export default { data(){ return { msg1:"This is the message 1 of the pass level subassembly" } }, setup(){ // Create a responsive data // The writing method 1 is applicable to the basic type ref and has other uses, which are described in the following chapters const msg2 = ref("This is the message 2 of the pass level subassembly") // Writing method 2 is applicable to complex types, such as arrays and objects const msg2 = reactive(["This is the message 2 of the pass level subassembly"]) return { msg2 } } } </script> // Child.vue receive <script> export default { props: ["msg1", "msg2"],// If this line is not written, it will not be received below setup(props) { console.log(props) // {msg1: "this is the information 1 passed to the sub component", msg2: "this is the information 2 passed to the sub component"} }, } </script>
Method 2: pure Vue3 writing
// Parent.vue transfer <child :msg2="msg2"></child> <script setup> import child from "./child.vue" import { ref, reactive } from "vue" const msg2 = ref("This is the message passed to the subcomponent 2") // Or complex type const msg2 = reactive(["This is the message 2 of the pass level subassembly"]) </script> // Child.vue receive <script setup> // Direct use without introduction // import { defineProps } from "vue" const props = defineProps({ // Writing method I msg2: String // Writing method 2 msg2:{ type:String, default:"" } }) console.log(props) // {msg2: "this is the information 2 of the pass level sub component"} </script>
2. $emit
// Distributed by Child.vue <template> // Writing method I <button @click="emit('myClick')">Button</buttom> // Writing method 2 <button @click="handleClick">Button</buttom> </template> <script setup> // Method 1 is applicable to Vue3.2 and does not need to be introduced // import { defineEmits } from "vue" // Corresponding writing method I const emit = defineEmits(["myClick","myClick2"]) // Correspondence 2 const handleClick = ()=>{ emit("myClick", "This is the information sent to the parent component") } // Method 2 is not applicable to Vue3.2, which is obsolete import { useContext } from "vue" const { emit } = useContext() const handleClick = ()=>{ emit("myClick", "This is the information sent to the parent component") } </script> // Parent.vue response <template> <child @myClick="onMyClick"></child> </template> <script setup> import child from "./child.vue" const onMyClick = (msg) => { console.log(msg) // This is the message received by the parent component } </script>
3. expose / ref
The parent component obtains the properties of the child component or calls the child component method
// Child.vue <script setup> // Method 1 is not applicable to Vue3.2, which is obsolete import { useContext } from "vue" const ctx = useContext() // External exposure properties and methods are OK ctx.expose({ childName: "This is the property of the subcomponent", someMethod(){ console.log("This is the sub component method") } }) // Method 2 is applicable to Vue3.2 and does not need to be introduced // import { defineExpose } from "vue" defineExpose({ childName: "This is the property of the subcomponent", someMethod(){ console.log("This is the sub component method") } }) </script> // Parent.vue note ref="comp" <template> <child ref="comp"></child> <button @click="handlerClick">Button</button> </template> <script setup> import child from "./child.vue" import { ref } from "vue" const comp = ref(null) const handlerClick = () => { console.log(comp.value.childName) // Get the exposed properties of the subcomponent comp.value.someMethod() // Call the exposed method of the sub component } </script>
4. attrs
attrs: contains a collection of non props attributes in the parent scope except class and style
// Parent.vue transfer <child :msg1="msg1" :msg2="msg2" title="3333"></child> <script setup> import child from "./child.vue" import { ref, reactive } from "vue" const msg1 = ref("1111") const msg2 = ref("2222") </script> // Child.vue receive <script setup> import { defineProps, useContext, useAttrs } from "vue" // In version 3.2, defineProps does not need to be introduced and can be used directly const props = defineProps({ msg1: String }) // Method 1 is not applicable to Vue3.2, which is obsolete const ctx = useContext() // If you do not receive msg1 with props, it is {msg1: "1111", msg2:"2222", title: "3333"} console.log(ctx.attrs) // { msg2:"2222", title: "3333" } // Method 2 is applicable to Vue3.2 const attrs = useAttrs() console.log(attrs) // { msg2:"2222", title: "3333" } </script>
5. v-model
It can support multiple bidirectional data binding
// Parent.vue <child v-model:key="key" v-model:value="value"></child> <script setup> import child from "./child.vue" import { ref, reactive } from "vue" const key = ref("1111") const value = ref("2222") </script> // Child.vue <template> <button @click="handlerClick">Button</button> </template> <script setup> // Method 1 is not applicable to Vue3.2, which is obsolete import { useContext } from "vue" const { emit } = useContext() // Method 2 is applicable to Vue3.2 and does not need to be introduced // import { defineEmits } from "vue" const emit = defineEmits(["key","value"]) // usage const handlerClick = () => { emit("update:key", "new key") emit("update:value", "new value") } </script>
6. provide / inject
provide / inject is dependency injection
Provide: allows us to specify the data or data that we want to provide to future generations of components
inject: receive the data you want to add to any descendant component. No matter how deep the component is nested, it can be used directly
// Parent.vue <script setup> import { provide } from "vue" provide("name", "Mu Hua") </script> // Child.vue <script setup> import { inject } from "vue" const name = inject("name") console.log(name) // Mu Hua </script>
7. Vuex
// store/index.js import { createStore } from "vuex" export default createStore({ state:{ count: 1 }, getters:{ getCount: state => state.count }, mutations:{ add(state){ state.count++ } } }) // main.js import { createApp } from "vue" import App from "./App.vue" import store from "./store" createApp(App).use(store).mount("#app") // Page.vue // Method 1: direct use <template> <div>{{ $store.state.count }}</div> <button @click="$store.commit('add')">Button</button> </template> // Method 2 acquisition <script setup> import { useStore, computed } from "vuex" const store = useStore() console.log(store.state.count) // 1 const count = computed(()=>store.state.count) // Responsive, which changes as vuex data changes console.log(count) // 1 </script>
8. mitt
There is no cross component communication of EventBus in Vue3, but now there is an alternative scheme mit.js, and the principle is EventBus
Install NPM I MIT - s first
Then package the bus as before
mitt.js import mitt from 'mitt' const mitt = mitt() export default mitt
Then the use of communication between the two components
// Component A <script setup> import mitt from './mitt' const handleClick = () => { mitt.emit('handleChange') } </script> // Component B <script setup> import mitt from './mitt' import { onUnmounted } from 'vue' const someMethed = () => { ... } mitt.on('handleChange',someMethed) onUnmounted(()=>{ mitt.off('handleChange',someMethed) }) </script>
Vue2.x component communication mode
There are 12 kinds of Vue2.x component communication | Parent child component communication | Sibling component communication | Cross level component communication |
---|---|---|---|
props | props | EventBus | EventBus |
$emit / v-on | $emit / v-on | Vuex | provide/inject |
.sync | attrs/listeners | $parent | Vuex |
v-model | ref | attrs/listeners | |
ref | .sync | $root | |
children/parent | v-model | ||
attrs/listeners | children/parent | ||
provide / inject | |||
EventBus | |||
Vuex | |||
$root | |||
slot |
Vue2.x communication usage
1. props
The parent component transmits data to the child component, which should be the most common way
After the child component receives the data, it cannot directly modify the data of the parent component. An error will be reported, so when the parent component re renders, the data will be overwritten. If you want to modify in a sub component, it is recommended to use computed
// Parent.vue transfer <template> <child :msg="msg"></child> </template> // Child.vue receive export default { // Write a receive with array props:['msg'], // The second writing method uses object reception, which can limit the received data type, set the default value, verify, etc props:{ msg:{ type:String, default:'This is the default data' } }, mounted(){ console.log(this.msg) }, }
2. .sync
It can help us realize the two-way binding of the data transmitted from the parent component to the child component, so the child component can modify the data directly after receiving the data, and will modify the data of the parent component at the same time
// Parent.vue <template> <child :page.sync="page"></child> </template> <script> export default { data(){ return { page:1 } } } // Child.vue export default { props:["page"], computed(){ // When we modify the currentPage in the child component, the page of the parent component will also change currentPage { get(){ return this.page }, set(newVal){ this.$emit("update:page", newVal) } } } } </script>
3. v-model
Similar to. sync, the data passed from the parent component to the child component can be bidirectional bound, and the child component can modify the data of the parent component through $emit
// Parent.vue <template> <child v-model="value"></child> </template> <script> export default { data(){ return { value:1 } } } // Child.vue <template> <input :value="value" @input="handlerChange"> </template> export default { props:["value"], // You can modify the event name, which defaults to input model:{ event:"updateValue" }, methods:{ handlerChange(e){ this.$emit("input", e.target.value) // If there is a rename above, that's it this.$emit("updateValue", e.target.value) } } } </script>
4. ref
ref if it is on an ordinary DOM element, the reference refers to the DOM element;
If on a child component, the reference points to the child component instance, then the parent component can actively obtain the properties of the child component or call the methods of the child component through ref
// Child.vue export default { data(){ return { name:"Mu Hua" } }, methods:{ someMethod(msg){ console.log(msg) } } } // Parent.vue <template> <child ref="child"></child> </template> <script> export default { mounted(){ const child = this.$refs.child console.log(child.name) // Mu Hua child.someMethod("The method of the subcomponent was called") } } </script>
5. $emit / v-on
The child component sends data to the parent component by sending events, or triggers operations such as parent component update
// Distributed by Child.vue export default { data(){ return { msg: "This is the message sent to the parent component" } }, methods: { handleClick(){ this.$emit("sendMsg",this.msg) } }, } // Parent.vue response <template> <child v-on:sendMsg="getChildMsg"></child> // Or abbreviation <child @sendMsg="getChildMsg"></child> </template> export default { methods:{ getChildMsg(msg){ console.log(msg) // This is the message received by the parent component } } }
6.attrs/listeners
When multi-layer nested components transfer data, this can be used if they only transfer data without intermediate processing. For example, when a parent component transfers data to a child component
$attrs: contains a collection of non props attributes in the parent scope except class and style. Get all the qualified attribute sets in the parent scope through this.attrs, and then continue to pass them to other components within the child component. You can use v-bind="attrs"
$listeners: contains a collection of listening events except. native in the parent scope. If you want to continue to pass it to other components inside the sub component, you can use v-on = "$linkers"
Use the same way
// Parent.vue <template> <child :name="name" title="1111" ></child> </template export default{ data(){ return { name:"Mu Hua" } } } // Child.vue <template> // Continue to pass to grandchildren <sun-child v-bind="$attrs"></sun-child> </template> export default{ props:["name"], // You can receive or not receive here mounted(){ // If props receives name, it is {title:1111}, otherwise it is {Name: "Muhua", title:1111} console.log(this.$attrs) } }
7.children/parent
$children: get an array of VueComponent objects containing all sub components (excluding grandchildren), and you can directly get all data and methods in the sub components
$parent: get the VueComponent object of a parent node, which also contains all data and methods in the parent node
// Parent.vue export default{ mounted(){ this.$children[0].someMethod() // Call the method of the first subcomponent this.$children[0].name // Gets the property in the first subcomponent } } // Child.vue export default{ mounted(){ this.$parent.someMethod() // Call the method of the parent component this.$parent.name // Get properties in parent component } }
8. provide / inject
provide / inject is dependency injection, which is not recommended to be directly used in application code, but it is commonly used in some plug-ins or component libraries, so I think it's OK to use it, and it's very useful
Provide: allows us to specify the data or methods we want to provide to future generations of components
inject: receive data or methods that you want to add to any descendant component. No matter how deep the component is nested, it can be used directly
It should be noted that the data passed by provide and inject are not responsive, that is, after receiving the data with inject, the data in provide changes, and the data in descendant components will not change, unless the incoming object is a listening object
Therefore, it is recommended to pass some constants or methods
// Parent component export default{ // Method 1 cannot get the method in methods provide:{ name:"Mu Hua", age: this.data Properties in }, // Method 2 cannot get the attribute in data provide(){ return { name:"Mu Hua", someMethod:this.someMethod // Methods in methods } }, methods:{ someMethod(){ console.log("This is the injection method") } } } // Descendant component export default{ inject:["name","someMethod"], mounted(){ console.log(this.name) this.someMethod() } }
9. EventBus
EventBus is a central event bus, which can be used to complete communication operations for parent-child components, brother components, cross level components, etc
There are three ways to define
// Method 1 // Extract it into a separate JS file Bus.js, and then introduce it where necessary // Bus.js import Vue from "vue" export default new Vue() // Method 2 mount directly to the global // main.js import Vue from "vue" Vue.prototype.$bus = new Vue() // Method 3 is injected into the Vue root object // main.js import Vue from "vue" new Vue({ el:"#app", data:{ Bus: new Vue() } })
Use the following to take the on-demand introduction of method 1 as an example
// Within a component that needs to send custom events to the outside <template> <button @click="handlerClick">Button</button> </template> import Bus from "./Bus.js" export default{ methods:{ handlerClick(){ // Custom event name sendMsg Bus.$emit("sendMsg", "This is the data to be sent externally") } } } // Within a component that needs to receive external events import Bus from "./Bus.js" export default{ mounted(){ // Trigger of listening event Bus.$on("sendMsg", data => { console.log("This is the data received:", data) }) }, beforeDestroy(){ // Cancel listening Bus.$off("sendMsg") } }
10. Vuex
Vuex is a state manager that centrally stores and manages the state of all components. This piece of content is too long. If you are not familiar with the basics, you can look at this vuex, and the general usage is as follows
For example, create such a file structure
The contents in index.js are as follows
import Vue from 'vue' import Vuex from 'vuex' import getters from './getters' import actions from './actions' import mutations from './mutations' import state from './state' import user from './modules/user' Vue.use(Vuex) const store = new Vuex.Store({ modules: { user }, getters, actions, mutations, state }) export default store
Then, it is introduced in main.js
import Vue from "vue" import store from "./store" new Vue({ el:"#app", store, render: h => h(App) })
Then in the required components
import { mapGetters, mapMutations } from "vuex" export default{ computed:{ // Method 1, and then you can use it through the name of this. Attribute ...mapGetters(["introduce getters.js Inside attribute 1","Attribute 2"]) // Mode II ...mapGetters("user", ["user Attribute 1 in module","Attribute 2"]) }, methods:{ // Method 1, and then you can use it through the name of this. Attribute ...mapMutations(["introduce mutations.js Method 1 in","Method 2"]) // Mode II ...mapMutations("user",["introduce user Method 1 in module","Method 2"]) } } // Or you can get it this way this.$store.state.xxx this.$store.state.user.xxx
11. $root
$root can get the data and methods in App.vue
12. slot
It is to pass the data of the child component to the parent component through the slot, and then plug it back
// Child.vue <template> <div> <slot :user="user"></slot> </div> </template> export default{ data(){ return { user:{ name:"Mu Hua" } } } } // Parent.vue <template> <div> <child v-slot="slotProps"> {{ slotProps.user.name }} </child> </div> </template>