携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,点击查看活动详情 >>
Vue中组件通信方式有很多,其中Vue2和Vue3实现起来也会有很多差异;本文将通过选项式API 组合式API以及setup三种不同实现方式全面介绍Vue2和Vue3的组件通信方式。其中将要实现的通信方式如下表所示
| 方式 | Vue2 | Vue3 |
|---|---|---|
| 父传子 | props | props |
| 子传父 | $emit | emits |
| 父传子 | $attrs | attrs |
| 子传父 | $listeners | 无(合并到 attrs方式) |
| 父传子 | provide | provide |
| 子传父 | inject | inject |
| 子组件访问父组件 | $parent | 无 |
| 父组件访问子组件 | $children | 无 |
| 父组件访问子组件 | $ref | expose&ref |
| 兄弟传值 | EventBus | mitt |
props
props是组件通信中最常用的通信方式之一。父组件通过v-bind传入,子组件通过props接收,下面是它的三种实现方式
- 选项式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>
- 组合式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>
- setup语法糖
//父组件
<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>
注意
props中数据流是单项的,即子组件不可改变父组件传来的值
在组合式API中,如果想在子组件中用其它变量接收props的值时需要使用toRef将props中的属性转为响应式。
emit
子组件可以通过emit发布一个事件并传递一些参数,父组件通过v-on进行这个事件的监听
- 选项式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>
- 组合式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>
- setup语法糖
//父组件
<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>