首頁 > web前端 > Vue.js > 主體

優先比較:v-for 和 v-if哪個比較高?

青灯夜游
發布: 2022-08-29 19:52:05
轉載
3242 人瀏覽過

v-for 和 v-if哪個優先權比較高?下面這篇文章就從實際例子和源碼講解v-forv-if的優先級,相信你看完後會茅塞頓開的。

優先比較:v-for 和 v-if哪個比較高?

結論

1、本身不建議將v-for和v-if同時使用的。 (學習影片分享:vue影片教學

2、vue2裡面v-for比v-if的優先權更高。因為vue2在模板編譯的時候會先處理v-for再處理v-if,所以產生的渲染函數會先執行循環,然後再在循環裡面執行條件判斷。

3.這樣做帶來的問題就是

對於場景1:<li v-for="user in users" v-if="user.show"&gt ;

每次重新渲染的時候,都要重新遍歷整個列表,其實我們只需要列表的一部分,這樣做浪費效能。推薦的做法是,透過計算屬性先過濾出我們需要的部分,再去渲染,更有效率。

對於場景2: <li v-for="user in users" v-if="globalShow">

globalShow這個判斷其實如果是false ,循環並不需要執行,但是現在跟v-if一起用,不管globalShow是否是true都要執行循環,完全是浪費。建議的做法是將v-if移到ul容器。

4、要注意的是,vue3的breaking change,在vue3中v-if的優先權比v-for高,所以如果同時使用的話,對於場景1,這個時候user還沒有,v -if="user.show"就會報錯

5、一般我們如果有用eslint,也會給我們報錯,對應的規則是:vue/no-use-v-if-with-v- for

實際範例

例如:以下的模板,將會產生下面的渲染函數

<ul>
    <li v-for="user in users" v-if="user.isActive" :key="user.id">
        {{ user.name }}
    </li>
</ul>
登入後複製

產生的渲染函數如下

with(this) {
    return _c('ul', _l((users), function (user) {
        return (user.isActive) ? _c('li', user.name) : _e()
    }), 0)
}
登入後複製

從上面生成的渲染函數可以看出,會先執行_l遍歷user,在裡面進行條件判斷

源碼

##處理v-if和v -for的原始碼

src/compiler/index.js

// 模板解析,生成ast树
const ast = parse(template.trim(), options)
if (options.optimize !== false) {
    optimize(ast, options)
}
const code = generate(ast, options)
登入後複製
根據ast產生程式碼,假如是上面的模板,產生的ast簡化後如下

// 可以看出v-for和v-if都解析出来了
 ast = {
     'type': 1,
     'tag': 'ul',
     'attrsList': [],
     'attrsMap': {},
     'children': [{
     'type': 1,
     'tag': 'li',
     'attrsList': [],
     'attrsMap': {
         'v-for': 'user in users',
         'v-if': 'user.show'
     },
     // v-if解析出来的属性
     'if': 'user.show',
     'ifConditions': [{
         'exp': 'user.show',
         'block': // 指向el自身
     }],
     // v-for解析出来的属性
     'for': 'users',
     'alias': 'user',
     'iterator1': 'index',
     'parent': // 指向其父节点
     'children': [
         'type': 2,
         'expression': '_s(user)'
         'text': '{{user}}',
         'tokens': [
             {'@binding':'user'},
         ]
      ]
     }]
 }
登入後複製

compiler/codegen/index.js

// generate 调用 genElement
const code = ast ? genElement(ast, state) : '_c("div")'
// genElement里面的处理
if (el.staticRoot && !el.staticProcessed) {
return genStatic(el, state)
} else if (el.once && !el.onceProcessed) {
return genOnce(el, state)
// 从这可以看出来,先执行genFor,处理v-for指令,在genFor里面会递归调用genElement,继续处理v-if,genFor会将forProcessed设为true,这样下次进来的时候就不会处理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 {
// 最后这里处理标签等
const children = el.inlineTemplate ? null : genChildren(el, state, true)
code = `_c('${el.tag}'${
data ? `,${data}` : '' // data
}${
children ? `,${children}` : '' // children
})`
}

// genFor的代码
const exp = el.for // 对应上面ast的 for: users
const alias = el.alias // alias: user
// iterator1 对应v-for的(item,key,index) in items的key
// iterator2 对应的是index
// 通常我们遍历数组 key就是index
// 假如我们遍历的是对象 key就是对象的key,index就是遍历的索引
const iterator1 = el.iterator1 ? `,${el.iterator1}` : ''
const iterator2 = el.iterator2 ? `,${el.iterator2}` : ''
el.forProcessed = true // 下次递归调用genElement的时候就不会重复处理v-for了
return `${altHelper || '_l'}((${exp}),` +
`function(${alias}${iterator1}${iterator2}){`

// 这里处理完了v-for,递归调用genElement继续处理v-if
`return ${(altGen || genElement)(el, state)}` +
'})'
登入後複製

最終會產生類似如下的程式碼返回

_l((users), function(user, index) {
    // 如果有v-if 前面就会有个条件判断,如user.isActive
    return (user.isActive) ? _c('li', user.name) : _e()
});
登入後複製
(學習影片分享:

web前端開發程式設計基礎影片

以上是優先比較:v-for 和 v-if哪個比較高?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:juejin.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板