<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。