vue3的defineExpose宏函數(shù)是如何暴露方法給父組件使用
前言
眾所周知,當(dāng)子組件使用setup后,父組件就不能像vue2那樣直接就可以訪問子組件內(nèi)的屬性和方法。這個(gè)時(shí)候就需要在子組件內(nèi)使用defineExpose宏函數(shù)來(lái)指定想要暴露出去的屬性和方法。這篇文章來(lái)講講defineExpose宏函數(shù)是如何暴露出去這些屬性和方法給父組件使用。注:本文中使用的vue版本為3.4.19。
看個(gè)demo
父組件index.vue的代碼如下:
<template>
<ChildDemo ref="child" />
<button @click="handleClick">調(diào)用子組件的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>上面的代碼很簡(jiǎn)單,通過ref拿到子組件的實(shí)例賦值給child變量。然后在按鈕的click事件中打印出子組件的validate方法和執(zhí)行validate方法。
再來(lái)看看子組件child.vue不使用defineExpose宏的例子,代碼如下:
<template></template>
<script setup>
function validate() {
console.log("執(zhí)行子組件validate方法");
}
</script>在瀏覽器中點(diǎn)擊父組件的button按鈕,可以看到控制臺(tái)中打印的是undefined,并且子組件內(nèi)的validate方法也沒有執(zhí)行。因?yàn)樽咏M件使用了setup,默認(rèn)是不會(huì)暴露setup中定義的屬性和方法。如下圖:

我們?cè)賮?lái)看看子組件child.vue使用defineExpose宏的例子,代碼如下:
<template></template>
<script setup>
function validate() {
console.log("執(zhí)行子組件validate方法");
}
defineExpose({
validate,
});
</script>在瀏覽器中點(diǎn)擊父組件的button按鈕,可以看到控制臺(tái)中打印的不再是undefined,子組件內(nèi)的validate方法也執(zhí)行了。如下圖:

加我微信heavenyjj0012回復(fù)「666」,免費(fèi)領(lǐng)取歐陽(yáng)研究vue源碼過程中收集的源碼資料,歐陽(yáng)寫文章有時(shí)也會(huì)參考這些資料。同時(shí)讓你的朋友圈多一位對(duì)vue有深入理解的人。
編譯后的代碼
首先需要在瀏覽器中找到編譯后的使用defineExpose宏的child.vue文件,在network面板中找到child.vue,然后右鍵點(diǎn)擊Open in Sources panel就可以在source面板中找到編譯后的child.vue。如下圖:

為了要在瀏覽器中debug,我們還需要在設(shè)置中關(guān)閉瀏覽器的javascript source map,如下圖:

現(xiàn)在我們來(lái)看看編譯后的child.vue文件,代碼如下:
const _sfc_main = {
__name: "child",
setup(__props, { expose: __expose }) {
function validate() {
console.log("執(zhí)行子組件validate方法");
}
__expose({
validate,
});
const __returned__ = { validate };
return __returned__;
},
};
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
return null;
}
_sfc_main.render = _sfc_render;
export default _sfc_main;從上面可以看到_sfc_main對(duì)象中的setup對(duì)應(yīng)的就是我們?cè)创a<script setup>中的內(nèi)容,并且defineExpose宏函數(shù)也不在了,變成了一個(gè)__expose方法(defineExpose宏函數(shù)如何編譯成__expose方法我們會(huì)在下一篇文章講)。如下圖:

expose方法
給__expose方法打個(gè)斷點(diǎn),刷新頁(yè)面此時(shí)斷點(diǎn)停留在__expose方法上面。點(diǎn)擊step into進(jìn)入到__expose方法內(nèi)部,如下圖:

進(jìn)入到__expose方法內(nèi)部,我們發(fā)現(xiàn)__expose方法是在一個(gè)createSetupContext函數(shù)中定義的。在我們這個(gè)場(chǎng)景中createSetupContext函數(shù)簡(jiǎn)化后的代碼如下:
function createSetupContext(instance) {
const expose = (exposed) => {
instance.exposed = exposed || {};
};
return Object.freeze({
// ...省略
expose,
});
}我們先來(lái)看看函數(shù)中的instance變量,我想你通過名字應(yīng)該已經(jīng)猜到了他就是當(dāng)前vue實(shí)例對(duì)象。如下圖:

在vue實(shí)例對(duì)象中有我們熟悉的data方法、directives和componens屬性等。
在expose函數(shù)內(nèi)部做的事情也很簡(jiǎn)單,將子組件需要暴露的屬性或者方法組成的對(duì)象賦值給vue實(shí)例上的exposed屬性。
父組件訪問子組件的validate方法
在vue3中想要訪問子組件需要使用特殊的 ref attribute,在我們這個(gè)例子中就是使用<ChildDemo ref="child" />。這樣使用后就可以使用child變量訪問子組件,其實(shí)在這里child變量的值就是一個(gè)名為getExposeProxy函數(shù)的返回值(后面的文章中會(huì)去詳細(xì)講解ref attribute是如何訪問子組件)。
getExposeProxy函數(shù)的代碼如下:
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宏函數(shù)中定義了想要暴露出來(lái)的屬性和方法,經(jīng)過編譯后defineExpose宏函數(shù)變成了__expose方法。執(zhí)行__expose方法后會(huì)將子組件想要暴露的屬性或者方法組成的對(duì)象賦值給vue實(shí)例上的exposed屬性,也就是instance.exposed。
在上面的getExposeProxy函數(shù)中就是返回了instance.exposed的Proxy對(duì)象,當(dāng)我們使用child.value.validate訪問子組件的validate方法,其實(shí)就是訪問的是instance.exposed對(duì)象中的validate方法,而instance.exposed中的validate方法就是defineExpose宏函數(shù)暴露的validate方法。如下圖:

總結(jié)
父組件想要訪問子組件暴露的validate方法主要分為下面四步:
- 子組件使用
defineExpose宏函數(shù)聲明想要暴露validate方法。 defineExpose宏函數(shù)經(jīng)過編譯后變成__expose方法。- 執(zhí)行
__expose方法將子組件需要暴露的屬性或者方法組成的對(duì)象賦值給子組件vue實(shí)例上的exposed屬性,也就是instance.exposed。 - 父組件使用ref訪問子組件的
validate方法,也就是訪問child.value.validate。其實(shí)訪問的就是上一步的instance.exposed.validate方法,最終訪問的就是defineExpose宏函數(shù)中暴露的validate方法。
到此這篇關(guān)于vue3的defineExpose宏函數(shù)是如何暴露方法給父組件使用的文章就介紹到這了,更多相關(guān)vue3 defineExpose宏函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解vue 配合vue-resource調(diào)用接口獲取數(shù)據(jù)
本篇文章主要介紹了vue 配合vue-resource調(diào)用接口獲取數(shù)據(jù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
vue自定義權(quán)限指令的實(shí)現(xiàn)
本文主要介紹了vue自定義權(quán)限指令的實(shí)現(xiàn)2024-05-05
vue中通過iframe方式加載本地的vue頁(yè)面的解決方法
這篇文章主要給大家介紹了在vue中如何通過iframe方式加載本地的vue頁(yè)面的解決方法,文中有詳細(xì)的解決流程,需要的朋友可以參考下2023-06-06
vue路由緩存的幾種實(shí)現(xiàn)方式小結(jié)
這篇文章主要介紹了vue路由緩存的幾種實(shí)現(xiàn)方式,結(jié)合實(shí)例形式詳細(xì)分析了vue.js路由緩存常見實(shí)現(xiàn)方式、使用技巧與操作注意事項(xiàng),需要的朋友可以參考下2020-02-02
Vue實(shí)現(xiàn)簡(jiǎn)易翻頁(yè)效果源碼分享
本文給大家分享了vue實(shí)現(xiàn)簡(jiǎn)易翻頁(yè)效果,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-11-11

