Vue3新增的组件通讯API:defineProps()
、 defineEmits()
和defineExpose()
defineProps()
、 defineEmits()
和defineExpose()
只能在 <script setup>
中使用(的编译器宏),使用前不需要 通过 import
方式 导入,它们会随着 <script setup>
的处理过程一同被编译掉。
1、defineProps()
使用场景: 父组件传值给子组件(父传子)
说明: defineProps()
接收与 props
选项相同的值,声明的 props
会自动暴露给template
模板(在子组件template
中可以直接使用defineProps
传过来的父组件的值 )。
使用方法如下:
父组件:App.vue
<template>
<div class="app">app组件(父组件)</div>
<!-- 子组件 -->
<Child :countData="count" :infData="info" />
</template>
<script setup>
import { ref, reactive } from 'vue'
import Child from './components/Child.vue'
const count = ref(10)
const info = reactive({
name: 'xiaozhu',
age: 18,
})
</script>
<style scope>
.app {
border: 1px solid black;
padding: 50px;
}
</style>
子组件:Child.vue
<template>
<div class="child">
Child组件
<div>父组件传过来的数据count:{{ countData }} info:{{ infData.name }}-{{ infData.age }}</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
// defineProps 不需要 通过 import 导入,直接可以使用,声明的 props 会自动暴露给 template模板
const childData = defineProps({
countData: {
type: Number,
default: 0,
},
infData: Object,
})
// 想要在子组件的setup中 获取父组件传过来的数据,需要 接受 defineProps 返回值,通过返回值获取对应数据
console.log('childData.countData', childData.countData)
</script>
<style scope>
.child {
border: 1px solid red;
padding: 50px;
}
</style>
父传子数据流程:
效果展示:
2、defineEmits()
使用场景: 子组件传值给父组件(子传父)
说明: defineEmits()
接收与 emits
选项相同的值,子组件通过 defineEmits()
声明的 emit
函数传递方法和对应的数据,父组件根据子组件传过来的方法进行自定义事件,然后绑定父组件中定义的方法进行接收。
使用方法如下:
父组件:App.vue
<template>
<div class="app">app组件(父组件) {{ count }} {{ info.name }}-{{ info.age }}</div>
<!-- 子组件 -->
<Child @changeCount="change" @modifyInfo="modify" />
</template>
<script setup>
import { ref, reactive } from 'vue'
import Child from './components/Child.vue'
const count = ref(10)
const info = reactive({
name: 'xiaozhu',
age: 18,
})
// 改变 count值
const change = (num1, num2) => {
// num1 和 num2 是从 子组件传过来的 数据,10 和 20
console.log('num1', num1, 'num2', num2)
count.value += num1 + num2
}
const modify = (data) => {
// data 是从子组件传过来的 数据 { name: '筱竹', age: 20 }
console.log('data', data)
const { name, age } = data
info.name = name
info.age = age
}
</script>
<style scope>
.app {
border: 1px solid black;
padding: 50px;
}
</style>
子组件:Child.vue
<template>
<div class="child">
Child组件
<button @click="handle()">处理</button>
</div>
</template>
<script setup>
const emit = defineEmits(['changeCount', 'modifyInfo'])
const handle = () => {
// 子组件通过 emit 向父组件传递数据
console.log('Child组件中的 emit事件 触发了')
emit('changeCount', 10, 20)
emit('modifyInfo', { name: '筱竹', age: 20 })
}
</script>
<style scope>
.child {
border: 1px solid red;
padding: 50px;
}
</style>
父传子数据流程:
效果展示:
3、defineExpose()
使用场景: 子组件向外暴露属性和方法给父组件
说明: 使用了 的子组件中的任何属性和方法,如果子组件想要向外暴露组件中的属性和方法,需要使用defineExpose()
来显式指定在 <script setup>
组件中要暴露出去的属性和方法。
使用方法如下:
父组件:App.vue
<template>
<div class="app">
app组件(父组件)
{{ info }} - {{ data.bookName }}- {{ data.author }}
<br />
<button @click="getData">获取子组件中的数据</button>
</div>
<!-- 子组件 -->
<Child ref="getMsg" />
</template>
<script setup>
import { ref, toRefs } from 'vue'
import Child from './components/Child.vue'
// 在父组件中需要设置 ref 获取到 子组件中的数据
const getMsg = ref(null)
const info = ref(null)
const data = ref({})
const getData = () => {
// 在子组件中 通过 defineExpose 编译器宏 显式暴露数据后,可以在父组件中 通过 ref 就获取到子组件中数据了,并可以对子组件中的数据进行操作。
console.log('getMsg.value.msg', getMsg.value.msg)
console.log('getMsg.value.msg', getMsg.value.infoData)
getMsg.value.release()
const { msg, infoData } = getMsg.value
info.value = msg
data.value = infoData
}
</script>
<style scope>
.app {
border: 1px solid black;
padding: 50px;
}
</style>
子组件:Child.vue
import { reactive } from 'vue';
<template>
<div class="app">
Child组件
{{ msg }}-{{ infoData.bookName }}-{{ infoData.author }}
</div>
</template>
<script setup>
import { ref, reactive } from 'vue'
const msg = ref('hello vue3')
const infoData = reactive({
bookName: '《Vue3.js项目实战开发》',
author: '筱竹',
})
const release = () => {
console.log('我是子组件中的release方法')
}
// 使用了 <script setup> 的组件是默认私有的:一个父组件无法访问到一个使用了 <script setup> 的子组件中的任何东西,除非子组件在其中通过 defineExpose 宏显式暴露,defineExpose 这样的编译器宏不需要导入就可以直接使用。
defineExpose({
msg,
infoData,
release,
})
</script>
<style scope>
.child {
border: 1px solid red;
}
</style>
子组件数据暴露流程:
效果展示: