避免v-if和v-for用在一起
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了避免v-if和v-for用在一起相关的知识,希望对你有一定的参考价值。
参考技术Av-if和v-for一起使用,v-for的优先级要高于v-if
详解
当vue处理指令时, v-for 比 v-if 具有更高的优先级,所以这个模板:
将会经过如下运算
因此,哪怕我们只渲染出一小部分的用户元素,也得在每次重新渲染的时候遍历整个列表,不论活跃用户是否发生了改变。
通过将其更换为如下的一个计算属性上遍历:
我们将会获得如下好处:
也可以把:
更新为:
通过将 v-if 移动到容器元素,我们不会再对列表中的每个用户检查 shouldShoeUsers 。取而代之的是,我们只检查一次,且不会在 shouldShoeUsers 为否的时候运算 v-for 。
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 }
对于对象来说,逻辑是一样的,只是在逻辑上多个几个细分支,就不介绍了。
以上是关于避免v-if和v-for用在一起的主要内容,如果未能解决你的问题,请参考以下文章