Vue でのスロット/スコープの使用の詳細な説明
今回は、Vue でのスロット/スコープの使用について詳しく説明します。Vue でスロット/スコープを使用する際の 注意事項 について、実際のケースを見てみましょう。
以下は、スロットの動作原理を簡単に説明するための例です
dx-li サブコンポーネントのテンプレートは次のとおりです:<li class="dx-li"> <slot> 你好! </slot> </li> dx-ul父组件的template如下: <ul> <dx-li> hello juejin! </dx-li> </ul> 结合上述例子以及vue中相关源码进行分析 dx-ul父组件中template编译后,生成的组件render函数: module.exports={ render:function (){ var _vm=this; var _h=_vm.$createElement; var _c=_vm._self._c||_h; // 其中_vm.v为createTextVNode创建文本VNode的函数 return _c('ul', [_c('dx-li', [_vm._v("hello juejin!")])], 1) }, staticRenderFns: [] }
module.exports={ render:function (){ var _vm=this; var _h=_vm.$createElement; var _c=_vm._self._c||_h; // 其中_vm._v 函数为renderSlot函数 return _c('li', {staticClass: "dx-li" }, [_vm._t("default", [_vm._v("你好 掘金!")])], 2 ) }, staticRenderFns: [] }
function initRender (vm) { ... // 其中_renderChildren数组,存储为 'hello juejin!'的VNode节点;renderContext一般为父组件Vue实例 这里为dx-ul组件实例 vm.$slots = resolveSlots(options._renderChildren, renderContext); ... }
/** * 主要作用是将children VNodes转化成一个slots对象. */ export function resolveSlots ( children: ?Array<VNode>, context: ?Component ): { [key: string]: Array<VNode> } { const slots = {} // 判断是否有children,即是否有插槽VNode if (!children) { return slots } // 遍历父组件节点的孩子节点 for (let i = 0, l = children.length; i < l; i++) { const child = children[i] // data为VNodeData,保存父组件传递到子组件的props以及attrs等 const data = child.data /* 移除slot属性 * <span slot="abc"></span> * 编译成span的VNode节点data = {attrs:{slot: "abc"}, slot: "abc"},所以这里删除该节点attrs的slot */ if (data && data.attrs && data.attrs.slot) { delete data.attrs.slot } /* 判断是否为具名插槽,如果为具名插槽,还需要子组件/函数子组件渲染上下文一致。主要作用: *当需要向子组件的子组件传递具名插槽时,不会保持插槽的名字。 * 举个栗子: * child组件template: * <p> * <p class="default"><slot></slot></p> * <p class="named"><slot name="foo"></slot></p> * </p> * parent组件template: * <child><slot name="foo"></slot></child> * main组件template: * <parent><span slot="foo">foo</span></parent> * 此时main渲染的结果: * <p> * <p class="default"><span slot="foo">foo</span></p> <p class="named"></p> * </p> */ if ((child.context === context || child.fnContext === context) && data && data.slot != null ) { const name = data.slot const slot = (slots[name] || (slots[name] = [])) // 这里处理父组件采用template形式的插槽 if (child.tag === 'template') { slot.push.apply(slot, child.children || []) } else { slot.push(child) } } else { // 返回匿名default插槽VNode数组 (slots.default || (slots.default = [])).push(child) } } // 忽略仅仅包含whitespace的插槽 for (const name in slots) { if (slots[name].every(isWhitespace)) { delete slots[name] } } return slots }
export function renderSlot ( name: string, // 子组件中slot的name,匿名default fallback: ?Array<VNode>, // 子组件插槽中默认内容VNode数组,如果没有插槽内容,则显示该内容 props: ?Object, // 子组件传递到插槽的props bindObject: ?Object // 针对<slot v-bind="obj"></slot> obj必须是一个对象 ): ?Array<VNode> { // 判断父组件是否传递作用域插槽 const scopedSlotFn = this.$scopedSlots[name] let nodes if (scopedSlotFn) { // scoped slot props = props || {} if (bindObject) { if (process.env.NODE_ENV !== 'production' && !isObject(bindObject)) { warn( 'slot v-bind without argument expects an Object', this ) } props = extend(extend({}, bindObject), props) } // 传入props生成相应的VNode nodes = scopedSlotFn(props) || fallback } else { // 如果父组件没有传递作用域插槽 const slotNodes = this.$slots[name] // warn duplicate slot usage if (slotNodes) { if (process.env.NODE_ENV !== 'production' && slotNodes._rendered) { warn( `Duplicate presence of slot "${name}" found in the same render tree ` + `- this will likely cause render errors.`, this ) } // 设置父组件传递插槽的VNode._rendered,用于后面判断是否有重名slot slotNodes._rendered = true } // 如果没有传入插槽,则为默认插槽内容VNode nodes = slotNodes || fallback } // 如果还需要向子组件的子组件传递slot /*举个栗子: * Bar组件: <p class="bar"><slot name="foo"/></p> * Foo组件:<p class="foo"><bar><slot slot="foo"/></bar></p> * main组件:<p><foo>hello</foo></p> * 最终渲染:<p class="foo"><p class="bar">hello</p></p> */ const target = props && props.slot if (target) { return this.$createElement('template', { slot: target }, nodes) } else { return nodes } }
<li class="dx-li"> <slot str="你好 掘金!"> hello juejin! </slot> </li> dx-ul父组件的template如下: <ul> <dx-li> <span slot-scope="scope"> {{scope.str}} </span> </dx-li> </ul> 结合例子和Vue源码简单作用域插槽 dx-ul父组件中template编译后,产生组件render函数: module.exports={ render:function (){ var _vm=this; var _h=_vm.$createElement; var _c=_vm._self._c||_h; return _c('ul', [_c('dx-li', { // 可以编译生成一个对象数组 scopedSlots: _vm._u([{ key: "default", fn: function(scope) { return _c('span', {}, [_vm._v(_vm._s(scope.str))] ) } }]) })], 1) }, staticRenderFns: [] }
function resolveScopedSlots ( fns, // 为一个对象数组,见上文scopedSlots res ) { res = res || {}; for (var i = 0; i < fns.length; i++) { if (Array.isArray(fns[i])) { // 递归调用 resolveScopedSlots(fns[i], res); } else { res[fns[i].key] = fns[i].fn; } } return res }
概要
実際、スロット/スコープ付きスロットの原理は非常に単純で、vue がコンポーネントをレンダリングするときに、VNode に基づいて実際の DOM 要素がレンダリングされることを理解するだけで済みます。 スロットは、親コンポーネントをコンパイルすることによって生成されるスロット VNode であり、サブコンポーネントをレンダリングするときに、対応するサブコンポーネント レンダリング VNode ツリーに配置されます。 スコープ付きスロットは、親コンポーネントのスロットの内容を関数にコンパイルし、サブコンポーネントをレンダリングするときに、サブコンポーネントの props を渡し、対応する VNode を生成します。最後に、サブコンポーネントはコンポーネントのレンダリング関数に従って VNode ノード ツリーを返し、更新して実際の DOM 要素をレンダリングします。同時に、コンポーネント間でスロットを渡すことも可能ですが、名前付きスロットを渡す場合は注意が必要であることがわかります。 この記事の事例を読んだ後は、この方法を習得したと思います。さらに興味深い情報については、php 中国語 Web サイトの他の関連記事に注目してください。 推奨読書: vueコンポーネントでのスロットソケットの使用方法の詳細な説明
以上がVue でのスロット/スコープの使用の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











C++ のモード関数の詳細な説明 統計において、モードとは、一連のデータ内で最も頻繁に現れる値を指します。 C++ 言語では、モード関数を記述することによって、任意のデータセット内のモードを見つけることができます。モード関数はさまざまな方法で実装できます。一般的に使用される 2 つの方法を以下で詳しく紹介します。 1 つ目の方法は、ハッシュ テーブルを使用して各数値の出現回数をカウントすることです。まず、各数値をキー、出現回数を値とするハッシュ テーブルを定義する必要があります。次に、特定のデータセットに対して次を実行します。

Windows オペレーティング システムは世界で最も人気のあるオペレーティング システムの 1 つであり、その新バージョン Win11 が大きな注目を集めています。 Win11 システムでは、管理者権限の取得は重要な操作であり、管理者権限を取得すると、ユーザーはシステム上でより多くの操作や設定を実行できるようになります。この記事では、Win11システムで管理者権限を取得する方法と、権限を効果的に管理する方法を詳しく紹介します。 Win11 システムでは、管理者権限はローカル管理者とドメイン管理者の 2 種類に分かれています。ローカル管理者はローカル コンピュータに対する完全な管理権限を持っています

OracleSQL の除算演算の詳細な説明 OracleSQL では、除算演算は一般的かつ重要な数学演算であり、2 つの数値を除算した結果を計算するために使用されます。除算はデータベース問合せでよく使用されるため、OracleSQL での除算演算とその使用法を理解することは、データベース開発者にとって重要なスキルの 1 つです。この記事では、OracleSQL の除算演算に関する関連知識を詳細に説明し、読者の参考となる具体的なコード例を示します。 1. OracleSQL での除算演算

Vue.nextTick 関数の使い方と非同期更新での応用について詳しく説明 Vue の開発では、DOM を変更した直後にデータを更新したり、関連する操作が必要になったりするなど、データを非同期で更新する必要がある状況によく遭遇します。データが更新された直後に実行されます。このような問題を解決するために登場したのが、Vue が提供する .nextTick 関数です。この記事では、Vue.nextTick 関数の使用法を詳しく紹介し、コード例と組み合わせて、非同期更新でのアプリケーションを説明します。 1.Vue.nex

C++ の剰余関数の詳しい説明 C++ では、剰余演算子 (%) を使用して、2 つの数値を除算した余りを計算します。これは、オペランドが任意の整数型 (char、short、int、long など) または浮動小数点数型 (float、double など) になる二項演算子です。剰余演算子は、被除数と同じ符号の結果を返します。たとえば、整数の剰余演算の場合、次のコードを使用して実装できます。

PHP-FPM は、PHP のパフォーマンスと安定性を向上させるために一般的に使用される PHP プロセス マネージャーです。ただし、高負荷環境では、PHP-FPM のデフォルト設定ではニーズを満たせない場合があるため、チューニングが必要です。この記事では、PHP-FPM のチューニング方法を詳しく紹介し、いくつかのコード例を示します。 1. プロセスの数を増やす デフォルトでは、PHP-FPM はリクエストを処理するために少数のプロセスのみを開始します。高負荷環境では、プロセス数を増やすことで PHP-FPM の同時実行性を高めることができます。

Linux システム コール system() 関数の詳細説明 システム コールは、Linux オペレーティング システムの非常に重要な部分であり、システム カーネルと対話する方法を提供します。その中でも、system()関数はよく使われるシステムコール関数の一つです。この記事では、system() 関数の使用法を詳しく紹介し、対応するコード例を示します。システム コールの基本概念 システム コールは、ユーザー プログラムがオペレーティング システム カーネルと対話する方法です。ユーザープログラムはシステムコール関数を呼び出してオペレーティングシステムを要求します。

PHP のモジュロ演算子 (%) は、2 つの数値を除算した余りを取得するために使用されます。この記事では、モジュロ演算子の役割と使用法について詳しく説明し、読者の理解を深めるために具体的なコード例を示します。 1. モジュロ演算子の役割 数学では、整数を別の整数で割ると、商と余りが得られます。たとえば、10 を 3 で割ると、商は 3 になり、余りは 1 になります。モジュロ演算子は、この剰余を取得するために使用されます。 2. モジュロ演算子の使用法 PHP では、% 記号を使用してモジュロを表します。
