闽公网安备 35020302035485号
<template>
<ChildDemo ref="child" />
<button @click="handleClick">调用子组件的validate方法</button>
</template>
<script setup lang="ts">
import ChildDemo from "./child.vue";
import { ref } from "vue";
const child = ref();
function handleClick() {
console.log(child.value.validate);
child.value.validate?.();
}
</script>
上面的代码很简单,通过ref拿到子组件的实例赋值给child变量。然后在按钮的click事件中打印出子组件的validate方法和执行validate方法。再来看看子组件child.vue不使用defineExpose宏的例子,代码如下:<template></template>
<script setup>
function validate() {
console.log("执行子组件validate方法");
}
</script>
在浏览器中点击父组件的button按钮,可以看到控制台中打印的是undefined,并且子组件内的validate方法也没有执行。因为子组件使用了setup,默认是不会暴露setup中定义的属性和方法。<template></template>
<script setup>
function validate() {
console.log("执行子组件validate方法");
}
defineExpose({
validate,
});
</script>
在浏览器中点击父组件的button按钮,可以看到控制台中打印的不再是undefined,子组件内的validate方法也执行了。如下图:


const _sfc_main = {
__name: "child",
setup(__props, { expose: __expose }) {
function validate() {
console.log("执行子组件validate方法");
}
__expose({
validate,
});
const __returned__ = { validate };
return __returned__;
},
};
// 堆代码 duidaima.com
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
return null;
}
_sfc_main.render = _sfc_render;
export default _sfc_main;
从上面可以看到_sfc_main对象中的setup对应的就是我们源代码<script setup>中的内容,并且defineExpose宏函数也不在了,变成了一个__expose方法(defineExpose宏函数如何编译成__expose方法我们会在下一篇文章讲)。如下图:

function createSetupContext(instance) {
const expose = (exposed) => {
instance.exposed = exposed || {};
};
return Object.freeze({
// ...省略
expose,
});
}
我们先来看看函数中的instance变量,我想你通过名字应该已经猜到了他就是当前vue实例对象。如下图:
function getExposeProxy(instance) {
if (instance.exposed) {
return (
instance.exposeProxy ||
(instance.exposeProxy = new Proxy(proxyRefs(markRaw(instance.exposed)), {
get(target, key) {
if (key in target) {
return target[key];
} else if (key in publicPropertiesMap) {
return publicPropertiesMap[key](instance);
}
},
has(target, key) {
// ...省略
},
}))
);
}
}
前面我们讲过了defineExpose宏函数中定义了想要暴露出来的属性和方法,经过编译后defineExpose宏函数变成了__expose方法。执行__expose方法后会将子组件想要暴露的属性或者方法组成的对象赋值给vue实例上的exposed属性,也就是instance.exposed。