<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      徹底搞清楚vue3的defineExpose宏函數是如何暴露方法給父組件使用

      前言

      眾所周知,當子組件使用setup后,父組件就不能像vue2那樣直接就可以訪問子組件內的屬性和方法。這個時候就需要在子組件內使用defineExpose宏函數來指定想要暴露出去的屬性和方法。這篇文章來講講defineExpose宏函數是如何暴露出去這些屬性和方法給父組件使用。注:本文中使用的vue版本為3.4.19

      關注公眾號:【前端歐陽】,給自己一個進階vue的機會

      加我微信heavenyjj0012回復「666」,免費領取歐陽研究vue源碼過程中收集的源碼資料,歐陽寫文章有時也會參考這些資料。同時讓你的朋友圈多一位對vue有深入理解的人。

      看個demo

      父組件index.vue的代碼如下:

      <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中定義的屬性和方法。如下圖:
      no-defineExpose

      我們再來看看子組件child.vue使用defineExpose宏的例子,代碼如下:

      <template></template>
      
      <script setup>
      function validate() {
        console.log("執行子組件validate方法");
      }
      
      defineExpose({
        validate,
      });
      </script>
      

      在瀏覽器中點擊父組件的button按鈕,可以看到控制臺中打印的不再是undefined,子組件內的validate方法也執行了。如下圖:
      has-defineExpose

      關注公眾號:【前端歐陽】,給自己一個進階vue的機會

      加我微信heavenyjj0012回復「666」,免費領取歐陽研究vue源碼過程中收集的源碼資料,歐陽寫文章有時也會參考這些資料。同時讓你的朋友圈多一位對vue有深入理解的人。

      編譯后的代碼

      首先需要在瀏覽器中找到編譯后的使用defineExpose宏的child.vue文件,在network面板中找到child.vue,然后右鍵點擊Open in Sources panel就可以在source面板中找到編譯后的child.vue。如下圖:
      network

      為了要在瀏覽器中debug,我們還需要在設置中關閉瀏覽器的javascript source map,如下圖:
      source-map

      現在我們來看看編譯后的child.vue文件,代碼如下:

      const _sfc_main = {
        __name: "child",
        setup(__props, { expose: __expose }) {
          function validate() {
            console.log("執行子組件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對應的就是我們源代碼<script setup>中的內容,并且defineExpose宏函數也不在了,變成了一個__expose方法(defineExpose宏函數如何編譯成__expose方法我們會在下一篇文章講)。如下圖:
      convert

      expose方法

      __expose方法打個斷點,刷新頁面此時斷點停留在__expose方法上面。點擊step into進入到__expose方法內部,如下圖:
      step-into

      進入到__expose方法內部,我們發現__expose方法是在一個createSetupContext函數中定義的。在我們這個場景中createSetupContext函數簡化后的代碼如下:

      function createSetupContext(instance) {
        const expose = (exposed) => {
          instance.exposed = exposed || {};
        };
      
        return Object.freeze({
          // ...省略
          expose,
        });
      }
      

      我們先來看看函數中的instance變量,我想你通過名字應該已經猜到了他就是當前vue實例對象。如下圖:
      instance

      在vue實例對象中有我們熟悉的data方法、directives和componens屬性等。

      expose函數內部做的事情也很簡單,將子組件需要暴露的屬性或者方法組成的對象賦值給vue實例上的exposed屬性。

      父組件訪問子組件的validate方法

      在vue3中想要訪問子組件需要使用特殊的 ref attribute,在我們這個例子中就是使用<ChildDemo ref="child" />。這樣使用后就可以使用child變量訪問子組件,其實在這里child變量的值就是一個名為getExposeProxy函數的返回值(后面的文章中會去詳細講解ref attribute是如何訪問子組件)。

      getExposeProxy函數的代碼如下:

      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

      在上面的getExposeProxy函數中就是返回了instance.exposedProxy對象,當我們使用child.value.validate訪問子組件的validate方法,其實就是訪問的是instance.exposed對象中的validate方法,而instance.exposed中的validate方法就是defineExpose宏函數暴露的validate方法。如下圖:
      full-progress

      總結

      父組件想要訪問子組件暴露的validate方法主要分為下面四步:

      • 子組件使用defineExpose宏函數聲明想要暴露validate方法。

      • defineExpose宏函數經過編譯后變成__expose方法。

      • 執行__expose方法將子組件需要暴露的屬性或者方法組成的對象賦值給子組件vue實例上的exposed屬性,也就是instance.exposed

      • 父組件使用ref訪問子組件的validate方法,也就是訪問child.value.validate。其實訪問的就是上一步的instance.exposed.validate方法,最終訪問的就是defineExpose宏函數中暴露的validate方法。

      關注公眾號:【前端歐陽】,給自己一個進階vue的機會

      加我微信heavenyjj0012回復「666」,免費領取歐陽研究vue源碼過程中收集的源碼資料,歐陽寫文章有時也會參考這些資料。同時讓你的朋友圈多一位對vue有深入理解的人。

      posted @ 2024-05-29 08:51  前端歐陽  閱讀(1142)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 东京热人妻无码一区二区av| 日本精品极品视频在线| 国产资源精品中文字幕| 国产精品色三级在线观看 | 久久久亚洲欧洲日产国码αv| 日韩精品中文字幕有码| 亚洲熟少妇在线播放999| 久久精品国产免费观看频道| 亚洲精品国产无套在线观| 国产99在线 | 亚洲| 巢湖市| 成在线人视频免费视频| 人人做人人妻人人精| 亚洲国产成人无码网站大全| 亚洲精品熟女一区二区| 欧美一区二区三区欧美日韩亚洲| 亚洲AVAV天堂AV在线网阿V| 欧美日韩中文国产一区| 国产日韩av二区三区| jizzjizz日本高潮喷水| 亚洲av专区一区| 亚洲色大成网站www永久男同| 麻豆一区二区三区蜜桃免费| 久久国产精99精产国高潮| 中文国产不卡一区二区| 老师破女学生处特级毛ooo片| 亚洲色偷偷色噜噜狠狠99| 亚洲av无码之国产精品网址蜜芽| 国产乱码日韩亚洲精品成人| 一区二区三区不卡国产| 红桃视频成人传媒| 亚洲国产成人久久综合一区77| 自拍偷在线精品自拍偷免费| 亚洲日韩AV秘 无码一区二区| 国产精品久久久久无码网站| 久久三级国内外久久三级| 国产区二区三区在线观看| 日本高清中文字幕免费一区二区| 亚洲色成人网站www永久下载| 青春草公开在线视频日韩| 男女动态无遮挡动态图|