ホームページ >ウェブフロントエンド >Vue.js >Vue の優先度の比較: v-for が v-if よりも高い理由

Vue の優先度の比較: v-for が v-if よりも高い理由

青灯夜游
青灯夜游転載
2023-03-14 19:44:191673ブラウズ

vue v-for の優先順位が v-if よりも高いのはなぜですか?次の記事では、ソースコードを分析しながらこの疑問に答えますので、皆さんのお役に立てれば幸いです。

Vue の優先度の比較: v-for が v-if よりも高い理由

一部のインタビューでは、v-forv-if のどちらの優先順位が高いかをよく尋ねます。ここでは、ソースコードを分析してこの質問に答えてください。

以下の内容は「When we talk about v-model, what are we speech about?」に基づいて分析されているため、以下の内容を読む前にこの記事を読んでください。

引き続きコンパイルを開始します

次の例から始めましょう:

new Vue({
    el:'#app',
    template:`
        <ul>
            <li v-for="(item,index) in items" v-if="index!==0">
                {{item}}
            </li>
        </ul>
    `
})

前の記事からわかるように、3 つのステップがあります。コンパイルへ

  • parse: テンプレート文字列を解析してAST構文ツリーを生成します。
  • optimize: 主にマーキングを行い、構文ツリーを最適化します。ページ更新の効率を向上させる静的ノード パフォーマンス [関連する推奨事項: vuejs ビデオ チュートリアルWeb フロントエンド開発]
  • codegen : js コードを生成します。主に render 関数と staticRenderFns 関数を使用します。

これら 3 つの手順を再度実行して、上記の例を分析してみましょう。

parse

parseこのプロセスでは、テンプレートを解析するために多数の正規表現が使用されます。冒頭の例は、attrsMap のレコードに加えて、

v-for

ディレクティブの <pre class="brush:js;toolbar:false;">// 其实ast有很多属性,我这里只展示涉及到分析的属性 ast = { &amp;#39;type&amp;#39;: 1, &amp;#39;tag&amp;#39;: &amp;#39;ul&amp;#39;, &amp;#39;attrsList&amp;#39;: [], attrsMap: {}, &amp;#39;children&amp;#39;: [{ &amp;#39;type&amp;#39;: 1, &amp;#39;tag&amp;#39;: &amp;#39;li&amp;#39;, &amp;#39;attrsList&amp;#39;: [], &amp;#39;attrsMap&amp;#39;: { &amp;#39;v-for&amp;#39;: &amp;#39;(item,index) in data&amp;#39;, &amp;#39;v-if&amp;#39;: &amp;#39;index!==0&amp;#39; }, // v-if解析出来的属性 &amp;#39;if&amp;#39;: &amp;#39;index!==0&amp;#39;, &amp;#39;ifConditions&amp;#39;: [{ &amp;#39;exp&amp;#39;: &amp;#39;index!==0&amp;#39;, &amp;#39;block&amp;#39;: // 指向el自身 }], // v-for解析出来的属性 &amp;#39;for&amp;#39;: &amp;#39;items&amp;#39;, &amp;#39;alias&amp;#39;: &amp;#39;item&amp;#39;, &amp;#39;iterator1&amp;#39;: &amp;#39;index&amp;#39;, &amp;#39;parent&amp;#39;: // 指向其父节点 &amp;#39;children&amp;#39;: [ &amp;#39;type&amp;#39;: 2, &amp;#39;expression&amp;#39;: &amp;#39;_s(item)&amp;#39; &amp;#39;text&amp;#39;: &amp;#39;{{item}}&amp;#39;, &amp;#39;tokens&amp;#39;: [ {&amp;#39;@binding&amp;#39;:&amp;#39;item&amp;#39;}, ] ] }] }</pre> という AST ノードに解析されます。および attrsList は、for (トラバースするオブジェクトまたは配列に対応)、aliasiterator1 も追加します。 iterator2 に対応 v-for 命令バインディング コンテンツの 1 番目、2 番目、および 3 番目のパラメータ 最初の例には 3 番目のパラメータがないため、iterator2## はありません# 属性。

v-if命令は、v-if命令でバインドされている内容を取り出して、ifに入れて初期化します。同時に ifConditions属性は配列であり、オブジェクトはその中に格納されます: {exp,block}、ここで exp はバインディングを格納しますv-if 命令内 指定されたコンテンツ blockel を指します。

最適化 この例には静的ノードがないため、プロセスはここでは分析されません。

codegen

前回の記事では、

const code =generate(ast, options),generate から始まるコード生成プロセスを分析しました。 は内部で genElement を呼び出して、AST 構文ツリーである el を解析します。 genElement のソース コードを見てみましょう:

export function genElement (el: ASTElement, state: CodegenState): string {
  if (el.parent) {
    el.pre = el.pre || el.parent.pre
  }

  if (el.staticRoot && !el.staticProcessed) {
    return genStatic(el, state)
  } else if (el.once && !el.onceProcessed) {
    return genOnce(el, state)
  // 其实从此处可以初步知道为什么v-for优先级比v-if高,
  // 因为解析ast树生成渲染函数代码时,会先解析ast树中涉及到v-for的属性
  // 然后再解析ast树中涉及到v-if的属性
  // 而且genFor在会把el.forProcessed置为true,防止重复解析v-for相关属性
  } else if (el.for && !el.forProcessed) {
    return genFor(el, state)
  } else if (el.if && !el.ifProcessed) {
    return genIf(el, state)

  } else if (el.tag === &#39;template&#39; && !el.slotTarget && !state.pre) {
    return genChildren(el, state) || &#39;void 0&#39;
  } else if (el.tag === &#39;slot&#39;) {
    return genSlot(el, state)
  } else {
    // component or element
    let code
    if (el.component) {
      code = genComponent(el.component, el, state)
    } else {
      let data
      if (!el.plain || (el.pre && state.maybeComponent(el))) {
        data = genData(el, state)
      }

      const children = el.inlineTemplate ? null : genChildren(el, state, true)
      code = `_c(&#39;${el.tag}&#39;${        data ? `,${data}` : &#39;&#39; // data      }${        children ? `,${children}` : &#39;&#39; // children      })`
    }
    // module transforms
    for (let i = 0; i < state.transforms.length; i++) {
      code = state.transforms[i](el, code)
    }
    return code
  }
}

次に、

genForgenIf## の関数のソース コードを見てみましょう。 #: <pre class="brush:js;toolbar:false;">export function genFor (el, state , altGen, altHelper) { const exp = el.for const alias = el.alias const iterator1 = el.iterator1 ? `,${el.iterator1}` : &amp;#39;&amp;#39; const iterator2 = el.iterator2 ? `,${el.iterator2}` : &amp;#39;&amp;#39; el.forProcessed = true // avoid recursion return `${altHelper || &amp;#39;_l&amp;#39;}((${exp}),` + `function(${alias}${iterator1}${iterator2}){` + `return ${(altGen || genElement)(el, state)}` + //递归调用genElement &amp;#39;})&amp;#39; }</pre>この例では、

li

ast ツリーを処理するときに、最初に genElement を呼び出して ## を処理します。 #for 属性 このとき、forProcessed は仮想値です。このとき、v-for 関連属性を処理するために genFor が呼び出されます。 li ツリー。次に、 genElement を呼び出して li ツリーを処理します。これは、 forProcessedgenFortrue としてマークされているためです。したがって、genFor は実行されず、genIf が実行されて、v-if に関連する属性が処理されます。

export function genIf (el,state,altGen,altEmpty) {
  el.ifProcessed = true // avoid recursion
  // 调用genIfConditions主要处理el.ifConditions属性
  return genIfConditions(el.ifConditions.slice(), state, altGen, altEmpty)
}

function genIfConditions (conditions, state, altGen, altEmpty) {
  if (!conditions.length) {
    return altEmpty || &#39;_e()&#39; // _e用于生成空VNode
  }

  const condition = conditions.shift()
  if (condition.exp) { //condition.exp即v-if绑定值,例子中则为&#39;index!==0&#39;
    // 生成一段带三目运算符的js代码字符串
    return `(${condition.exp})?${       genTernaryExp(condition.block)    }:${      genIfConditions(conditions, state, altGen, altEmpty)    }`
  } else {
    return `${genTernaryExp(condition.block)}`
  }

  // v-if with v-once should generate code like (a)?_m(0):_m(1)
  function genTernaryExp (el) {
    return altGen
      ? altGen(el, state)
      : el.once
        ? genOnce(el, state)
        : genElement(el, state)
  }
}
参考フロントエンドの高度なインタビューの質問に対する詳細な回答

最後に、codegen

によって生成されたjsコードは次のとおりです:

function render() {
  with(this) {
    return _c(&#39;ul&#39;, _l((items), function (item, index) {
      return (index !== 0) ? _c(&#39;li&#39;) : _e()
    }), 0)
  }
}
その中に:

    _c
  • :

    createElement を呼び出して VNode を作成します

  • _l
  • :

    renderList 関数。主にリスト

  • _e
  • :

    createEmptyVNode 関数。主に空の VNode

    概要
v-for が v より優先順位が高いのはなぜですか-もし?要約すると、コンパイルには

parse

->

optimize->codegen という 3 つのプロセスがあります。 codegen プロセスでは、AST ツリー内の v-for に関連する属性が最初に解析され、次に v-if関連プロパティ。さらに、Vuev-forv-if をどのように処理するかを知ることもできます。 (学習ビデオ共有: vuejs 入門チュートリアル

基本プログラミング ビデオ )

以上がVue の優先度の比較: v-for が v-if よりも高い理由の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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