当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函数,如下:

if (el.staticRoot && !el.staticProcessed) {
    return genStatic(el, state)
  } else if (el.once && !el.onceProcessed) {
    return genOnce(el, state)
  } 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
  }

 它会优先处理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
}

 

posted on 2020-12-22 21:59  Jack·zhou  阅读(334)  评论(0编辑  收藏  举报