Vue 组件通信全解析:Props、Emit 与 defineExpose

在 Vue 开发中,组件通信是构建复杂应用的关键部分。Vue 提供了多种方式来实现组件之间的数据传递和交互,本文将详细介绍三种常见的组件通信方式:父组件向子组件传递数据(props)、子组件向父组件传递数据(emit)以及子组件向父组件暴露数据(defineExpose),并结合具体代码示例进行讲解。

1. 父组件向子组件传递数据:props

原理

props 是 Vue 中用于实现父组件向子组件传递数据的机制。父组件可以通过在子组件标签上绑定属性的方式,将数据传递给子组件。子组件则使用 defineProps 来声明和接收这些数据。

代码示例

在 defineProps.vue 文件中,父组件定义了一个 msg 的响应式变量:

<script setup>
import {ref} from 'vue'
import ChildComponent from '@/components/ChildComponent.vue'

const msg = ref(0)
</script>

<template>
  <ChildComponent :msg="msg" />
</template>

在 ChildComponent.vue 文件中,子组件使用 defineProps 来接收 msg

<script setup>
import { onMounted,ref } from 'vue';
const props = defineProps({
  msg: {
    type: Number,
    required: true
  }
})
</script>

<template>
  <p>我是父组件传过来的值(msg):{{ msg }}</p>
</template>

在上述代码中,父组件通过 :msg="msg"msg 变量传递给子组件,子组件使用 defineProps 声明并接收 msg,然后在模板中显示该值。

2. 子组件向父组件传递数据:emit

原理

emit 是 Vue 中用于实现子组件向父组件传递数据的机制。子组件可以通过触发自定义事件,并携带数据,将数据传递给父组件。父组件则监听这些自定义事件,并在事件触发时执行相应的处理函数。

代码示例

在 ChildComponent.vue 文件中,子组件定义了一个 msg2 的响应式变量,并通过 defineEmits 声明了一个自定义事件 pass-msg-to-father

<script setup>
import { onMounted,ref } from 'vue';
const props = defineProps({
  msg: {
    type: Number,
    required: true
  }
})

const emit = defineEmits(['pass-msg-to-father'])
const msg2 = ref(666)
onMounted(()=>{
  emit('pass-msg-to-father', msg2)
})
const handleClick = () => {
  msg2.value++
  emit('pass-msg-to-father', msg2)
}
</script>

<template>
  <button @click="handleClick">msg2++</button>
</template>

在 defineProps.vue 文件中,父组件监听 pass-msg-to-father 事件,并在事件触发时执行 getMagFromSon 函数:

<script setup>
import {ref} from 'vue'
import ChildComponent from '@/components/ChildComponent.vue'

const msg2 = ref('')
const getMagFromSon = (data) => {
  msg2.value = data.value
}
</script>

<template>
  <ChildComponent :msg="msg" @pass-msg-to-father="getMagFromSon"/>
  <p>这是子组件传给父组件的值(msg2):{{ msg2 }}</p>
</template>

在上述代码中,子组件在挂载时和点击按钮时分别触发 pass-msg-to-father 事件,并携带 msg2 数据。父组件监听该事件,并在事件触发时更新 msg2 的值。

3. 子组件向父组件暴露数据:defineExpose

原理

defineExpose 是 Vue 3 中新增的一个 API,用于在 <script setup> 中向父组件暴露数据和方法。默认情况下,在 <script setup> 中定义的所有变量和方法都是私有的,父组件无法直接访问。使用 defineExpose 可以将这些变量和方法暴露给父组件。

代码示例

在 ChildComponent2.vue 文件中,子组件定义了一个 sonMsg 的响应式变量和一个 changeSonMsg 方法,并使用 defineExpose 将它们暴露给父组件:

<script setup>
import {ref} from 'vue'

const sonMsg = ref(999);
const changeSonMsg = () => {
  sonMsg.value++
}

defineExpose({
  sonMsg,
  changeSonMsg
})
</script>

<template>
  <p>这是子组件自己的值(sonMsg):{{ sonMsg }}</p>
</template>

在 defineProps.vue 文件中,父组件通过 ref 引用子组件,并调用子组件暴露的方法和访问暴露的数据:

<script setup>
import {ref} from 'vue'
import ChildCommonent2 from '@/components/ChildComponent2.vue'

const son2 = ref(null)
const son2Msg = ref(-1)
const getMsgFromSon2 = () => {
  console.log(son2.value.sonMsg)
  son2.value.changeSonMsg()
  son2Msg.value = son2.value.sonMsg
  console.log(son2.value.sonMsg)
}
</script>

<template>
  <ChildCommonent2 ref="son2"/>
  <p>这是子组件通过defineExpose暴露给父组件的值(son2Msg):{{ son2Msg}}</p>
  <button @click="getMsgFromSon2">修改子组件2的值</button>
</template>

在上述代码中,子组件使用 defineExpose 暴露了 sonMsgchangeSonMsg,父组件通过 ref 引用子组件,并调用 changeSonMsg 方法更新子组件的值,同时访问 sonMsg 数据。

总结

通过 propsemitdefineExpose,我们可以实现 Vue 组件之间的灵活通信。props 用于父组件向子组件传递数据,emit 用于子组件向父组件传递数据,defineExpose 用于子组件向父组件暴露数据和方法。这些机制为我们构建复杂的 Vue 应用提供了强大的支持。

更多推荐