ホームページ  >  記事  >  ウェブフロントエンド  >  Vue.slot の原理について話して、スロットがどのように実装されているかを見てみましょう。

Vue.slot の原理について話して、スロットがどのように実装されているかを見てみましょう。

青灯夜游
青灯夜游転載
2022-05-10 11:55:032968ブラウズ

この記事では、Vue に関する辛口な情報と、あなたが知らないかもしれない Vue.slot の原理についてお話します。皆様のお役に立てれば幸いです。

Vue.slot の原理について話して、スロットがどのように実装されているかを見てみましょう。

日々のビジネス開発でも、基本コンポーネントのカプセル化でも、 スロット スロット は私たちの視野に頻繁に現れると思います。これはプログラミングの実装に非常に便利です。おそらく誰もが slot の使用法に精通しているでしょう。名前付きスロット、または スコープ スロットのさまざまな使用方法など... slotslot-scope のレイヤーは実装されていますか?

わかりやすいVue.slot を 10 分で削除できます ソースコード実装分析###! ! !著者に従って、Vue (v2.6.14) のスロット slot がどのように実装されているかを調べてください。 !この記事では主に 2 つの部分で説明します。

  • 通常のスロット (名前付きスロット、デフォルト スロット)

  • スコープ スロット

この記事には、あいまいなソース コード分析はなく、専門用語で直接説明されているため、Vue ソース コードにどれほど精通していても理解できます。オンサイトのデバッグを通じて、

Vueslot がどのように実装されているかを明確に確認できます。行こう行こう! (学習ビデオ共有: vue ビデオ チュートリアル )

1.

slot の使用法を確認する

まず、スロットの一般的な使用法を確認します。ここでの

slot の使用法では、新しい標準の 2.6.0 を使用します (この記事では、v2.5v2.6 の書き方についても説明します) ソースコード実装の違いは何ですか!)。

使用方法について詳しく知りたい場合は、公式 Web サイトにアクセスして Vue のスロットのドキュメントを詳しく読んでください。

https://cn.vuejs.org/v2/ guide/components-slots.html

1. デフォルトのスロット

<!-- 子组件 -->
<template>
  <div class="wrapper">
    <!-- 默认插槽 -->
    <div class="main">
      <slot></slot>
    </div>
</template>

<!-- 父组件 -->
<my-slot>
  <template>
    <h1>默认插槽</h1>
  </template>
</my-slot>

ページ表示効果は図に示すとおりです:

Vue.slot の原理について話して、スロットがどのように実装されているかを見てみましょう。

2. 名前付きスロット

上記の例に従って、名前付きスロット

header を追加します。コードは次のとおりです:

<!-- 子组件 -->
<template>
  <div class="wrapper">
    <!-- header 具名插槽 -->
    <header class="header">
      <slot name="header"></slot>
    </header>
    <!-- 默认插槽 -->
    <div class="main">
      <slot></slot>
    </div>
</template>

<!-- 父组件 -->
<my-slot>
  <template v-slot:header>
    <h1>header 具名插槽</h1>
  </template>
  <template>
    <h1>默认插槽</h1>
  </template>
</my-slot>

上記のコード ブロックは次のとおりです。 : サブコンポーネント内の

  • slot タグ には name という名前の属性が含まれており、値は header##親コンポーネントの

  • #template タグ

    には属性 v-slot があり、値は header

  • ページの表示効果は次のとおりです:

Vue.slot の原理について話して、スロットがどのように実装されているかを見てみましょう。3. スコープ スロット (slot-scope)

上記に従うこの場合、スコープ スロット

footer

を追加します。コードは次のとおりです。<pre class="brush:js;toolbar:false;">&lt;!-- 子组件 --&gt; &lt;template&gt; &lt;div class=&quot;wrapper&quot;&gt; &lt;!-- header 具名插槽 --&gt; &lt;header class=&quot;header&quot;&gt; &lt;slot name=&quot;header&quot;&gt;&lt;/slot&gt; &lt;/header&gt; &lt;!-- 默认插槽 --&gt; &lt;div class=&quot;main&quot;&gt; &lt;slot&gt;&lt;/slot&gt; &lt;/div&gt; &lt;!-- footer 具名 + 作用域插槽 --&gt; &lt;footer class=&quot;footer&quot;&gt; &lt;slot name=&quot;footer&quot; :footerInfo=&quot;footerInfo&quot;&gt;&lt;/slot&gt; &lt;/footer&gt; &lt;/div&gt; &lt;/template&gt; &lt;script&gt; export default { name: &quot;mySlot&quot;, data () { return { footerInfo: { text: &amp;#39;这是 子组件 footer插槽 的作用域数据&amp;#39; } } } } &lt;/script&gt; &lt;!-- 父组件 --&gt; &lt;my-slot&gt; &lt;template v-slot:header&gt; &lt;h1&gt;header 具名插槽&lt;/h1&gt; &lt;/template&gt; &lt;template&gt; &lt;h1&gt;默认插槽&lt;/h1&gt; &lt;/template&gt; &lt;template v-slot:footer=&quot;slotProps&quot;&gt; &lt;h1&gt;footer 具名 + 作用域插槽&lt;/h1&gt; &lt;p&gt;{{ slotProps.footerInfo.text }}&lt;/p&gt; &lt;/template&gt; &lt;/my-slot&gt;</pre>上記のコード ブロックは次のとおりです。

    The
  • サブコンポーネント内のスロット タグ

    name=footer 属性を除き、:footerInfo="footerInfo" 属性もあります (その機能は子コンポーネント データを渡すことです)#親コンポーネントの

  • ##template タグ
  • v-slot:footer だけでなく、代入操作 ="slotProps "。テンプレートの二重括弧構文で、サブの footerInfo ページにアクセスした後、

    slotProps
  • を直接渡します。 -component のページ表示効果は次の図に示すとおりです。

Vue.slot の原理について話して、スロットがどのように実装されているかを見てみましょう。 さて、簡単なレビューです。使用を終えた後、作成者はここで 3 つの質問をします。

通常スロットとスコープ スロットの vNode はどの段階で生成されますか? 親コンポーネントまたは子コンポーネントをレンダリングするとき?

    スコープ スロット 親コンポーネントから子コンポーネントのデータにアクセスできるのはなぜですか?
  1. 通常のスロットとスコープ スロットでは実装に違いはありますか?
  2. 質問をしながら読み進めましょう。
2. さまざまな

slot

のコンパイルの違い 上記の最後のケース コードに基づいて、パッケージ化コマンドを実行して、テンプレートのコンパイル時に Vue がそれをどのように処理するかを確認します。私たちの スロット

です!これ以上面倒なことはせずに、急いで

build~ (みんなに内緒で言っておきますが、Vueスコープ スロット 通常スロット を処理します。違いはコンパイルから始まります、つまり、レンダリング関数が異なります) ここでは、v2.5

の名前付きスロットの書き込みメソッドを使用して参考にします(名前付きスロットのヘッダーを書き換えるには、

slot="header" を使用してください)、v2.6v2.5 の記述と実装を確認できます。違いは~難しくありません。とにかく、見てみるために取り出してみました

Vue.slot の原理について話して、スロットがどのように実装されているかを見てみましょう。

上图左边是 v2.6 、右边是 v2.5 的,这里,我们集中关注:

  • scopedSlots 属性。使用作用域插槽的 footer 的 render函数 是放在 scopedSlots 里的,并且 函数中 还有接收一个参数

  • my-slotchildren。可以发现,默认插槽的 render函数 一直都是作为当前组件的childre节点,放在 当前 组件render函数 的第三个参数

  • 关注 header 两种具名插槽写法的区别。

    • v2.6 中,我们使用了具名插槽,但是又未使用 作用域插槽的 header 被放在了 scopedSlots但是函数的参数为空,这点跟作用域插槽有区别
    • v2.5 中, 具名插槽header 仅仅作为 my-slot组件 的children节点,并且其render函数的第二个参数中有一个 slot 的属性。

其实根据上述编译后的结果,我们不妨这样猜测

  • 默认插槽直接在父组件的 render 阶段生成 vNode

    • 子组件 render 时,可能通过某种手段取得已经生成好的 插槽vNode 用作自己的 slot 节点。
    • 因为观察上述默认插槽的render函数:e("h1", [t._v("默认插槽")]),直接就是 my-slot 组件的childre节点(位于 my-slot 组件的第三个参数)。
  • 作用域插槽是在子组件 render 阶段生成 vNode

    • 因为我们观察作用域插槽 footer 的编译后结果,其不作为 my-slot 组件的 children,而是被放在了 my-slot 组件的 第二个参数 data 中的一个 scopedSlots属性里。
    • 并且,作用域插槽的 render 函数 外层的 funciton 接收了一个参数。如果在执行子组件 render 的时候调用,那完全可以拿到子组件的数据。

这里放出具体的 作用域插槽 打包后代码,大家一看就很清晰了:

{
  scopedSlots: t._u([
    {
      key: "footer", 
      // 函数接收了一个参数n    
      fn: function (n) {
        return [
          // h1 标签的 render 函数
          e("h1", [t._v("footer 具名 + 作用域插槽")]), 
          // p 标签的 render 函数,这里可以看到编译后是:n.footerInfo.text
          e("p", [t._v(t._s(n.footerInfo.text))])
        ]
      }
    }
  ])
}

三、slot实现原理

1. 断点调试

为了方便大家看调试结果,当前项目的组件结构主要是这样,有三大层:

Vue -> <app></app> -> <my-slot></my-slot>

这里笔者在运行时代码 initRender()renderSlot() 中,打上 debugger ,直接带大火看看执行流程。这里简单介绍下两个方法:

  • initRender:获取 vm.$slot 。组件初始化时执行(比如执行到 my-slot组件 时,可从vm.$slot 获取父组件中的slot vNode,也就是我们的 默认插槽)

  • renderSlot:把组件的 slot 替换成真正的 插槽vNode

接下来直接看实验截图:

1、先是进入initRender()(这里跳过初始化 大VueApp 的过程)。直接到初始化 my-slot组件 过程。【 简单解释:由于 App组件 执行 render 得到 App组件vNode ,在 patch 过程中 遇到 vue-component-my-slot 的 vNode ,又执行 my-slot组件 的 初始化流程。不是很熟悉组件化流程的朋友可以去看看笔者的Vue响应式原理~】

  • 我们不难发现,图中此时正值 my-slot组件init 阶段。

Vue.slot の原理について話して、スロットがどのように実装されているかを見てみましょう。

  • 再往下执行,我们可以得到 App组件中的 <h1>默认插槽</h1> 的vNode,赋值给 vm.$slot(这里我们记住,默认插槽的 vNode 已经得到)

Vue.slot の原理について話して、スロットがどのように実装されているかを見てみましょう。

2. 次に、renderSlot() と入力します。次に、上記のシングルステップの実行を続けると、renderSlot に到達します。現時点では、my-slot コンポーネント render ステージに入っています。最初のステップを振り返ると、この時点では デフォルト スロットの vNode があり、vm.$slot.default には

ヘッダー スロットがあります。

  • 順番に進み、まず最初にランク付けされたヘッダーの vNode をレンダリングします。図に示すように、ブレークポイントに到達し、

Vue.slot の原理について話して、スロットがどのように実装されているかを見てみましょう。

  • ヘッダー スロットのレンダリング関数の実行に直接進みます。 。デバッグ手順によると、 サブコンポーネントのレンダリング時に scopedSlots 属性 に配置されたレンダリング関数が実行されることが確認できます。
  • ##ヘッダー スロットの vNode を取得します

Vue.slot の原理について話して、スロットがどのように実装されているかを見てみましょう。

  • ##デフォルト スロット

Vue.slot の原理について話して、スロットがどのように実装されているかを見てみましょう。 続き単一ステップ、今度はデフォルト スロットの番です!図に示すように、ここの

key

は正確に 'default' です。

は上記のヘッダー スロットのようにレンダリングを実行せず、前に取得したスロット vNode を直接返していることがわかります。
  • #デフォルト スロットの vNode を取得します

Vue.slot の原理について話して、スロットがどのように実装されているかを見てみましょう。

    Scope スロット

フロントはヘッダー スロットと同じであり、スロットのレンダリングは my-slot コンポーネントで実行されます。違いを確認するために、直接レンダリングに進んでみましょう。ここで、1Vue.slot の原理について話して、スロットがどのように実装されているかを見てみましょう。function で渡されたパラメータは、サブコンポーネント

my-slot

data データであると結論付けることができます。そのため、

App を使用します。コンポーネント
  • scope スロットを介してサブコンポーネント データにアクセスできる理由##最後に、フッター スロットの vNode も返します。さて、検証プロセスは終了しました~

2. スロット実装の原則を要約します1Vue.slot の原理について話して、スロットがどのように実装されているかを見てみましょう。

実際、上記のプロセスは単なるデモンストレーション プロセスであり、実際にはそうではありません。それに囚われなければなりません。ここでは著者が実際のプロセスに基づいて結論を直接まとめています。つまり、最初に尋ねた 3 つの質問に戻らなければなりません。
  • 1. 通常スロットとスコープ スロットの vNode はどの段階で生成されますか? 親コンポーネントまたは子コンポーネントをレンダリングするとき?

デフォルトのスロット

は、

v2.5

v2.6

の記述方法に関係なく、親にあります。コンポーネント
    vNode
  • は で生成されます。

    vNodevm.$slot に存在します。子コンポーネント render がスロットに到達すると、 は親の vNode を直接取得します。名前付きスロット状況は 2 つのバージョン間で異なります。コンパイル結果によると、

  • v2.5
  • はデフォルトのスロットと同じように記述されており、親に vNode が生成されていることがわかります。コンポーネントであり、子コンポーネントによって直接使用されます

      v2.6
    • スロット レンダー はサブコンポーネント内で直接実行され、## を生成します# スロット vNode

    • スコープ スロット。バージョンに関係なく、 はサブコンポーネント でレンダリングされます。

  • このように理解するとよいでしょう。テンプレートがコンパイルされた後、それが
  • scopeSlots 属性

    に配置されたスロットである限り、テンプレートはコンパイルされません。サブコンポーネントが render を実行するまで使用されます。vNode を生成します。 2. スコープ スロット 親コンポーネントから子コンポーネントのデータにアクセスできるのはなぜですか?

  • スコープ スロット

    サブコンポーネントがレンダリングされる場合のみ、レンダリングが実行されて vNode が生成されます。さらに、スコープ スロットのレンダー関数 はパラメータを受け取り、サブコンポーネントのデータ

    を取得できます。スコープスロットはこうして形成される!したがって、親コンポーネント内の子コンポーネントのデータにアクセスできます。

3. 通常のスロットとスコープ スロットで実装に違いはありますか? #########違いがあります。

  • 通常スロットv2.5 の場合、名前付きスロットとデフォルト スロットの両方は、親コンポーネントがレンダリングするときにのみ vNode を生成します。子コンポーネントがスロットをレンダリングしたい場合は、$slot から直接取得されます。親コンポーネント インスタンスの vNode データ。
  • 通常スロットv2.6 の場合、名前付きスロットは子コンポーネントで render を実行しますが、 パラメーターを受け取りません。

  • スコープ スロット。

    v2.5 または v2.6 に関係なく、レンダリングはサブコンポーネント内でのみ実行され、パラメータ を受け取ることができます。

さて、最後に簡潔にまとめましょう。

スコープ スロットは遅延してパラメーターを受け取る必要があります。通常のスロットは遅延または直接実行できますが、パラメータは受け取りません。


最後に書いてあるように、レンガをコピーしてドキュメントに従って機能を実装することが多いので、本当に省力化できて安心です~でも、やりすぎると、あなたは、現在のものには挑戦が欠けていて退屈であると気づくでしょう。この時点で、その実装原理を詳しく調べて、

slot がどのように実装されているかを確認したいという衝動が生じます。特に スコープ スロット 。使っていると、上位コンポーネントがスコープスロットを通じてサブコンポーネントのデータを取得するのが当たり前だと思ってしまいますが、ソースコードを掘り下げて他の人がどのようにやっているのかを理解すると、突然啓発された気分になります。 ~

(学習ビデオ共有:

Web フロントエンド開発基本プログラミング ビデオ)

以上がVue.slot の原理について話して、スロットがどのように実装されているかを見てみましょう。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。