下载安卓APP箭头
箭头给我发消息

客服QQ:3315713922

Web前端:Vue.js 从源码理解v-for和v-if的优先级的高低

作者:大沙漠     来源: https://www.cnblogs.com/greatdesert/archive/2020/02/25/12357点击数:2023发布时间: 2020-02-29 16:01:50

标签: Web前端Vue.jsv-for

Web开发

Vue.js(读音 /vjuː/, 类似于 view)是一个构建数据驱动的 web 界面的渐进式框架。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

在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是个数组,因此是执行到这里的

        }

    } elseif (typeof val === 'number') {

        ret = new Array(val);

        for (i = 0; i < val; i++) {

            ret[i] = render(i + 1, i);

        }

    } elseif (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

}

对于对象来说的话,逻辑是一模一样的,只是在逻辑上多个几个细分支,小编就不一一介绍了。

Vue.js 自身不是一个全能框架--它只聚焦于视图层。因此它非常容易学习,非常容易与其它库或已有项目整合。另一方面,在与相关工具和支持库一起使用时,Vue.js 也能完美地驱动复杂的单页应用。

赞(0)
踩(0)
分享到:
华为认证网络工程师 HCIE直播课视频教程