vue3的defineExpose宏函數(shù)是如何暴露方法給父組件使用
前言
眾所周知,當子組件使用setup后,父組件就不能像vue2那樣直接就可以訪問子組件內(nèi)的屬性和方法。這個時候就需要在子組件內(nèi)使用defineExpose
宏函數(shù)來指定想要暴露出去的屬性和方法。這篇文章來講講defineExpose
宏函數(shù)是如何暴露出去這些屬性和方法給父組件使用。注:本文中使用的vue版本為3.4.19
。
看個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>
上面的代碼很簡單,通過ref
拿到子組件的實例賦值給child
變量。然后在按鈕的click事件中打印出子組件的validate
方法和執(zhí)行validate
方法。
再來看看子組件child.vue
不使用defineExpose
宏的例子,代碼如下:
<template></template> <script setup> function validate() { console.log("執(zhí)行子組件validate方法"); } </script>
在瀏覽器中點擊父組件的button按鈕,可以看到控制臺中打印的是undefined
,并且子組件內(nèi)的validate
方法也沒有執(zhí)行。因為子組件使用了setup,默認是不會暴露setup中定義的屬性和方法。如下圖:
我們再來看看子組件child.vue
使用defineExpose
宏的例子,代碼如下:
<template></template> <script setup> function validate() { console.log("執(zhí)行子組件validate方法"); } defineExpose({ validate, }); </script>
在瀏覽器中點擊父組件的button按鈕,可以看到控制臺中打印的不再是undefined
,子組件內(nèi)的validate
方法也執(zhí)行了。如下圖:
加我微信heavenyjj0012回復(fù)「666」,免費領(lǐng)取歐陽研究vue源碼過程中收集的源碼資料,歐陽寫文章有時也會參考這些資料。同時讓你的朋友圈多一位對vue有深入理解的人。
編譯后的代碼
首先需要在瀏覽器中找到編譯后的使用defineExpose
宏的child.vue
文件,在network面板中找到child.vue
,然后右鍵點擊Open in Sources panel就可以在source面板中找到編譯后的child.vue
。如下圖:
為了要在瀏覽器中debug,我們還需要在設(shè)置中關(guān)閉瀏覽器的javascript source map,如下圖:
現(xiàn)在我們來看看編譯后的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
對象中的setup
對應(yīng)的就是我們源代碼<script setup>
中的內(nèi)容,并且defineExpose
宏函數(shù)也不在了,變成了一個__expose
方法(defineExpose
宏函數(shù)如何編譯成__expose
方法我們會在下一篇文章講)。如下圖:
expose
方法
給__expose
方法打個斷點,刷新頁面此時斷點停留在__expose
方法上面。點擊step into
進入到__expose
方法內(nèi)部,如下圖:
進入到__expose
方法內(nèi)部,我們發(fā)現(xiàn)__expose
方法是在一個createSetupContext
函數(shù)中定義的。在我們這個場景中createSetupContext
函數(shù)簡化后的代碼如下:
function createSetupContext(instance) { const expose = (exposed) => { instance.exposed = exposed || {}; }; return Object.freeze({ // ...省略 expose, }); }
我們先來看看函數(shù)中的instance
變量,我想你通過名字應(yīng)該已經(jīng)猜到了他就是當前vue實例對象。如下圖:
在vue實例對象中有我們熟悉的data方法、directives和componens屬性等。
在expose
函數(shù)內(nèi)部做的事情也很簡單,將子組件需要暴露的屬性或者方法組成的對象賦值給vue實例上的exposed
屬性。
父組件訪問子組件的validate
方法
在vue3中想要訪問子組件需要使用特殊的 ref
attribute,在我們這個例子中就是使用<ChildDemo ref="child" />
。這樣使用后就可以使用child
變量訪問子組件,其實在這里child
變量的值就是一個名為getExposeProxy
函數(shù)的返回值(后面的文章中會去詳細講解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ù)中定義了想要暴露出來的屬性和方法,經(jīng)過編譯后defineExpose
宏函數(shù)變成了__expose
方法。執(zhí)行__expose
方法后會將子組件想要暴露的屬性或者方法組成的對象賦值給vue實例上的exposed
屬性,也就是instance.exposed
。
在上面的getExposeProxy
函數(shù)中就是返回了instance.exposed
的Proxy
對象,當我們使用child.value.validate
訪問子組件的validate
方法,其實就是訪問的是instance.exposed
對象中的validate
方法,而instance.exposed
中的validate
方法就是defineExpose
宏函數(shù)暴露的validate
方法。如下圖:
總結(jié)
父組件想要訪問子組件暴露的validate
方法主要分為下面四步:
- 子組件使用
defineExpose
宏函數(shù)聲明想要暴露validate
方法。 defineExpose
宏函數(shù)經(jīng)過編譯后變成__expose
方法。- 執(zhí)行
__expose
方法將子組件需要暴露的屬性或者方法組成的對象賦值給子組件vue實例上的exposed
屬性,也就是instance.exposed
。 - 父組件使用ref訪問子組件的
validate
方法,也就是訪問child.value.validate
。其實訪問的就是上一步的instance.exposed.validate
方法,最終訪問的就是defineExpose
宏函數(shù)中暴露的validate
方法。
到此這篇關(guān)于vue3的defineExpose宏函數(shù)是如何暴露方法給父組件使用的文章就介紹到這了,更多相關(guān)vue3 defineExpose宏函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決vue無法加載文件D:\Program Files\nodejs\node_global\vue.ps1,
這篇文章主要給大家介紹了關(guān)于解決vue無法加載文件D:\Program Files\nodejs\node_global\vue.ps1,因為在此系統(tǒng)上禁止運行腳本的相關(guān)資料,這個報錯是由于在系統(tǒng)上禁止運行腳本導致的,文中通過圖文介紹的非常詳細,需要的朋友可以參考下2024-01-01vue使用pdfjs顯示PDF可復(fù)制的實現(xiàn)方法
這篇文章主要介紹了vue使用pdfjs顯示PDF可復(fù)制的實現(xiàn)方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-12-12webpack+vue-cil 中proxyTable配置接口地址代理操作
這篇文章主要介紹了webpack+vue-cil 中proxyTable配置接口地址代理操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07使用Vue.js報錯:ReferenceError: “Vue is not d
在前端開發(fā)中,ReferenceError: "Vue is not defined" 是一個常見的錯誤,該錯誤通常發(fā)生在項目中未正確引入 Vue.js 框架或代碼配置存在問題時,本篇文章將詳細分析該錯誤的成因,并提供多種解決方案,幫助開發(fā)者快速排查問題,需要的朋友可以參考下2024-12-12vue3的介紹和兩種創(chuàng)建方式詳解(cli和vite)
這篇文章主要介紹了vue3的介紹和兩種創(chuàng)建方式(cli和vite),vue3對比vue2帶來的性能提升有很多優(yōu)勢,總體來說Vue 3在性能、開發(fā)體驗和代碼組織方面都有所改進,使得它更加適合于大型、復(fù)雜的應(yīng)用程序開發(fā),需要的朋友可以參考下2023-04-04