ホームページ >ウェブフロントエンド >Vue.js >Vue の優先度の比較: v-for が v-if よりも高い理由
vue v-for の優先順位が v-if よりも高いのはなぜですか?次の記事では、ソースコードを分析しながらこの疑問に答えますので、皆さんのお役に立てれば幸いです。
一部のインタビューでは、v-for
と v-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 つのステップがあります。コンパイルへ
これら 3 つの手順を再度実行して、上記の例を分析してみましょう。
parseこのプロセスでは、テンプレートを解析するために多数の正規表現が使用されます。冒頭の例は、attrsMap
のレコードに加えて、
ディレクティブの <pre class="brush:js;toolbar:false;">// 其实ast有很多属性,我这里只展示涉及到分析的属性
ast = {
&#39;type&#39;: 1,
&#39;tag&#39;: &#39;ul&#39;,
&#39;attrsList&#39;: [],
attrsMap: {},
&#39;children&#39;: [{
&#39;type&#39;: 1,
&#39;tag&#39;: &#39;li&#39;,
&#39;attrsList&#39;: [],
&#39;attrsMap&#39;: {
&#39;v-for&#39;: &#39;(item,index) in data&#39;,
&#39;v-if&#39;: &#39;index!==0&#39;
},
// v-if解析出来的属性
&#39;if&#39;: &#39;index!==0&#39;,
&#39;ifConditions&#39;: [{
&#39;exp&#39;: &#39;index!==0&#39;,
&#39;block&#39;: // 指向el自身
}],
// v-for解析出来的属性
&#39;for&#39;: &#39;items&#39;,
&#39;alias&#39;: &#39;item&#39;,
&#39;iterator1&#39;: &#39;index&#39;,
&#39;parent&#39;: // 指向其父节点
&#39;children&#39;: [
&#39;type&#39;: 2,
&#39;expression&#39;: &#39;_s(item)&#39;
&#39;text&#39;: &#39;{{item}}&#39;,
&#39;tokens&#39;: [
{&#39;@binding&#39;:&#39;item&#39;},
]
]
}]
}</pre>
という AST
ノードに解析されます。および attrsList
は、for
(トラバースするオブジェクトまたは配列に対応)、alias
、iterator1
、 も追加します。 iterator2
に対応 v-for
命令バインディング コンテンツの 1 番目、2 番目、および 3 番目のパラメータ 最初の例には 3 番目のパラメータがないため、iterator2## はありません# 属性。
v-if命令は、
v-if命令でバインドされている内容を取り出して、
ifに入れて初期化します。同時に
ifConditions属性は配列であり、オブジェクトはその中に格納されます:
{exp,block}、ここで
exp はバインディングを格納します
v-if 命令内 指定されたコンテンツ
block は
el を指します。
最適化 この例には静的ノードがないため、プロセスはここでは分析されません。
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 === 'template' && !el.slotTarget && !state.pre) { return genChildren(el, state) || 'void 0' } else if (el.tag === 'slot') { 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('${el.tag}'${ data ? `,${data}` : '' // data }${ children ? `,${children}` : '' // children })` } // module transforms for (let i = 0; i < state.transforms.length; i++) { code = state.transforms[i](el, code) } return code } }次に、
genFor と
genIf## の関数のソース コードを見てみましょう。 #: <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}` : &#39;&#39;
const iterator2 = el.iterator2 ? `,${el.iterator2}` : &#39;&#39;
el.forProcessed = true // avoid recursion
return `${altHelper || &#39;_l&#39;}((${exp}),` +
`function(${alias}${iterator1}${iterator2}){` +
`return ${(altGen || genElement)(el, state)}` + //递归调用genElement
&#39;})&#39;
}</pre>
この例では、
の ast
ツリーを処理するときに、最初に genElement
を呼び出して ## を処理します。 #for 属性 このとき、
forProcessed は仮想値です。このとき、
v-for 関連属性を処理するために
genFor が呼び出されます。
li ツリー。次に、
genElement を呼び出して
li ツリーを処理します。これは、
forProcessed が
genFor で
true としてマークされているためです。したがって、
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 || '_e()' // _e用于生成空VNode } const condition = conditions.shift() if (condition.exp) { //condition.exp即v-if绑定值,例子中则为'index!==0' // 生成一段带三目运算符的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('ul', _l((items), function (item, index) { return (index !== 0) ? _c('li') : _e() }), 0) } }その中に:
createElement を呼び出して
VNode を作成します
renderList 関数。主にリスト
createEmptyVNode 関数。主に空の
VNode
optimize->
codegen という 3 つのプロセスがあります。
codegen プロセスでは、
AST ツリー内の
v-for に関連する属性が最初に解析され、次に
v-if関連プロパティ。さらに、
Vue が
v-for と
v-if をどのように処理するかを知ることもできます。
(学習ビデオ共有:
vuejs 入門チュートリアル
基本プログラミング ビデオ )
以上がVue の優先度の比較: v-for が v-if よりも高い理由の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。