Vue.js 從源碼理解v-for和v-if的優先級的高低


在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) + "->其它奇數")])
            })
        )
    ]
)

 writer by:大沙漠 QQ:22969969

_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
}

對於對象來說,邏輯是一樣的,只是在邏輯上多個幾個細分支,就不介紹了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM