vue の v-bind を理解する

vue の v-bind を理解する

1. v-bindの主要ソースコードの分析

1. v-bind属性はどこに均一に保存されるか: attrsMapとattrsList

<p v-bind:title="vBindTitle"></p>

p タグのtitle属性がv-bindあると仮定して、 vuetitle属性がどのように処理されるかを分析してみましょう。

この HTML タグを取得した後、Vue は title 属性を処理し、次の手順を実行します。

  • HTMLを解析し、属性セットattrsを解析して、 startコールバックで返します。
  • ASTElement,createASTElement(... ,attrs, ...)
  • 作成後、 ASTElement attrsListattrsMapを生成します。

作成後にv-bind:titleなどの共通属性値をどのように処理するかについては、以下の v-bind:src ソースコード解析で詳しく知ることができます。

2. HTMLを解析し、属性セットattrsを解析して、開始コールバックで返します。

 
  関数handleStartTag(一致){
    ...
    定数 l = マッチ.属性.長さ
    const attrs = 新しい配列(l)
    (i = 0; i < l; i++ とします) {
      定数args = match.attrs[i]
      ...
      属性[i] = {
        名前: 引数[1],
        値: decodeAttr(値、shouldDecodeNewlines)
      }
    }
   ...
    if (オプション.開始) {
      // ここで開始関数にアップロードします options.start(tagName, attrs, unary, match.start, match.end)
    }
  }

3. 開始コールバックで ASTElement を作成します (createASTElement(... ,attrs, ...))

// HTML の解析
parseHTML(テンプレート、{
    ...
    開始(タグ、属性、単項、開始、終了) {
        let element: ASTElement = createASTElement(tag, attrs, currentParent) // ここでの attrs に注意してください
    }
})

4. 作成後、ASTElementはattrsListとattrsMapを生成します。

// AST要素エクスポート関数createASTElement (を作成する
  タグ: 文字列、
  attrs: Array<ASTAttr>, // 属性オブジェクト配列 parent: ASTElement | void // 親要素も ASTElement です
): ASTElement { // ASTElementを返す
  戻る {
    タイプ: 1,
    タグ、
    attrsList: attrs、
    attrsMap: makeAttrsMap(attrs)、
    生の属性マップ: {},
    親、
    子供たち: []
  }
}

5. attrsのデータ型定義

//ASTAttr属性抽象構文木オブジェクトデータ型を宣言するdeclare type ASTAttr = {
  name: string; // 属性名value: any; // 属性値dynamic?: boolean; // 動的な属性かどうかstart?: number;
  終了?: 番号
};

6. バインディング属性取得関数

バインディング属性取得関数 getBindingAttr と属性操作関数 getAndRemoveAttr

getBindingAttrとそのサブ関数getAndRemoveAttrは、特定のシナリオ的v-bindを処理するのに非常に役立ちます。つまり、「 v-bindさまざまなバインディング属性を処理する方法」セクションが非常に役立ちます。 これらは、次のv-bind:keyソース コード分析、 v-bind:srcソース コード分析、 v-bind:classソース コード分析;v-bind:styleソース コード分析、 v-bind:dataset.propソース コード分析の参照用にここにリストされています。

エクスポート関数 getBindingAttr (
  el: AST要素、
  名前: 文字列、
  getStatic?: ブール値
): ?弦 {
  定数動的値 =
    getAndRemoveAttr(el, ':' + 名前) ||
    getAndRemoveAttr(el, 'v-bind:' + 名前)
  動的値 != null の場合
    parseFilters(dynamicValue) を返す
  } そうでない場合 (getStatic !== false) {
    const staticValue = getAndRemoveAttr(el, 名前)
    静的値 != null の場合 {
      JSON.stringify(staticValue) を返す
    }
  }
}

// 注意: これは配列(attrsList)から属性のみを削除するので、
// processAttrs によって処理されません。
// デフォルトではマップ(attrsMap)から削除されません。マップは
// コード生成中に必要です。
エクスポート関数 getAndRemoveAttr (
  el: AST要素、
  名前: 文字列、
  マップから削除しますか?: ブール値
): ?弦 {
  valを
  el.attrsMap[name] が null の場合
    定数リスト = el.attrsList
    (i = 0, l = list.length; i < l; i++) の場合 {
      if (リスト[i].name === name) {
        list.splice(i, 1) // attrsList から属性を削除しますが、attrsMap から break は削除されません
      }
    }
  }
  if (マップから削除) {
    el.attrsMap[名前]を削除します
  }
  戻り値
}

2. v-bindの値を取得する方法

次のコードを例にして、 vueソース コードからv-bindの値を取得する方法を分析します。

いくつかのシーンを書き出して分析してみます。

  • 共通key属性
  • 共通のhtml attribute:title
  • バインディングclassstyle
  • html DOM property:textContent
vBind:{
    キー: +新しい日付()、
    タイトル: "これは HTML 属性 v-bind です",
    クラス: "{ borderRadius: isBorderRadius }"
    スタイル: "{ minHeight: 100 + 'px' , maxHeight}"
    テキストコンテンツ: "hello vue v-bind"
}

<div
   v-bind:key="vBind.key"
   v-bind:title="vBind.title"
   v-bind:class="vBind.class"
   v-bind:style="vBind.style"
   v-bind:text-content.prop="vBind.textContent"
 />
</div>

1. v-bind:key ソースコード分析

関数 processKey (el) {
  const exp = getBindingAttr(el, 'キー')
   if(式){
      ...
      el.key = exp;
   }
}


getBindingAttr関数はprocessKey関数で使用されます。:, const dynamicValue = getAndRemoveAttr(el, 'v-bind:'+'key') ; ではなくv-bindを使用しているため、 getAndRemoveAttr(el, 'v-bind:key')関数はattrsMapにアクセスして'v-bind:key'存在するかどうかを確認し、この属性の値を val として取得してattrsListから削除しますが、 attrsMapからは削除せず、最後に'v-bind:key'の値、つまり val をdynamicValueとして使用し、解析とフィルタリングの結果を返し、最後に結果をprocessKeyの要素のkey propertyとしてset 。そして、 segmentsに格納されます。 segmentsが何であるかについては、上記のソースコードで確認できます。

2. v-bind:title ソースコード分析

titleは「非vue特殊」かつ通常のHTML attributeです。

関数 processAttrs(el){
     const リスト = el.attrsList;
     ...
     if (bindRE.test(name)) { // v-bind
        名前 = 名前.replace(bindRE, '')
        値 = parseFilters(値)
        ...
        addAttr(el, 名前, 値, リスト[i], ...)
      }
}
エクスポート const bindRE = /^:|^\.|^v-bind:/
エクスポート関数 addAttr(el: ASTElement、名前: 文字列、値: 任意、範囲?: 範囲、動的?: ブール値) {
  const attrs = 動的
    ? (el.dynamicAttrs || (el.dynamicAttrs = []))
    : (el.attrs || (el.attrs = []))
  attrs.push(rangeSetItem({ 名前、値、動的 }、範囲))
  el.plain = 偽
}

ソースコードを読むと、title などのネイティブ属性の場合、vue は最初にnamevalueを解析し、次にmodifiersがあるかどうかの一連の判断を行い ( modifier部分については後で詳しく説明します)、最後にASTElementattrs更新し、 attrsListattrsMapも同期的に更新されることがわかります。

3. v-bind:class ソースコード分析

css class 、フロントエンド開発のプレゼンテーションにおいて非常に重要なレイヤーです。 そのため、 vue class属性に対しても多くの特別な処理を実行します。

関数 transformNode (el: ASTElement, オプション: CompilerOptions) {
  const 警告 = options.warn || baseWarn
  const staticClass = getAndRemoveAttr(el, 'class')
  if (静的クラス) {
    el.staticClass = JSON.stringify(staticClass)
  }
  const classBinding = getBindingAttr(el, 'class', false /* getStatic */)
  if (クラスバインディング) {
    el.classBinding = クラスバインディング
  }
}

transfromNode関数では、静的classgetAndRemoveAttrを通じて取得されます (つまり、class="foo")。バインドされたクラスはgetBindingAttrで取得されます (つまり、 v-bind:class="vBind.class " またはv-bind:class="{ borderRadius: isBorderRadius }")。その後、バインドした属性に ASTElement の classBinding が割り当てられ、後続の使用が可能になります。

4. v-bind:style ソースコード解析

スタイルは、スタイルを直接操作するHTML attributeであり、クラスの次にmportantで、クラスよりも直感的です。 Vue はこの属性に対しても特別な処理を行います。

関数 transformNode (el: ASTElement, オプション: CompilerOptions) {
  const 警告 = options.warn || baseWarn
  const staticStyle = getAndRemoveAttr(el, 'style')
  静的スタイルの場合{
    el.staticStyle = JSON.stringify(parseStyleText(staticStyle))
  }
  const styleBinding = getBindingAttr(el, 'style', false /* getStatic */)
  if (スタイルバインディング) {
    el.styleBinding = スタイルバインディング
  }
}

transfromNode関数では、静的スタイルはgetAndRemoveAttrを通じて取得されます (つまり、 style="{fontSize: '12px' }")。バインドされたスタイルはgetBindingAttrで取得されます (つまり、 v-bind:style="vBind.style"即v-bind:class={ minHeight: 100 + 'px' , maxHeight }")。ここで、 maxHeight は変数であり、 ASTElementstyleBinding 、後で使用するためにバインドした属性に割り当てられます。

5. v-bind:text-content.prop ソースコード分析

textContentは DOM オブジェクトのネイティブ プロパティなので、prop によって識別できます。 vue を通じて DOM プロパティを直接設定したい場合は、DOM ノードに変更を加えることができます。

ソースコードを見てみましょう。

関数 processAttrs(el) {
  定数リスト = el.attrsList
  ...
  if (bindRE.test(name)) { // v-bind
      if (修飾子) {
          modifiers.prop が !isDynamic の場合 {
            名前 = キャメル化(名前)
            if (name === 'innerHtml') name = 'innerHTML'
          }
       }
       if (modifiers && modifiers.prop) {
          addProp(el, 名前, 値, リスト[i], isDynamic)
        }
   }
}
エクスポート関数 addProp (el: ASTElement、名前: 文字列、値: 文字列、範囲?: 範囲、動的?: ブール値) {
  (el.props || (el.props = [])).push(rangeSetItem({ 名前、値、動的 }、範囲))
  el.plain = 偽
}
プロパティ?: Array<ASTAttr>;

上記のソースコードから、 v-bind:text-content.proptext-contentが最初にキャメルケース化されてtextContentなっていることがわかります (これは、 DOM propertyすべてキャメルケース形式であるためです)。Vue はinnerHtml誤った記述との互換性も確保し、prop 識別子を介して textContent 属性をASTElement的propsに追加します。ここでの props は基本的に ASTAttr です。

考えてみる価値のある疑問があります。なぜこれをするのでしょうか? HTML 属性との類似点と相違点は何ですか?

  • DOMのテキストコンテンツを直接変更できるHTML attributeはないので、別途マークする必要があります。
  • これは、js を介して DOM テキスト ノードを手動で更新するよりも高速であり、DOM をクエリしてからテキスト コンテンツを置き換える手順が不要になります。
  • ラベルにどの属性がv-bindされているかがわかります。これは非常に直感的です。
  • 実際、v-bind:title はv-bind:title.attr,v-bind:text-content.prop vueが修飾子なしで HTML attributeをデフォルトにするだけです。

6. v-bind modifier.camel.sync ソースコード分析

. camelは単なる camelCase です。シンプルです。 しかし、.sync はそれほど単純ではなく、親コンポーネントのバインドされた値を更新する v-on リスナーに拡張されます。

実際、.sync 修飾子を初めて見たとき、私は戸惑いましたが、コンポーネントの .sync を注意深く読み、実際の作業と組み合わせることで、その威力がわかりました。

<親
  v-bind:foo="parent.foo"
  v-on:updateFoo="parent.foo = $event"
</親>

Vue では、親コンポーネントから子コンポーネントに渡されるprops this.props.foo = newFooを通じて子コンポーネントによって直接変更することはできません。 this.$emit("updateFoo", newFoo),親コンポーネントで v-on を使用してupdateFooイベントをリッスンしない限りは。読みやすさを向上したい場合は、 $emitの名前を update:foo に変更し、次にv-on:update:fooします。

もっと簡潔に書く方法はありますか? ? ? それがここにある .sync 演算子です。 次のように短縮できます。

<親 v-bind:foo.sync="parent.foo"></親>

次に、 this.$emit("update:foo", newFoo ); を通じて子コンポーネントでトリガーします。ここでのイベント名は update:xxx の形式にする必要があることに注意してください。これは、Vue のソース コードでは、.sync 修飾子属性を使用するとv-on:update:xxxリスナーが自動的に生成されるためです。

ソースコードを見てみましょう:

(modifiers.camel && !isDynamic)の場合{
  名前 = キャメル化(名前)
}
(modifiers.sync)の場合{
  syncGen = genAssignmentCode(値、`$event`)
  if (!isDynamic) {
    addHandler(el,`update:${camelize(name)}`,syncGen,null,false,warn,list[i]) 
   // Hyphenate はハイフネーション関数で、camelize はキャメルケース関数です。if (hyphenate(name) !== camelize(name)) {
      addHandler(el,`update:${hyphenate(name)}`,syncGen,null,false,warn,list[i])
    }
  } それ以外 {
    // 動的イベント名を持つハンドラー
    addHandler(el,`"update:"+(${name})`,syncGen,null,false,warn,list[i],true)
  }
}

ソースコードを読むと、次のことがわかります。 v-bind:foo.syncの属性については、Vue は属性が動的属性であるかどうかを判断します。 動的プロパティでない場合は、最初に camelCase リスナーを追加し、次にハイフンで区切られたリスナーを追加します。たとえば、 v-bind:foo-bar.sync 、最初にv-on:update:fooBar 、次にv-on:update:foo-bar 。 v-on リスナーはaddHandleを介して追加されます。 動的属性の場合は、キャメルケースやハイフン化は行われません。addHandler addHandler(el,update:${name}, ...),動的属性のイベントが正直にリッスンされます。

sync一文で要約すると、 sync v-bind と v-on をv-bind.syncthis.$emit('update:xxx' ) に簡略化する構文糖です。子コンポーネントが親コンポーネントのデータをすばやく更新する方法を提供します。

これで、vue の v-bind を理解するためのこの記事は終わりです。vue の v-bind に関するより関連性の高いコンテンツについては、123WORDPRESS.COM で以前の記事を検索するか、次の関連記事を引き続き参照してください。今後も 123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • vue ディレクティブ v-bind の使用と注意点
  • Vue の動的属性データバインディング (v-bind 命令) を 1 つの記事で理解する
  • Vue の v-bind:style 効果のカスタム命令の詳細な説明
  • Vue v-bind 動的バインディングクラスインスタンスメソッド
  • Vue の基本: v-bind 属性、クラス、スタイルの使用状況分析
  • Vueでは、v-bindは三項演算子を使用してクラスインスタンスをバインドします。
  • vue で v-bind:class を使用するタブメソッド
  • VueJs の V-bind ディレクティブの詳細な説明
  • VUE における v-bind の基本的な使い方の詳細な説明
  • Vue.js での v-bind ディレクティブの使用方法の紹介

<<:  Tomcat をサービスとして登録する際に注意すべき点のまとめ

>>:  Linux でファイルを削除するさまざまな方法の効率の比較

推薦する

3つの主要データベース(Mysql、SqlServer、Oracle)の違いについて簡単に説明します。

マイグレーションアドバンテージ:小型、高速、総所有コストが低い、オープンソース。複数のオペレーティン...

WeChatミニプログラムビデオ集中砲火位置ランダム

この記事では、WeChatミニプログラムのビデオ弾幕の位置をランダム化するための具体的なコードを紹介...

jQueryアニメーションを理解するのに役立つ記事

目次1. 要素の表示と非表示を制御する show() hide() 2. 要素の透明度を制御する f...

CSS3 カテゴリメニュー効果

CSS3 カテゴリ メニューの効果は次のとおりです。 html <html> <ヘ...

ドラッグ位置プレビューを実装するネイティブJS

この記事では、要素をドラッグするときにプレビューを追加する小さなデモを紹介します。効果は次のとおりで...

mysql 基本操作文コマンドの詳細な説明

1. MySQLに接続するフォーマット: mysql -h ホストアドレス -u ユーザー名 -p ...

HTML 基本ノート (推奨)

1. ウェブページの基本構造: XML/HTML コードコンテンツをクリップボードにコピー<...

shtml includeの使い方

これを応用することで、ウェブサイトの一部の公開領域を独立したページにすることができ、その後、この技術...

Linux入力サブシステムフレームワーク原理の分析

入力サブシステムフレームワークLinux 入力サブシステムは、上から下に向かって、入力サブシステム ...

WeChatアプレットの世界的な状況の詳細な説明

序文WeChat アプレットでは、App.js の globalData を中間ブリッジとして使用し...

Centos ベースイメージの作成方法

序文現在、私の会社で使用しているオペレーティングシステムはすべて CentOS7.4 で、アプリケー...

Angularコンポーネント投影の詳細な説明

目次概要1. 簡単な例1.サブコンポーネントの<ng-content>ディレクティブを使...

MySQLでカーソルを宣言する方法

MySQL でカーソルを宣言する方法: 1. 変数とカーソルを宣言する 結果をvarchar(300...

Vueはフォーム検証機能を実装します

この記事では主に、NUXT の validate メソッドに基づいてフォーム検証を実装する方法につい...

Dockerの国内イメージソースを変更する方法

Dockerデーモンのアクセラレータを構成する設定ファイルから Docker を起動し、/etc/d...