欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue3的provide和inject實(shí)現(xiàn)多級(jí)傳遞的原理解析

 更新時(shí)間:2024年12月03日 08:49:43   作者:前端歐陽  
Vue3中的provide和inject函數(shù)通過原型鏈實(shí)現(xiàn)數(shù)據(jù)的多級(jí)傳遞,父組件使用provide注入數(shù)據(jù),子組件和后代組件通過inject獲取這些數(shù)據(jù),在創(chuàng)建組件實(shí)例時(shí),子組件會(huì)繼承父組件的provides屬性對(duì)象,介紹Vue3的provide和inject實(shí)現(xiàn)多級(jí)傳遞的原理,需要的朋友可以參考下

前言

沒有看過provideinject函數(shù)源碼的小伙伴可能覺得他們實(shí)現(xiàn)數(shù)據(jù)多級(jí)傳遞非常神秘,其實(shí)他的源碼非常簡單,這篇文章歐陽來講講provideinject函數(shù)是如何實(shí)現(xiàn)數(shù)據(jù)多級(jí)傳遞的。ps:本文中使用的Vue版本為3.5.13

看個(gè)demo

先來看個(gè)demo,這個(gè)是父組件,代碼如下:

<template>
  <ChildDemo />
</template>
<script setup>
import ChildDemo from "./child.vue";
import { ref, provide } from "vue";
// 提供響應(yīng)式的值
const count = ref(0);
provide("count", count);
</script>

在父組件中使用provide為后代組件注入一個(gè)count響應(yīng)式變量。

再來看看子組件child.vue代碼如下:

<template>
  <GrandChild />
</template>
<script setup>
import GrandChild from "./grand-child.vue";
</script>

從上面的代碼可以看到在子組件中什么事情都沒做,只渲染了孫子組件。

我們再來看看孫子組件grand-child.vue,代碼如下:

<script setup>
import { inject } from "vue";
// 注入響應(yīng)式的值
const count = inject("count");
console.log("inject count is:", count);
</script>

從上面的代碼可以看到在孫子組件中使用inject函數(shù)拿到了父組件中注入的count響應(yīng)式變量。

provide函數(shù)

我們先來debug看看provide函數(shù)的代碼,給父組件中的provide函數(shù)打個(gè)斷點(diǎn),如下圖:

刷新頁面,此時(shí)代碼將會(huì)停留在斷點(diǎn)處。讓斷點(diǎn)走進(jìn)provide函數(shù),代碼如下:

function provide(key, value) {
  if (!currentInstance) {
    if (!!(process.env.NODE_ENV !== "production")) {
      warn$1(`provide() can only be used inside setup().`);
    }
  } else {
    let provides = currentInstance.provides;
    const parentProvides = currentInstance.parent && currentInstance.parent.provides;
    if (parentProvides === provides) {
      provides = currentInstance.provides = Object.create(parentProvides);
    }
    provides[key] = value;
  }
}

首先判斷currentInstance是否有值,如果沒有就說明當(dāng)前沒有vue實(shí)例,也就是說當(dāng)前調(diào)用provide函數(shù)的地方是不在setup函數(shù)中執(zhí)行的,然后給出警告provide只能在setup中使用。

然后走進(jìn)else邏輯中,首先從當(dāng)前vue實(shí)例中取出存的provides屬性對(duì)象。并且通過currentInstance.parent.provides拿到父組件vue實(shí)例中的provides屬性對(duì)象。

這里為什么需要判斷if (parentProvides === provides)呢?

因?yàn)樵趧?chuàng)建子組件時(shí)會(huì)默認(rèn)使用父組件的provides屬性對(duì)象作為父組件的provides屬性對(duì)象。代碼如下:

const instance: ComponentInternalInstance = {
  uid: uid++,
  vnode,
  type,
  parent,
  provides: parent ? parent.provides : Object.create(appContext.provides),
  // ...省略
}

從上面的代碼可以看到如果有父組件,那么創(chuàng)建子組件實(shí)例的時(shí)候就直接使用父組件的provides屬性對(duì)象。

所以這里在provide函數(shù)中需要判斷if (parentProvides === provides),如果相等說明當(dāng)前父組件和子組件是共用的同一個(gè)provides屬性對(duì)象。此時(shí)如果子組件調(diào)用了provide函數(shù),說明子組件需要?jiǎng)?chuàng)建自己的provides屬性對(duì)象。

并且新的屬性對(duì)象還需要能夠訪問到父組件中注入的內(nèi)容,所以這里以父組件的provides屬性對(duì)象為原型去創(chuàng)建一個(gè)新的子組件的,這樣在子組件中不僅能夠訪問到原型鏈中注入的provides屬性對(duì)象,也能夠訪問到自己注入進(jìn)去的provides屬性對(duì)象。

最后就是執(zhí)行provides[key] = value將當(dāng)前注入的內(nèi)容存到provides屬性對(duì)象中。

inject函數(shù)

我們再來看看inject函數(shù)是如何隔了一層子組件從父組件中如何取出數(shù)據(jù)的,還是一樣的套路,給孫子組件中的inject函數(shù)打個(gè)斷點(diǎn)。如下圖:

將斷點(diǎn)走進(jìn)inject函數(shù),代碼如下:

export function inject(
  key: InjectionKey<any> | string,
  defaultValue?: unknown,
  treatDefaultAsFactory = false,
) {
  // fallback to `currentRenderingInstance` so that this can be called in
  // a functional component
  const instance = currentInstance || currentRenderingInstance
  // also support looking up from app-level provides w/ `app.runWithContext()`
  if (instance || currentApp) {
    const provides = currentApp
      ? currentApp._context.provides
      : instance
        ? instance.parent == null
          ? instance.vnode.appContext && instance.vnode.appContext.provides
          : instance.parent.provides
        : undefined
    if (provides && key in provides) {
      return provides[key]
    } else if (arguments.length > 1) {
      return treatDefaultAsFactory && isFunction(defaultValue)
        ? defaultValue.call(instance && instance.proxy)
        : defaultValue
    } else if (__DEV__) {
      warn(`injection "${String(key)}" not found.`)
    }
  } else if (__DEV__) {
    warn(`inject() can only be used inside setup() or functional components.`)
  }
}

首先拿到當(dāng)前渲染的vue實(shí)例賦值給本地變量instance。接著使用if (instance || currentApp)判斷當(dāng)前是否有vue實(shí)例,如果沒有看看有沒有使用app.runWithContext手動(dòng)注入了上下文,如果注入了那么currentApp就有值。

接著就是一串三元表達(dá)式,如果使用app.runWithContext手動(dòng)注入了上下文,那么就優(yōu)先從注入的上下文中取出provides屬性對(duì)象。

如果沒有那么就看當(dāng)前組件是否滿足instance.parent == null,也就是說當(dāng)前組件是否是根節(jié)點(diǎn)。如果是根節(jié)點(diǎn)就取app中注入的provides屬性對(duì)象。

如果上面的都不滿足就去取父組件中注入的provides屬性對(duì)象,前面我們講過了在inject函數(shù)階段,如果子組件內(nèi)沒有使用inject函數(shù),那么就會(huì)直接使用父組件的provides屬性對(duì)象。如果子組件中使用了inject函數(shù),那么就以父組件的provides屬性對(duì)象為原型去創(chuàng)建一個(gè)新的子組件的provides屬性對(duì)象,從而形成一條原型鏈。

所以這里的孫子節(jié)點(diǎn)的provides屬性對(duì)象中當(dāng)然就能夠拿到父組件中注入的count響應(yīng)式變量,那么if (provides && key in provides)就滿足條件,最后會(huì)走到return provides[key]中將父組件中注入的響應(yīng)式變量count原封不動(dòng)的返回。

還有就是如果我們inject一個(gè)沒有使用provide存入的key,并且傳入了第二個(gè)參數(shù)defaultValue,此時(shí)else if (arguments.length > 1)就滿足條件了。

在里面會(huì)去判斷是否傳入第三個(gè)參數(shù)treatDefaultAsFactory,如果這個(gè)參數(shù)的值為true,說明第二個(gè)參數(shù)defaultValue可能是一個(gè)工廠函數(shù)。那么就執(zhí)行defaultValue.call(instance && instance.proxy)defaultValue的當(dāng)中工廠函數(shù)的執(zhí)行結(jié)果進(jìn)行返回。

如果第三個(gè)參數(shù)treatDefaultAsFactory的值不為true,那么就直接將第二個(gè)參數(shù)defaultValue當(dāng)做默認(rèn)值返回。

總結(jié)

這篇文章講了使用provideinject函數(shù)是如何實(shí)現(xiàn)數(shù)據(jù)多級(jí)傳遞的。

在創(chuàng)建vue組件實(shí)例時(shí),子組件的provides屬性對(duì)象會(huì)直接使用父組件的provides屬性對(duì)象。如果在子組件中使用了provide函數(shù),那么會(huì)以父組件的provides屬性對(duì)象為原型創(chuàng)建一個(gè)新的provides屬性對(duì)象,并且將provide函數(shù)中注入的內(nèi)容塞到新的provides屬性對(duì)象中,從而形成了原型鏈。

在孫子組件中,他的parent就是子組件。前面我們講過了如果沒有在組件內(nèi)使用provide注入東西(很明顯這里的子組件確實(shí)沒有注入任何東西),那么就會(huì)直接使用他的父組件的provides屬性對(duì)象,所以這里的子組件是直接使用的是父組件中的provides屬性對(duì)象。所以在孫子組件中可以直接使用inject函數(shù)拿到父組件中注入的內(nèi)容。

到此這篇關(guān)于來談?wù)刅ue3的provide和inject實(shí)現(xiàn)多級(jí)傳遞的原理的文章就介紹到這了,更多相關(guān)Vue3的provide和inject多級(jí)傳遞內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 淺談vue單頁面中有多個(gè)echarts圖表時(shí)的公用代碼寫法

    淺談vue單頁面中有多個(gè)echarts圖表時(shí)的公用代碼寫法

    這篇文章主要介紹了淺談vue單頁面中有多個(gè)echarts圖表時(shí)的公用代碼寫法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-07-07
  • vue選項(xiàng)卡切換登錄方式小案例

    vue選項(xiàng)卡切換登錄方式小案例

    這篇文章主要為大家詳細(xì)介紹了vue選項(xiàng)卡切換登錄方式小案例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • Vue打包后頁面出現(xiàn)空白解決辦法

    Vue打包后頁面出現(xiàn)空白解決辦法

    本文主要介紹了Vue打包后頁面出現(xiàn)空白解決辦法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Vue實(shí)現(xiàn)Excel預(yù)覽功能使用場景示例詳解

    Vue實(shí)現(xiàn)Excel預(yù)覽功能使用場景示例詳解

    這篇文章主要為大家介紹了Vue實(shí)現(xiàn)Excel預(yù)覽功能使用場景示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • VUE實(shí)現(xiàn)表單元素雙向綁定(總結(jié))

    VUE實(shí)現(xiàn)表單元素雙向綁定(總結(jié))

    本篇文章主要介紹了VUE實(shí)現(xiàn)表單元素雙向綁定(總結(jié)) ,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • vue中的@click.native 原生點(diǎn)擊事件

    vue中的@click.native 原生點(diǎn)擊事件

    這篇文章主要介紹了vue中的@click.native 原生點(diǎn)擊事件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • Vue使用axios進(jìn)行g(shù)et請(qǐng)求拼接參數(shù)的2種方式詳解

    Vue使用axios進(jìn)行g(shù)et請(qǐng)求拼接參數(shù)的2種方式詳解

    axios中post請(qǐng)求都是要求攜帶參數(shù)進(jìn)行請(qǐng)求,這篇文章主要給大家介紹了關(guān)于Vue使用axios進(jìn)行g(shù)et請(qǐng)求拼接參數(shù)的2種方式,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-01-01
  • vue3+element?Plus實(shí)現(xiàn)表格前端分頁完整示例

    vue3+element?Plus實(shí)現(xiàn)表格前端分頁完整示例

    這篇文章主要給大家介紹了關(guān)于vue3+element?Plus實(shí)現(xiàn)表格前端分頁的相關(guān)資料,雖然很多時(shí)候后端會(huì)把分頁,搜索,排序都做好,但是有些返回?cái)?shù)據(jù)并不多的頁面,或者其他原因不能后端分頁的通常會(huì)前端處理,需要的朋友可以參考下
    2023-08-08
  • 關(guān)于vue3使用particles粒子特效的問題

    關(guān)于vue3使用particles粒子特效的問題

    這篇文章主要介紹了關(guān)于vue3使用particles粒子特效的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • vue中import導(dǎo)入三種方式詳解

    vue中import導(dǎo)入三種方式詳解

    在使用vue開發(fā)項(xiàng)目的時(shí)候,很多使用會(huì)import很多模塊,這篇文章主要給大家介紹了關(guān)于vue中import導(dǎo)入三種方式的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-02-02

最新評(píng)論