Home > Web Front-end > Vue.js > How to communicate between components? Inventory of Vue component communication methods (worth collecting)

How to communicate between components? Inventory of Vue component communication methods (worth collecting)

青灯夜游
Release: 2022-08-19 20:04:02
forward
1448 people have browsed it

VueHow to communicate between components? This article takes stock of the 10 component communication methods of Vue2 and Vue3. I hope it will be helpful to everyone!

How to communicate between components? Inventory of Vue component communication methods (worth collecting)

There are many ways to communicate components in Vue, and there will be many differences in the implementation of Vue2 and Vue3; this article will use Optional API The three different implementation methods of combined API and setup comprehensively introduce the component communication methods of Vue2 and Vue3. The communication methods to be implemented are shown in the table below. (Learning video sharing: vue video tutorial)

method Vue2 Vue3
Pass from father to son props props
Pass from son to father $emit emits
From father to son $attrs attrs
son to father $listeners None (merged into attrs mode)
father to son provide provide
Child to parent inject inject
Child component accesses parent Component $parent None
Parent component accesses child component $children None
Parent component accesses child component $ref expose&ref
Brother passing value EventBus mitt

props

Props are one of the most commonly used communication methods in component communication. The parent component is passed in through v-bind, and the child component is received through props. The following are its three implementation methods

  • Optional API
//父组件

<template>
  <div>
    <Child :msg="parentMsg" />
  </div>
</template>
<script>
import Child from './Child'
export default {
  components:{
    Child
  },
  data() {
    return {
      parentMsg: '父组件信息'
    }
  }
}
</script>


//子组件

<template>
  <div>
    {{msg}}
  </div>
</template>
<script>
export default {
  props:['msg']
}
</script>
Copy after login
  • Combined Api
//父组件

<template>
  <div>
    <Child :msg="parentMsg" />
  </div>
</template>
<script>
import { ref,defineComponent } from 'vue'
import Child from './Child.vue'
export default defineComponent({
  components:{
    Child
  },
  setup() {
    const parentMsg = ref('父组件信息')
    return {
      parentMsg
    };
  },
});
</script>

//子组件

<template>
    <div>
        {{ parentMsg }}
    </div>
</template>
<script>
import { defineComponent,toRef } from "vue";
export default defineComponent({
    props: ["msg"],// 如果这行不写,下面就接收不到
    setup(props) {
        console.log(props.msg) //父组件信息
        let parentMsg = toRef(props, 'msg')
        return {
            parentMsg
        };
    },
});
</script>
Copy after login
  • setup syntax sugar
//父组件

<template>
  <div>
    <Child :msg="parentMsg" />
  </div>
</template>
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'
const parentMsg = ref('父组件信息')
</script>

//子组件

<template>
    <div>
        {{ parentMsg }}
    </div>
</template>
<script setup>
import { toRef, defineProps } from "vue";
const props = defineProps(["msg"]);
console.log(props.msg) //父组件信息
let parentMsg = toRef(props, 'msg')
</script>
Copy after login

Note

The data flow in props is single item, that is, sub- Components cannot change the value passed by the parent component

In the combined API, if you want to use other variables to receive the value of props in the child component, you need to use toRef to convert the properties in the props to responsive.

emit

The child component can publish an event through emit and pass some parameters, and the parent component monitors this event through v-on

  • Option API
//父组件

<template>
  <div>
    <Child @sendMsg="getFromChild" />
  </div>
</template>
<script>
import Child from './Child'
export default {
  components:{
    Child
  },
  methods: {
    getFromChild(val) {
      console.log(val) //我是子组件数据
    }
  }
}
</script>

// 子组件

<template>
  <div>
    <button @click="sendFun">send</button>
  </div>
</template>
<script>
export default {
  methods:{
    sendFun(){
      this.$emit('sendMsg','我是子组件数据')
    }
  }
}
</script>
Copy after login
  • Combined API
//父组件

<template>
  <div>
    <Child @sendMsg="getFromChild" />
  </div>
</template>
<script>
import Child from './Child'
import { defineComponent } from "vue";
export default defineComponent({
  components: {
    Child
  },
  setup() {
    const getFromChild = (val) => {
      console.log(val) //我是子组件数据
    }
    return {
      getFromChild
    };
  },
});
</script>

//子组件

<template>
    <div>
        <button @click="sendFun">send</button>
    </div>
</template>

<script>
import { defineComponent } from "vue";
export default defineComponent({
    emits: ['sendMsg'],
    setup(props, ctx) {
        const sendFun = () => {
            ctx.emit('sendMsg', '我是子组件数据')
        }
        return {
            sendFun
        };
    },
});
</script>
Copy after login
  • setup syntax sugar
//父组件

<template>
  <div>
    <Child @sendMsg="getFromChild" />
  </div>
</template>
<script setup>
import Child from './Child'
const getFromChild = (val) => {
      console.log(val) //我是子组件数据
    }
</script>

//子组件

<template>
    <div>
        <button @click="sendFun">send</button>
    </div>
</template>
<script setup>
import { defineEmits } from "vue";
const emits = defineEmits(['sendMsg'])
const sendFun = () => {
    emits('sendMsg', '我是子组件数据')
}
</script>
Copy after login

attrs and listeners

The child component uses $attrs to obtain all attributes of the parent component except the attributes passed by props and the attribute binding attributes (class and style).

The sub-component uses $listeners to obtain all v-on event listeners of the parent component (excluding .native modifiers), which are no longer used in Vue3; but the attrs in Vue3 can not only obtain the parent component The passed properties can also be obtained from the parent component v-on event listener

  • Optional API
//父组件

<template>
  <div>
    <Child @parentFun="parentFun" :msg1="msg1" :msg2="msg2"  />
  </div>
</template>
<script>
import Child from './Child'
export default {
  components:{
    Child
  },
  data(){
    return {
      msg1:'子组件msg1',
      msg2:'子组件msg2'
    }
  },
  methods: {
    parentFun(val) {
      console.log(`父组件方法被调用,获得子组件传值:${val}`)
    }
  }
}
</script>

//子组件

<template>
  <div>
    <button @click="getParentFun">调用父组件方法</button>
  </div>
</template>
<script>
export default {
  methods:{
    getParentFun(){
      this.$listeners.parentFun('我是子组件数据')
    }
  },
  created(){
    //获取父组件中所有绑定属性
    console.log(this.$attrs)  //{"msg1": "子组件msg1","msg2": "子组件msg2"}
    //获取父组件中所有绑定方法    
    console.log(this.$listeners) //{parentFun:f}
  }
}
</script>
Copy after login
  • Combined API
//父组件

<template>
  <div>
    <Child @parentFun="parentFun" :msg1="msg1" :msg2="msg2" />
  </div>
</template>
<script>
import Child from './Child'
import { defineComponent,ref } from "vue";
export default defineComponent({
  components: {
    Child
  },
  setup() {
    const msg1 = ref('子组件msg1')
    const msg2 = ref('子组件msg2')
    const parentFun = (val) => {
      console.log(`父组件方法被调用,获得子组件传值:${val}`)
    }
    return {
      parentFun,
      msg1,
      msg2
    };
  },
});
</script>

//子组件

<template>
    <div>
        <button @click="getParentFun">调用父组件方法</button>
    </div>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
    emits: ['sendMsg'],
    setup(props, ctx) {
        //获取父组件方法和事件
        console.log(ctx.attrs) //Proxy {"msg1": "子组件msg1","msg2": "子组件msg2"}
        const getParentFun = () => {
            //调用父组件方法
            ctx.attrs.onParentFun('我是子组件数据')
        }
        return {
            getParentFun
        };
    },
});
</script>
Copy after login
  • setup syntax sugar
//父组件

<template>
  <div>
    <Child @parentFun="parentFun" :msg1="msg1" :msg2="msg2" />
  </div>
</template>
<script setup>
import Child from './Child'
import { ref } from "vue";
const msg1 = ref('子组件msg1')
const msg2 = ref('子组件msg2')
const parentFun = (val) => {
  console.log(`父组件方法被调用,获得子组件传值:${val}`)
}
</script>

//子组件

<template>
    <div>
        <button @click="getParentFun">调用父组件方法</button>
    </div>
</template>
<script setup>
import { useAttrs } from "vue";

const attrs = useAttrs()
//获取父组件方法和事件
console.log(attrs) //Proxy {"msg1": "子组件msg1","msg2": "子组件msg2"}
const getParentFun = () => {
    //调用父组件方法
    attrs.onParentFun('我是子组件数据')
}
</script>
Copy after login

Note

When using attrs to call the parent component method in Vue3, on needs to be added before the method; for example parentFun->onParentFun

provide/inject

provide: is an object, or a function that returns an object. It contains the attributes to be given to future generations

inject: a string array, or an object. Get the value provided by the parent component or higher-level component, which can be obtained in any descendant component through inject

  • Optional API
//父组件
<script>
import Child from './Child'
export default {
  components: {
    Child
  },
  data() {
    return {
      msg1: '子组件msg1',
      msg2: '子组件msg2'
    }
  },
  provide() {
    return {
      msg1: this.msg1,
      msg2: this.msg2
    }
  }
}
</script>

//子组件

<script>
export default {
  inject:['msg1','msg2'],
  created(){
    //获取高层级提供的属性
    console.log(this.msg1) //子组件msg1
    console.log(this.msg2) //子组件msg2
  }
}
</script>
Copy after login
  • Combined type API
//父组件

<script>
import Child from './Child'
import { ref, defineComponent,provide } from "vue";
export default defineComponent({
  components:{
    Child
  },
  setup() {
    const msg1 = ref('子组件msg1')
    const msg2 = ref('子组件msg2')
    provide("msg1", msg1)
    provide("msg2", msg2)
    return {
      
    }
  },
});
</script>

//子组件

<template>
    <div>
        <button @click="getParentFun">调用父组件方法</button>
    </div>
</template>
<script>
import { inject, defineComponent } from "vue";
export default defineComponent({
    setup() {
        console.log(inject('msg1').value) //子组件msg1
        console.log(inject('msg2').value) //子组件msg2
    },
});
</script>
Copy after login
  • setup syntax sugar
//父组件
<script setup>
import Child from './Child'
import { ref,provide } from "vue";
const msg1 = ref('子组件msg1')
const msg2 = ref('子组件msg2')
provide("msg1",msg1)
provide("msg2",msg2)
</script>

//子组件

<script setup>
import { inject } from "vue";
console.log(inject('msg1').value) //子组件msg1
console.log(inject('msg2').value) //子组件msg2
</script>
Copy after login

Description

provide/inject is generally in deep component nesting Use appropriately. Generally used in component development.

parent/children

$parent: The child component obtains the Vue instance of the parent component, and can obtain the properties and methods of the parent component, etc.

$children: Parent The component obtains the Vue instance of the sub-component, which is an array and a collection of direct children, but the order of the sub-components is not guaranteed

  • Vue2
import Child from './Child'
export default {
  components: {
    Child
  },
  created(){
    console.log(this.$children) //[Child实例]
    console.log(this.$parent)//父组件实例
  }
}
Copy after login

NoteThe $children obtained by the parent component is not responsive

expose&ref

$refs can directly obtain element attributes, and can also Directly obtain the sub-component instance

  • Optional API
//父组件

<template>
  <div>
    <Child ref="child" />
  </div>
</template>
<script>
import Child from './Child'
export default {
  components: {
    Child
  },
  mounted(){
    //获取子组件属性
    console.log(this.$refs.child.msg) //子组件元素

    //调用子组件方法
    this.$refs.child.childFun('父组件信息')
  }
}
</script>

//子组件 

<template>
  <div>
    <div></div>
  </div>
</template>
<script>
export default {
  data(){
    return {
      msg:'子组件元素'
    }
  },
  methods:{
    childFun(val){
      console.log(`子组件方法被调用,值${val}`)
    }
  }
}
</script>
Copy after login
  • Combined API
//父组件

<template>
  <div>
    <Child ref="child" />
  </div>
</template>
<script>
import Child from './Child'
import { ref, defineComponent, onMounted } from "vue";
export default defineComponent({
  components: {
    Child
  },

  setup() {
    const child = ref() //注意命名需要和template中ref对应
    onMounted(() => {
      //获取子组件属性
      console.log(child.value.msg) //子组件元素

      //调用子组件方法
      child.value.childFun('父组件信息')
    })
    return {
      child //必须return出去 否则获取不到实例
    }
  },
});
</script>

//子组件

<template>
    <div>
    </div>
</template>
<script>
import { defineComponent, ref } from "vue";
export default defineComponent({
    setup() {
        const msg = ref('子组件元素')
        const childFun = (val) => {
            console.log(`子组件方法被调用,值${val}`)
        }
        return {
            msg,
            childFun
        }
    },
});
</script>
Copy after login
  • setup syntax sugar
//父组件

<template>
  <div>
    <Child ref="child" />
  </div>
</template>
<script setup>
import Child from './Child'
import { ref, onMounted } from "vue";
const child = ref() //注意命名需要和template中ref对应
onMounted(() => {
  //获取子组件属性
  console.log(child.value.msg) //子组件元素

  //调用子组件方法
  child.value.childFun('父组件信息')
})
</script>

//子组件

<template>
    <div>
    </div>
</template>
<script setup>
import { ref,defineExpose } from "vue";
const msg = ref('子组件元素')
const childFun = (val) => {
    console.log(`子组件方法被调用,值${val}`)
}
//必须暴露出去父组件才会获取到
defineExpose({
    childFun,
    msg
})
</script>
Copy after login

Note

Obtaining the subcomponent instance through ref must be obtained after the page is mounted.

When using setup syntax sugar, the child component must expose elements or methods to the parent component in order to obtain

EventBus/mitt

sibling component communication It can be implemented through an event center EventBus, which creates a new Vue instance to monitor, trigger and destroy events.

There is no EventBus sibling component communication in Vue3, but now there is an alternative solutionmitt.js, the principle is still EventBus

  • Optional API
//组件1
<template>
  <div>
    <button @click="sendMsg">传值</button>
  </div>
</template>
<script>
import Bus from './bus.js'
export default {
  data(){
    return {
      msg:'子组件元素'
    }
  },
  methods:{
    sendMsg(){
      Bus.$emit('sendMsg','兄弟的值')
    }
  }
}
</script>

//组件2

<template>
  <div>
    组件2
  </div>
</template>
<script>
import Bus from './bus.js'
export default {
  created(){
   Bus.$on('sendMsg',(val)=>{
    console.log(val);//兄弟的值
   })
  }
}
</script>

//bus.js

import Vue from "vue"
export default new Vue()
Copy after login
  • Combined API

First install mitt

npm i mitt -S
Copy after login

and then create a new one like bus.js in Vue2mitt.jsFile

mitt.js

import mitt from 'mitt'
const Mitt = mitt()
export default Mitt
Copy after login
//组件1
<template>
     <button @click="sendMsg">传值</button>
</template>
<script>
import { defineComponent } from "vue";
import Mitt from './mitt.js'
export default defineComponent({
    setup() {
        const sendMsg = () => {
            Mitt.emit('sendMsg','兄弟的值')
        }
        return {
           sendMsg
        }
    },
});
</script>

//组件2
<template>
  <div>
    组件2
  </div>
</template>
<script>
import { defineComponent, onUnmounted } from "vue";
import Mitt from './mitt.js'
export default defineComponent({
  setup() {
    const getMsg = (val) => {
      console.log(val);//兄弟的值
    }
    Mitt.on('sendMsg', getMsg)
    onUnmounted(() => {
      //组件销毁 移除监听
      Mitt.off('sendMsg', getMsg)
    })

  },
});
</script>
Copy after login
  • setup syntax sugar
//组件1

<template>
    <button @click="sendMsg">传值</button>
</template>
<script setup>
import Mitt from './mitt.js'
const sendMsg = () => {
    Mitt.emit('sendMsg', '兄弟的值')
}
</script>

//组件2

<template>
  <div>
    组件2
  </div>
</template>
<script setup>
import { onUnmounted } from "vue";
import Mitt from './mitt.js'
const getMsg = (val) => {
  console.log(val);//兄弟的值
}
Mitt.on('sendMsg', getMsg)
onUnmounted(() => {
  //组件销毁 移除监听
  Mitt.off('sendMsg', getMsg)
})
</script>
Copy after login

Write at the end

In fact, components can also communicate with Vuex or Pinia state management tools (but this is generally not recommended for communication between components, because this will cause the problem that components cannot be reused). For the usage of Vuex and Pinia, you can refer to this article An article analyzing Pinia and Vuex

(Learning video sharing: web front-end development, Basic programming video )

The above is the detailed content of How to communicate between components? Inventory of Vue component communication methods (worth collecting). For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:juejin.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template