欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue為什么v-for的優(yōu)先級比v-if高原理解析

 更新時間:2023年05月22日 10:11:39   作者:風度翩翩的紅金魚  
這篇文章主要為大家介紹了vue為什么v-for的優(yōu)先級比v-if高原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

有時候有些面試中經(jīng)常會問到v-forv-if誰的優(yōu)先級高,這里就通過分析源碼去解答一下這個問題。

下面的內(nèi)容是在 當我們談及v-model,我們在討論什么?的基礎(chǔ)上分析的,所以閱讀下面內(nèi)容之前可先看這篇文章。

繼續(xù)從編譯出發(fā)

以下面的例子出發(fā)分析:

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

從上篇文章可以知道,編譯有三個步驟

  • parse : 解析模板字符串生成 AST語法樹
  • optimize : 優(yōu)化語法樹,主要時標記靜態(tài)節(jié)點,提高更新頁面的性能
  • codegen : 生成js代碼,主要是render函數(shù)和staticRenderFns函數(shù)

我們再次順著這三個步驟對上述例子進行分析。

parse

parse過程中,會對模板使用大量的正則表達式去進行解析。開頭的例子會被解析成以下AST節(jié)點:

// 其實ast有很多屬性,我這里只展示涉及到分析的屬性
ast = {
  'type': 1,
  'tag': 'ul',
  'attrsList': [],
  attrsMap: {},
  'children': [{
    'type': 1,
    'tag': 'li',
    'attrsList': [],
    'attrsMap': {
      'v-for': '(item,index) in data',
      'v-if': 'index!==0'
     },
     // v-if解析出來的屬性
    'if': 'index!==0',
    'ifConditions': [{
      'exp': 'index!==0',
      'block': // 指向el自身
    }],
    // v-for解析出來的屬性
    'for': 'items',
    'alias': 'item',
    'iterator1': 'index',
    'parent': // 指向其父節(jié)點
    'children': [
      'type': 2,
      'expression': '_s(item)'
      'text': '{{item}}',
      'tokens': [
        {'@binding':'item'},
      ]
    ]
  }]
}

對于v-for指令,除了記錄在attrsMapattrsList,還會新增for(對應(yīng)要遍歷的對象或數(shù)組),aliasiterator1,iterator2對應(yīng)v-for指令綁定內(nèi)容中的第一,第二,第三個參數(shù),開頭的例子沒有第三個參數(shù),因此沒有iterator2屬性。

對于v-if指令,把v-if指令中綁定的內(nèi)容取出放在if中,與此同時初始化ifConditions屬性為數(shù)組,然后往里面存放對象:{exp,block},其中exp存放v-if指令中綁定的內(nèi)容,block指向el。

optimize 過程在此不做分析,因為本例子沒有靜態(tài)節(jié)點。

codegen

上一篇文章從const code = generate(ast, options)開始分析過其生成代碼的過程,generate內(nèi)部會調(diào)用genElement用來解析el,也就是AST語法樹。我們來看一下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優(yōu)先級比v-if高,
  // 因為解析ast樹生成渲染函數(shù)代碼時,會先解析ast樹中涉及到v-for的屬性
  // 然后再解析ast樹中涉及到v-if的屬性
  // 而且genFor在會把el.forProcessed置為true,防止重復(fù)解析v-for相關(guān)屬性
  } 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
  }
}

接下來依次看看genForgenIf的函數(shù)源碼:

export function genFor (el, state , altGen, altHelper) {
  const exp = el.for
  const alias = el.alias
  const iterator1 = el.iterator1 ? `,${el.iterator1}` : ''
  const iterator2 = el.iterator2 ? `,${el.iterator2}` : ''
  el.forProcessed = true // avoid recursion
  return `${altHelper || '_l'}((${exp}),` + 
    `function(${alias}${iterator1}${iterator2}){` +
      `return ${(altGen || genElement)(el, state)}` + //遞歸調(diào)用genElement
    '})'
}

在我們的例子里,當他處理liast樹時,會先調(diào)用genElement,處理到for屬性時,此時forProcessed為虛值,此時調(diào)用genFor處理li樹中的v-for相關(guān)的屬性。然后再調(diào)用genElement處理li樹,此時因為forProcessedgenFor中已被標記為true。因此genFor不會被執(zhí)行,繼而執(zhí)行genIf處理與v-if相關(guān)的屬性。

export function genIf (el,state,altGen,altEmpty) {
  el.ifProcessed = true // avoid recursion
  // 調(diào)用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)
  }
}

參考 前端進階面試題詳細解答

最后,經(jīng)過codegen生成的js代碼如下:

function render() {
  with(this) {
    return _c('ul', _l((items), function (item, index) {
      return (index !== 0) ? _c('li') : _e()
    }), 0)
  }
}

其中:

  • _c: 調(diào)用 createElement 去創(chuàng)建 VNode
  • _lrenderList函數(shù),主要用來渲染列表
  • _ecreateEmptyVNode函數(shù),主要用來創(chuàng)建空VNode

總結(jié)

為什么v-for的優(yōu)先級比v-if的高?總結(jié)來說是編譯有三個過程,parse->optimize->codegen。在codegen過程中,會先解析AST樹中的與v-for相關(guān)的屬性,再解析與v-if相關(guān)的屬性。除此之外,也可以知道Vuev-forv-if是怎么處理的。

以上就是vue為什么v-for的優(yōu)先級比v-if高原理解析的詳細內(nèi)容,更多關(guān)于vue優(yōu)先級v-for v-if的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue自定義模態(tài)對話框彈窗

    Vue自定義模態(tài)對話框彈窗

    這篇文章主要為大家詳細介紹了Vue自定義模態(tài)對話框彈窗,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • vue自定義指令添加跟隨鼠標光標提示框v-tooltip方式

    vue自定義指令添加跟隨鼠標光標提示框v-tooltip方式

    這篇文章主要介紹了vue自定義指令添加跟隨鼠標光標提示框v-tooltip方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10
  • Vue3中Provide?/?Inject的實現(xiàn)原理分享

    Vue3中Provide?/?Inject的實現(xiàn)原理分享

    provide和inject主要為高階插件/組件庫提供用例,這篇文章主要給大家介紹了關(guān)于Vue3中Provide?/?Inject的實現(xiàn)原理,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-02-02
  • vue2.0 和 animate.css的結(jié)合使用

    vue2.0 和 animate.css的結(jié)合使用

    animate.css是一款前端動畫庫,相似的有velocity-animate。這篇文章給大家介紹vue2.0 和 animate.css的結(jié)合使用,需要的朋友參考下吧
    2017-12-12
  • vuex的簡單使用教程

    vuex的簡單使用教程

    vuex是一個專門為vue.js設(shè)計的集中式狀態(tài)管理架構(gòu)。這篇文章主要介紹了vuex的簡單使用,需要的朋友可以參考下
    2018-02-02
  • 安裝vue-cli的簡易過程

    安裝vue-cli的簡易過程

    安裝vue-cli的前提是你已經(jīng)安裝了npm,安裝npm你可以直接下載node的安裝包進行安裝。接下來通過本文給大家介紹安裝vue-cli的簡易過程,感興趣的朋友跟隨腳本之家小編一起學習吧
    2018-05-05
  • vue+jquery+lodash實現(xiàn)滑動時頂部懸浮固定效果

    vue+jquery+lodash實現(xiàn)滑動時頂部懸浮固定效果

    這篇文章主要為大家詳細介紹了vue+jquery+lodash實現(xiàn)滑動時頂部懸浮固定效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • Vue中JS動畫與Velocity.js的結(jié)合使用

    Vue中JS動畫與Velocity.js的結(jié)合使用

    這篇文章主要介紹了Vue中JS動畫與Velocity.js的結(jié)合使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-02-02
  • tdesign vue初始化組件源碼解析

    tdesign vue初始化組件源碼解析

    這篇文章主要為大家介紹了tdesign vue初始化組件源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • vue中echarts關(guān)系圖動態(tài)增刪節(jié)點以及連線方式

    vue中echarts關(guān)系圖動態(tài)增刪節(jié)點以及連線方式

    這篇文章主要介紹了vue中echarts關(guān)系圖動態(tài)增刪節(jié)點以及連線方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07

最新評論