defineProps 和 defineEmits 只能在<script setup>中使用,是编译器宏(???), 传入到defineProps 和 defineEmits的选项会从setup中提升到模块的范围。
definneExpose API
在标准组件写法里,子组件的数据都是默认隐式暴露给父组件的,但在 script-setup 模式下,所有数据只是默认 return 给 template 使用,不会暴露到组件外,所以父组件是无法直接通过挂载 ref 变量获取子组件的数据。
如果要调用子组件的数据,需要先在子组件显示的暴露出来,才能够正确的拿到,这个操作,就是由 expose 来完成。
expose 也是 context 的一个组件成员,原来的用法是从 useContext 里导出。由于 useContext 会在未来版本里移除,所以新增了 defineExpose API 来实现 expose 的功能。父组件就可以通过 ref API 去拿到子组件暴露出来的数据了。
父组件
<script setup lang="ts">
import TestPropsEmit from './components/test-props-emit/index.vue'
import {ref, onMounted} from 'vue'
const msg = ref('hello world')
const handleChange = (params: string) => {
console.log(params)
}
const propsEmitRef = ref()
onMounted(() => {
console.log(propsEmitRef.value.child)
console.log(propsEmitRef.value.childNode())
})
</script>
<template>
<TestPropsEmit ref="propsEmitRef" :msg="msg" @on-change="handleChange"></TestPropsEmit>
</template>
子组件
<script setup lang="ts">
const props = defineProps({
msg: {
type: String,
default: () => '默认值1'
}
})
const emit = defineEmits(['on-change'])
const handleClick = () => {
emit('on-change', '父组件方法被调用了')
}
const childNode = () => {
console.log('子组件方法被调用了')
}
defineExpose({
child: '我是暴露的子组件',
childNode
})
</script>
<template>
<p>{{msg}}</p>
<p>{{props.msg}}</p>
<button @click="handleClick">点击我调用父组件的方法</button>
</template>