在vue.js里面,v-for和v-if是可以一起使用作用在某個元素上,網上看到一篇文章說永遠不要把v-for和v-if同時用在同一個元素上,感覺有點瞎扯,官網也注明了可以一起使用的,還把兩個指令的優先級給說明了:

當v-if和v-for一起使用時,v-for的優先級更高,為了方便理解舉個栗子:
<div id="app">
<ul>
<li v-for="item in Nums" v-if="item%2==0">{{item}}->偶數</li>
<li v-else-if="item%3==0">{{item}}->可以被3整除的奇數</li>
<li v-else>{{item}}->其它奇數</li>
</ul>
</div>
<script>
new Vue({
el:"#app",
data:{
Nums:[0,1,2,3,4,5,6,7,8,9,10,11,12]
}
})
</script>
比較簡單昂,就是用v-for循環一個數組,然后分別用v-if、v-else-if和v-else做判斷,渲染如下:

很多人剛開始一起用v-for和v-if時多少有點不習慣,如下:
<li v-for="item in Nums" v-if="item%2==0">{{item}}->偶數</li>
<li v-else-if="item%3==0">{{item}}->可以被3整除的奇數</li>
<li v-else>{{item}}->其它奇數</li>
第2和第3行<li>標簽的代碼里用到了item,但是item是在第一個<li>里定義了,這樣不是不能獲取到的嗎?其實在源碼內部,這三行代碼都封裝為一個返回一個三元表達式的函數了,作為v-for實現代碼的一個參數,然后在v-for遍歷數組時依次執行這函數來輸出數據的
對於例子里的模板經過在編譯階段生成AST對象后會調用generate函數生成render函數,如下:

它會優先處理v-for指令,然后處於v-if、v-else-if、v-else之類的指令(可以看到v-once的優先級高於v-for和v-else),對於例子里的模板生成的render函數如下:
_c(
'div',
{attrs: {"id": "app"}},
[
_c(
'ul',
_l((Nums),function(item) {
return (item % 2 == 0) ? _c('li', [_v(_s(item) + "->偶數")])
: (item % 3 == 0) ? _c('li', [_v(_s(item) + "->可以被3整除的奇數")])
: _c('li', [_v(_s(item) + "->其它奇數")])
})
)
]
)
_l對應的就是v-for的實現函數,可以看到vue內部把v-if的代碼封裝為了一個匿名函數,傳遞給了v-for,而在v-for最后實現時,它是通過遍歷Nums,依次執行參數2的,_l對應的函數如下:
function renderList(val, render) { //渲染v-for指令
var ret, i, l, keys, key;
if (Array.isArray(val) || typeof val === 'string') { //如果val是個數組
ret = new Array(val.length); //將ret定義成val一樣大小的數組
for (i = 0, l = val.length; i < l; i++) { //遍歷val數組
ret[i] = render(val[i], i); //依次調用render函數,參數1為值 參數2為索引 返回VNode,並把結果VNode保存到ret里面 ;例子里的Nums是個數組,因此是執行到這里的
}
} else if (typeof val === 'number') {
ret = new Array(val);
for (i = 0; i < val; i++) {
ret[i] = render(i + 1, i);
}
} else if (isObject(val)) { //如果val是一個對象
keys = Object.keys(val);
ret = new Array(keys.length);
for (i = 0, l = keys.length; i < l; i++) {
key = keys[i];
ret[i] = render(val[key], key, i); //執行的時候傳遞三個參數,分別是值、key和索引
}
}
if (isDef(ret)) { //如果ret存在(成功調用了)
(ret)._isVList = true; //則給該數組添加一個_isVList屬性,值為true
}
return ret //最后返回ret
}
對於對象來說,邏輯是一樣的,只是在邏輯上多個幾個細分支,就不介紹了。

