この記事では、Vue に関する辛口な情報と、あなたが知らないかもしれない Vue.slot の原理についてお話します。皆様のお役に立てれば幸いです。
日々のビジネス開発でも、基本コンポーネントのカプセル化でも、
スロット スロット
は私たちの視野に頻繁に現れると思います。これはプログラミングの実装に非常に便利です。おそらく誰もがslot
の使用法に精通しているでしょう。名前付きスロット、または スコープ スロットのさまざまな使用方法など...slot
とslot-scope
のレイヤーは実装されていますか?
わかりやすい、の Vue.slot
を 10 分で削除できます ソースコード実装分析###! ! !著者に従って、Vue (v2.6.14) のスロット
slot がどのように実装されているかを調べてください。 !この記事では主に 2 つの部分で説明します。
Vue の
slot がどのように実装されているかを明確に確認できます。行こう行こう! (学習ビデオ共有:
vue ビデオ チュートリアル )
の使用法を確認する
slot の使用法では、新しい標準の
2.6.0 を使用します (この記事では、v2.5 と
v2.6 の書き方についても説明します) ソースコード実装の違いは何ですか!)。
使用方法について詳しく知りたい場合は、公式 Web サイトにアクセスして Vue のスロットのドキュメントを詳しく読んでください。https://cn.vuejs.org/v2/ guide/components-slots.html1. デフォルトのスロット
<!-- 子组件 --> <template> <div class="wrapper"> <!-- 默认插槽 --> <div class="main"> <slot></slot> </div> </template> <!-- 父组件 --> <my-slot> <template> <h1>默认插槽</h1> </template> </my-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##親コンポーネントの
には属性 v-slot
があり、値は header
3. スコープ スロット (slot-scope)
を追加します。コードは次のとおりです。<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;"><!-- 子组件 -->
<template>
<div class="wrapper">
<!-- header 具名插槽 -->
<header class="header">
<slot name="header"></slot>
</header>
<!-- 默认插槽 -->
<div class="main">
<slot></slot>
</div>
<!-- footer 具名 + 作用域插槽 -->
<footer class="footer">
<slot name="footer" :footerInfo="footerInfo"></slot>
</footer>
</div>
</template>
<script>
export default {
name: "mySlot",
data () {
return {
footerInfo: {
text: &#39;这是 子组件 footer插槽 的作用域数据&#39;
}
}
}
}
</script>
<!-- 父组件 -->
<my-slot>
<template v-slot:header>
<h1>header 具名插槽</h1>
</template>
<template>
<h1>默认插槽</h1>
</template>
<template v-slot:footer="slotProps">
<h1>footer 具名 + 作用域插槽</h1>
<p>{{ slotProps.footerInfo.text }}</p>
</template>
</my-slot></pre><div class="contentsignin">ログイン後にコピー</div></div>
上記のコード ブロックは次のとおりです。
name=footer
属性を除き、:footerInfo="footerInfo"
属性もあります (その機能は子コンポーネント データを渡すことです)#親コンポーネントの
v-slot:footer だけでなく、代入操作
="slotProps "。テンプレートの二重括弧構文で、サブの
footerInfo ページにアクセスした後、
さて、簡単なレビューです。使用を終えた後、作成者はここで 3 つの質問をします。
通常スロットとスコープ スロットの vNode はどの段階で生成されますか? 親コンポーネントまたは子コンポーネントをレンダリングするとき?
slot
のコンパイルの違い 上記の最後のケース コードに基づいて、パッケージ化コマンドを実行して、テンプレートのコンパイル時に Vue がそれをどのように処理するかを確認します。私たちの
スロット build~ (みんなに内緒で言っておきますが、
Vue は
スコープ スロット と
通常スロット を処理します。違いはコンパイルから始まります、つまり、レンダリング関数が異なります) ここでは、v2.5
slot="header" を使用してください)、
v2.6、
v2.5 の記述と実装を確認できます。違いは~難しくありません。とにかく、見てみるために取り出してみました
上图左边是 v2.6
、右边是 v2.5
的,这里,我们集中关注:
scopedSlots
属性。使用作用域插槽的 footer
的 render函数 是放在 scopedSlots
里的,并且 函数中 还有接收一个参数
my-slot
的 children
。可以发现,默认插槽的 render函数
一直都是作为当前组件的childre节点
,放在 当前 组件render函数 的第三个参数中
关注 header
两种具名插槽写法的区别。
scopedSlots
,但是函数的参数为空,这点跟作用域插槽有区别。my-slot组件
的children节点,并且其render函数的第二个参数中有一个 slot
的属性。其实根据上述编译后的结果,我们不妨这样猜测:
默认插槽直接在父组件的 render
阶段生成 vNode
。
render
时,可能通过某种手段取得已经生成好的 插槽vNode
用作自己的 slot
节点。e("h1", [t._v("默认插槽")])
,直接就是 my-slot
组件的childre节点(位于 my-slot
组件的第三个参数)。作用域插槽是在子组件 render
阶段生成 vNode
。
footer
的编译后结果,其不作为 my-slot
组件的 children,而是被放在了 my-slot
组件的 第二个参数 data
中的一个 scopedSlots属性
里。这里放出具体的 作用域插槽 打包后代码,大家一看就很清晰了:
{ 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
实现原理为了方便大家看调试结果,当前项目的组件结构主要是这样,有三大层:
Vue
-><app></app>
-><my-slot></my-slot>
这里笔者在运行时代码 initRender()
、renderSlot()
中,打上 debugger ,直接带大火看看执行流程。这里简单介绍下两个方法:
initRender:获取 vm.$slot
。组件初始化时执行(比如执行到 my-slot组件
时,可从vm.$slot 获取父组件中的slot vNode
,也就是我们的 默认插槽)
renderSlot:把组件的 slot
替换成真正的 插槽vNode
接下来直接看实验截图:
1、先是进入initRender()
(这里跳过初始化 大Vue
、App
的过程)。直接到初始化 my-slot组件
过程。【 简单解释:由于 App组件
执行 render
得到 App组件vNode ,在 patch
过程中 遇到 vue-component-my-slot
的 vNode ,又执行 my-slot组件
的 初始化流程。不是很熟悉组件化流程的朋友可以去看看笔者的Vue响应式原理~】
my-slot组件
的 init
阶段。<h1>默认插槽</h1>
的vNode,赋值给 vm.$slot
(这里我们记住,默认插槽的 vNode 已经得到)2. 次に、renderSlot()
と入力します。次に、上記のシングルステップの実行を続けると、renderSlot
に到達します。現時点では、my-slot コンポーネント
の render
ステージに入っています。最初のステップを振り返ると、この時点では デフォルト スロットの vNode があり、vm.$slot.default には
ヘッダー スロットがあります。
scopedSlots 属性
に配置されたレンダリング関数が実行されることが確認できます。
続き単一ステップ、今度はデフォルト スロットの番です!図に示すように、ここの
keyは正確に 'default' です。
は上記のヘッダー スロットのようにレンダリングを実行せず、前に取得したスロット vNode を直接返していることがわかります。
#デフォルト スロットの vNode を取得します
フロントはヘッダー スロットと同じであり、スロットのレンダリングは my-slot コンポーネントで実行されます。違いを確認するために、直接レンダリングに進んでみましょう。ここで、function で渡されたパラメータは、サブコンポーネント
my-slotの data データであると結論付けることができます。そのため、
App を使用します。コンポーネント
##最後に、フッター スロットの vNode も返します。さて、検証プロセスは終了しました~
2. スロット実装の原則を要約します
実際、上記のプロセスは単なるデモンストレーション プロセスであり、実際にはそうではありません。それに囚われなければなりません。ここでは著者が実際のプロセスに基づいて結論を直接まとめています。つまり、最初に尋ねた 3 つの質問に戻らなければなりません。v2.5
とv2.6
の記述方法に関係なく、親にあります。コンポーネントvNode は vm.$slot に存在します。子コンポーネント
render がスロットに到達すると、
は親の vNode
を直接取得します。名前付きスロット状況は 2 つのバージョン間で異なります。コンパイル結果によると、
スロット レンダー はサブコンポーネント内で直接実行され、## を生成します# スロット vNode
。
スコープ スロット
。バージョンに関係なく、 はサブコンポーネント
でレンダリングされます。
に配置されたスロットである限り、テンプレートはコンパイルされません。サブコンポーネントが render を実行するまで使用されます。vNode を生成します。 2. スコープ スロット 親コンポーネントから子コンポーネントのデータにアクセスできるのはなぜですか?
サブコンポーネントがレンダリングされる場合のみ、レンダリングが実行されて vNode が生成されます。さらに、スコープ スロットのレンダー関数 はパラメータを受け取り、サブコンポーネントのデータ
を取得できます。スコープスロットはこうして形成される!したがって、親コンポーネント内の子コンポーネントのデータにアクセスできます。3. 通常のスロットとスコープ スロットで実装に違いはありますか? #########違いがあります。
通常スロット。 v2.6
の場合、名前付きスロットは子コンポーネントで render を実行しますが、 パラメーターを受け取りません。
v2.5 または
v2.6 に関係なく、レンダリングはサブコンポーネント内でのみ実行され、パラメータ
を受け取ることができます。
スコープ スロットは遅延してパラメーターを受け取る必要があります。通常のスロットは遅延または直接実行できますが、パラメータは受け取りません。
slot がどのように実装されているかを確認したいという衝動が生じます。特に
スコープ スロット 。使っていると、上位コンポーネントがスコープスロットを通じてサブコンポーネントのデータを取得するのが当たり前だと思ってしまいますが、ソースコードを掘り下げて他の人がどのようにやっているのかを理解すると、突然啓発された気分になります。 ~
以上がVue.slot の原理について話して、スロットがどのように実装されているかを見てみましょう。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。