1. 基本Vue では、ほとんどの場合、テンプレートを使用して HTML を作成することを推奨しています。ただし、シナリオによっては、JavaScript の完全なプログラミング能力が本当に必要になる場合があります。この時点では、テンプレートよりもコンパイラに近いレンダリング関数を使用することができます。 レンダリング関数が役立つ簡単な例を見てみましょう。アンカー付きの見出しをいくつか生成したいとします。 <h1> <a name="hello-world" href="#hello-world" rel="外部 nofollow" > こんにちは世界! </a> </h1> 上記の HTML では、コンポーネント インターフェイスを次のように定義することにしました。 <anchored-heading :level="1">こんにちは世界!</anchored-heading>
<script type="text/x-template" id="アンカー付き見出しテンプレート"> <h1 v-if="レベル === 1"> <スロット></スロット> </h1> <h2 v-else-if="レベル === 2"> <スロット></スロット> </h2> <h3 v-else-if="レベル === 3"> <スロット></スロット> </h3> <h4 v-else-if="レベル === 4"> <スロット></スロット> </h4> <h5 v-else-if="レベル === 5"> <スロット></スロット> </h5> <h6 v-else-if="レベル === 6"> <スロット></スロット> </h6> </スクリプト> Vue.component('アンカー付き見出し', { テンプレート: '#anchored-heading-template', 小道具: { レベル: タイプ: 数値、 必須: true } } }) ここでテンプレートを使用することは最善の選択ではありません。コードが長くなるだけでなく、 テンプレートはほとんどのコンポーネントでうまく機能しますが、ここでは明らかに適切ではありません。それでは、 Vue.component('アンカー付き見出し', { レンダリング: 関数 (createElement) { 要素の作成を返す( 'h' + this.level, // タグ名 this.$slots.default // 子ノード配列) }, 小道具: { レベル: タイプ: 数値、 必須: true } } }) 見た目がずっとシンプルになりました!これによりコードが大幅に簡素化されますが、Vue のインスタンス 2. ノード、ツリー、仮想DOMレンダリング関数の詳細に入る前に、ブラウザの仕組みについて少し理解しておくことが重要です。次の HTML を例に挙げます。 <div> <h1>私のタイトル</h1> テキストコンテンツ <!-- TODO: タグラインを追加 --> </div> ブラウザがこのコードを読み取ると、家族の成長を追跡するために家系図を描くのと同じように、すべてを追跡するための「DOM ノード」のツリーを構築します。 上記の HTML に対応する DOM ノード ツリーを以下に示します。 各要素はノードです。テキストの各段落もノードです。コメントもノードです。ノードはページのセクションです。家系図と同じように、各ノードには子ノードが存在する可能性があります (つまり、各部分に他の部分を含めることができます)。 これらすべてのノードを効率的に更新するのは難しい場合がありますが、幸いなことに手動で行う必要はありません。 Vue にページ上の HTML をどのようにしたいかを伝えるだけで、テンプレートで指定できます。 <h1>{{ ブログタイトル }}</h1> またはレンダリング関数では: レンダリング: 関数 (createElement) { createElement('h1', this.blogTitle) を返します } どちらの場合も、blogTitle が変更されても、Vue は自動的にページを更新し続けます。 1. 仮想DOMVue は、実際の DOM がどのように変更されるかを追跡するために仮想 DOM を作成します。次のコード行をよく見てください: createElement('h1', this.blogTitle) を返します
3. createElementパラメータ次に知っておく必要があるのは、 // @returns {VNode} 要素を作成します( // {文字列 | オブジェクト | 関数} // HTML タグ名、コンポーネント オプション オブジェクト、または // 上記のいずれかに解決される非同期関数。必須フィールドです。 'div', // {物体} // テンプレート内の属性に対応するデータ オブジェクト。オプション。 { // (詳細は次のセクションを参照) }, // {文字列 | 配列} // `createElement()` によって構築された子仮想ノード (VNode)、 // 文字列を使用して「テキスト仮想ノード」を生成することもできます。オプション。 [ 「まずはテキストを書いてください」 createElement('h1', '見出し'), 要素を作成します(MyComponent, { 小道具: { いくつかのプロパティ: 'foobar' } }) ] ) 1. データオブジェクトを詳しく調べる注意すべき点が 1 つあります。v { // `v-bind:class` と同じ API、 // 文字列、オブジェクト、または文字列とオブジェクトの配列を受け入れます 'class': { foo: 真、 バー: 偽 }, // `v-bind:style` と同じ API、 // 文字列、オブジェクト、またはオブジェクトの配列を受け入れます style: { 色: '赤'、 フォントサイズ: '14px' }, // 通常の HTML 属性 属性: { id: 'foo' }, // コンポーネントプロパティ 小道具: { myProp: 'バー' }, // DOMプロパティ domProps: { 内部HTML: 'baz' }, // イベントリスナーは`on`内にあります。 // ただし、`v-on:keyup.enter` のような修飾子はサポートされなくなりました。 // 処理関数で keyCode を手動で確認する必要があります。 の上: { クリック: this.clickHandler }, // コンポーネント内で `vm.$emit` によってトリガーされるイベントではなく、ネイティブ イベントをリッスンするコンポーネントにのみ使用されます。 ネイティブオン: { クリック: this.nativeClickHandler }, // カスタムディレクティブ。 `binding` では `oldValue` を使用できないことに注意してください。 // 割り当て。Vue によって自動的に同期されるためです。 ディレクティブ: [ { 名前: 'my-custom-directive', 値: '2'、 式: '1 + 1'、 引数: 'foo', 修飾子: バー: 真 } } ]、 // スコープ付きスロットの形式は // { name: props => VNode | Array<VNode> } です スコープスロット: { デフォルト: props => createElement('span', props.text) }, // コンポーネントが別のコンポーネントのサブコンポーネントである場合、スロットの名前を指定する必要があります slot: 'name-of-slot'、 // その他の特別なトップレベルプロパティ キー: 'myKey', 参照: 'myRef', // レンダリング関数で複数の要素に同じ参照名を適用すると、 // すると `$refs.myRef` は配列になります。 参照先: true } 2. 完全な例この知識があれば、最初に実装したかったコンポーネントを完成させることができます。 var getChildrenTextContent = 関数 (children) { 戻り値 children.map(function (node) { ノードの子を返す ? 子のテキストコンテンツを取得します(node.children) : ノード.テキスト })。参加する('') } Vue.component('アンカー付き見出し', { レンダリング: 関数 (createElement) { // ケバブケースIDを作成する var 見出しId = getChildrenTextContent(this.$slots.default) .toLowerCase() .replace(/\W+/g, '-') .replace(/(^-|-$)/g, '') 要素の作成を返す( 'h' + このレベル、 [ 要素を作成します('a', { 属性: { 名前: 見出しID、 href: '#' + 見出しID } }, this.$slots.default) ] ) }, 小道具: { レベル: タイプ: 数値、 必須: true } } }) 3. 制約VNode は一意である必要があります コンポーネント ツリー内のすべての VNode は一意である必要があります。つまり、次のレンダリング関数は不正です。 レンダリング: 関数 (createElement) { var myParagraphVNode = createElement('p', 'hi') createElement('div', [ を返します。 // エラー - VNode が重複しています myParagraphVNode、myParagraphVNode ]) } 要素/コンポーネントを何度も繰り返す必要がある場合は、ファクトリ関数を使用してそれを実行できます。たとえば、次のレンダリング関数は、20 個の同一の段落を完全に合法的な方法でレンダリングします。 レンダリング: 関数 (createElement) { createElement('div', を返します。 Array.apply(null, { 長さ: 20 }).map(関数 () { createElement('p', 'hi') を返します }) ) } 4. JavaScriptを使用してテンプレート関数を置き換える1. v-if と v-forネイティブ JavaScript で簡単に実行できる限り、Vue のレンダリング関数は独自の代替手段を提供しません。たとえば、テンプレートで使用される <ul v-if="アイテムの長さ"> <li v-for="item in items">{{ item.name }}</li> </ul> <p v-else>アイテムが見つかりません。</p> これらはすべて、 プロパティ: ['アイテム'], レンダリング: 関数 (createElement) { if (this.items.length) { createElement('ul', this.items.map(function (item) { を返します。 createElement('li', item.name) を返します。 })) } それ以外 { return createElement('p', 'アイテムが見つかりません。') } } 2. Vモデルレンダリング関数には プロパティ: ['値'], レンダリング: 関数 (createElement) { var 自己 = これ createElement('input', を返す) domProps: { 値: 自己.値 }, の上: { 入力: 関数 (イベント) { self.$emit('input', イベントターゲット値) } } }) } これは低レベル化に伴う代償ですが、v-model よりもインタラクションの詳細をより細かく制御できます。 3. イベントとキー修飾子
例えば: の上: { '!click': this.doThisInCapturingMode、 '~keyup': this.doThisOnce、 '~!マウスオーバー': this.doThisOnceInCapturingMode } 他のすべての修飾子の場合、イベント ハンドラー内からイベント メソッドを使用できるため、プライベート プレフィックスは必要ありません。
すべての修飾子を使用した例を次に示します。 の上: { keyup: 関数 (イベント) { // イベントをトリガーする要素がイベントがバインドされている要素でない場合は、 // 戻ります if (event.target !== event.currentTarget) 戻ります // Enter キーが押されなかった場合、または // Shift キーが同時に押されなかった場合 // 戻ります if (!event.shiftKey || event.keyCode !== 13) 戻ります // イベントのバブリングを停止する event.stopPropagation() // 要素のデフォルトのキーアップイベントを防止します。event.preventDefault() // ... } } 4. スロット静的スロットの内容には レンダリング: 関数 (createElement) { // `<div><スロット></スロット></div>` createElement('div', this.$slots.default) を返します }
プロパティ: ['メッセージ'], レンダリング: 関数 (createElement) { // `<div><スロット:text="メッセージ"></スロット></div>` createElement('div', [ を返します。 this.$scopedSlots.default({ テキスト: this.message }) ]) } レンダリング関数を使用してスコープ スロットを子コンポーネントに渡す場合は、VNode データ オブジェクトの レンダリング: 関数 (createElement) { // `<div><child v-slot="props"><span>{{ props.text }}</span></child></div>` createElement('div', [ を返します。 要素を作成します('child', { // データオブジェクトに `scopedSlots` を渡す // 形式は { name: props => VNode | Array<VNode> } です スコープスロット: { デフォルト: 関数 (props) { createElement('span', props.text) を返します。 } } }) ]) } 5. JSX 要素を作成します( 'アンカー見出し'、{ 小道具: { レベル: 1 } }, [ createElement('span', 'こんにちは')、 ' 世界!' ] ) 特に、対応するテンプレートが非常に単純な場合: <アンカー見出し:level="1"> こんにちは世界! </アンカー見出し> そのため、Vue で JSX 構文を使用するための Babel プラグインがあり、これによりテンプレートに近い構文に戻ることができます。 './AnchoredHeading.vue' から AnchoredHeading をインポートします。 新しいVue({ el: '#demo', レンダリング: 関数 (h) { 戻る ( <アンカー見出しレベル={1}> こんにちは世界! </アンカーされた見出し> ) } })
6. 機能コンポーネント先ほど作成したアンカー タイトル コンポーネントは比較的単純です。状態を管理せず、渡された状態をリッスンせず、ライフサイクル メソッドもありません。実際には、これはいくつかのプロパティを受け入れる単なる関数です。このようなシナリオでは、コンポーネントを機能的としてマークできます。これは、コンポーネントがステートレス (リアクティブ データなし) であり、インスタンスがない (this コンテキストがない) ことを意味します。機能コンポーネントは次のようになります。 Vue.component('my-component', { 機能的: 真、 // Propsはオプションです props: { // ... }, // インスタンスの不足を補うために // コンテキストレンダリングとして2番目の引数を提供します: function (createElement, context) { // ... } })
バージョン 2.5.0 以降では、単一ファイル コンポーネントを使用する場合、テンプレート ベースの機能コンポーネントは次のように宣言できます。 <テンプレート機能> </テンプレート> コンポーネントに必要なものはすべて、次のフィールドを持つオブジェクトである
関数コンポーネントは単なる関数であるため、レンダリングのオーバーヘッドは大幅に低くなります。 ラッパーコンポーネントとしても非常に便利です。たとえば、次の操作を行う必要がある場合:
以下は、渡されたプロパティの値に基づいて、より具体的なコンポーネントをレンダリングできる var 空のリスト = { /* ... */ } var テーブルリスト = { /* ... */ } var OrderedList = { /* ... */ } var 順序なしリスト = { /* ... */ } Vue.component('スマートリスト', { 機能的: 真、 小道具: { アイテム: { タイプ: 配列、 必須: true }, isOrdered: ブール値 }, レンダリング: 関数 (createElement, コンテキスト) { 関数適切なリストコンポーネント(){ var アイテム = context.props.items if (items.length === 0) 空のリストを返す if (typeof items[0] === 'object') は TableList を返します if (context.props.isOrdered) は OrderedList を返します。 順序なしリストを返す } 要素の作成を返す( 適切なリストコンポーネント()、 コンテキスト.データ、 コンテキスト.子供 ) } }) 1. 属性とイベントを子要素または子コンポーネントに渡す通常のコンポーネントでは、props として定義されていない属性はコンポーネントのルート要素に自動的に追加され、同じ名前の既存の属性が置き換えられるか、インテリジェントにマージされます。 ただし、機能コンポーネントでは、この動作を明示的に定義する必要があります。 Vue.component('my- functional-button', { 機能的: 真、 レンダリング: 関数 (createElement, コンテキスト) { // 属性、イベント リスナー、子ノードなどを完全に透過的に送信します。 createElement('button', context.data, context.children) を返します。 } }) context.data を テンプレートベースの機能コンポーネントを使用する場合は、属性とリスナーも手動で追加する必要があります。独自のコンテキストにアクセスできるため、 data.attrs を使用して任意の <テンプレート機能> <ボタン クラス="btn btn-primary" v-bind="data.attrs" v-on="リスナー" > <スロット/> </ボタン> </テンプレート> 2. slots() と children の比較なぜ <私の機能コンポーネント> <p v-スロット:foo> 初め </p> <p>2番目</p> </my-function-component> 関数コンポーネント このコンポーネントの場合、 children は 2 つの段落タグを提供しますが、 7. テンプレートのコンパイルVue テンプレートは実際にはレンダリング関数にコンパイルされることを知っておくと興味深いかもしれません。これは実装の詳細であり、通常は問題になりません。しかし、テンプレートの機能がどのようにコンパイルされるかを確認したい場合は、非常に興味深いと思うかもしれません。以下は、Vue.compile を使用してテンプレート文字列をオンザフライでコンパイルする簡単な例です。 <div> <ヘッダー> <h1>私はテンプレートです!</h1> </ヘッダー> <p v-if="メッセージ">{{ メッセージ }}</p> <p v-else>メッセージはありません。</p> </div> 与える: 関数匿名( ){ with(this){return _c('div',[_m(0),(message)?_c('p',[_v(_s(message))]):_c('p',[_v("メッセージがありません。"))])])} } 静的レンダリング関数: _m(0): 関数匿名( ){ with(this){return _c('header',[_c('h1',[_v("私はテンプレートです!")])])} } レンダリング関数と JSX の詳細に関するこの記事はこれで終わりです。レンダリング関数と JSX に関するより関連性の高いコンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
目次ループ - for forループの基本的な使い方ループを終了するネストされたループ配列配列とは何...
Discuz! フォーラムにはバックグラウンドで多くの設定オプションがあり、これらの設定オプションを...
目次1. データベース設計2. フロントエンドページ3. 完全なデモフロントエンド開発では、カスケー...
概要: MySQL は、トランザクションをサポートするためにさまざまなストレージ エンジンを提供しま...
仮想メモリとは何ですか?まずはWikipediaからの紹介文をそのまま引用します。仮想メモリは、コン...
今日は新しいCSS特殊効果、波型ウォーターボール効果を学びました。これもとても美しいです HTML:...
CSS 組み合わせセレクターには、単純なセレクターのさまざまな組み合わせが含まれます。 CSS3 に...
1.Mysqlスクリプトのワンクリックインストール [root@uat01 ~]# cat Inst...
1. Concat関数。よく使用される接続文字列: concat 関数。たとえば、SQLクエリ条件...
境界プロパティの概要borderプロパティは要素の境界を設定します。境界線の3要素は、太さ、線の種類...
Web ページの外観はレイアウトに大きく左右されます。ページ内に長い段落のテキストがある場合、通常は...
Vue を使用してプロジェクトを開発する過程で、次のような問題によく遭遇します。Vue のデータでオ...
Web ページの読み込み速度は、Web サイトの品質を評価するための重要な指標です。その理由は、ほと...
重複キーの置換と挿入の違い置換の使用法競合がない場合、挿入と同等となり、他の列のデフォルト値が使用さ...
1. HTMLとは何かHTML (ハイパーテキスト マークアップ言語): ハイパーテキスト マーク...