Vue 在一个元素同时出现v-if 和 v-for 指令,谁优先级高?

我们先看一个简单的代码,if 和 for 的代码实现。

if 优先处理

const numList = [1, 2, 3, 4];
const isShow = false;
//节点
const nodes = [];

//显示判断
if(isShow ){
    for(let i in numList){
        const val = numList[i];
        nodes.push(val );
    }
}

//最后输出 []
console.log(nodes);

for 优先处理

const numList = [1, 2, 3, 4];
const isShow = false;
//节点
const nodes = [];

//先运行
for(let i in numList){
    const val = numList[i];
    //判断处理
    if(isShow){
        nodes.push(val);
    }
}

//最后输出 []
console.log(nodes);

从上面的简单代码看到 if 和 for 是不可能同时运行的,总有个先后顺序,不管是 if 还是 for 先运行结果是一样的,但你会发现当 for 先运行时会有多余的计算浪费性能。

Vue 编译 v-if 和 v-for 同时出现时处理方法也是跟上面的代码一样,总有一个先后顺序。Vu2 使用 v-for 优先,Vue3 发现问题了更改为 v-if 优先。下面通过 Vue 将模板 template 编译成 vnode 时生成的代码来看看不同版本是怎么处理的,看了源代码你才会更加踏实,不是听别人说,而是听你说。

Vue2 v-for 优先,为了保证什么情况都可以正常运行,性能不考虑才会出现这个情况。

 //例子1:v-if 为独立条件,非 v-for 的条件

//组件数据,类样式组件


export default class AboutView extends Vue {
  public numList = [1, 2, 3, 4];
  public isShow = false;
}

 //template

{{item}}
// Vue 编译模板处理
//不管3721,先运行 v-for
_vm._l(_vm.numList, function (item) {
	//再判断 v-if
	return _vm.isShow
	  ? _c("div", { key: item }, [_vm._v(" " + _vm._s(item) + " ")])
	  : _vm._e()
})

从上面例子可以看到不管 v-if 是什么值都先运行 v-for 再作判断,明显看出性能会出现问题,_vm._e()会根据数据的长度产生对应长度的空vnode。

//例子2:v-if 为 v-for 的条件 

 //组件数据

export default class AboutView extends Vue {
  public numList = [1, 2, 3, 4];
  public isShow = true;
}

 //template

{{item}}

//编译处理 

// Vue 编译模板处理
//不管3721,先运行 v-for
 _vm._l(_vm.numList, function (item) {
	//判断值是否==2
	return item == 2
	  ? _c("div", { key: item }, [_vm._v(" " + _vm._s(item) + " ")])
	  : _vm._e()
})

从上面例子2可以看到 v-for 是必须的,再作判断是否显示,看似没有多余的动作,但这样做会造成逻辑复杂,性能上也是有问题的。首先_vm._e() 会产生空 vnode ,如果整个组件的其中一项数据发生变化,上面的渲染函数会重新运行,会计算数组 numList 不符合条件的项产生性能浪费。如果numList 已经计算好符合条件的数据,则 render 重新渲染不会产生多余的计算浪费性能,如下图。

Vue 在一个元素同时出现v-if 和 v-for 指令,谁优先级高?_第1张图片

小结:
综合上面两种情况当 v-if v-for 同时出现会出现性能问题,所以我们要避免同时使用两个指令。
处理方法有两种,一、在数据源处理掉 if 条件。二、两个指令分开写。

Vue3 v-if 优先,应该是开发者为了防止我们同时使用两个指令产生性能问题,所以 v-if 优先判断。

//例子1:v-if 为独立条件,非 v-for 的条件

//组件数据,ts setup


const numList = [1, 2, 3, 4];
const isShow = false;

//template

{{ item }}

//Vue编译模板 

// Vue 编译模板处理

//不管3721,先运行 v-if
$setup.isShow ? (_openBlock(), _createElementBlock(
_Fragment,
{ key: 0 },

//再运行 v-for
_renderList($setup.numList, (item) => {
  return _createElementVNode(
    "div",
    { key: item },
    _toDisplayString(item),
    1
    /* TEXT */
  );
}),
64
/* STABLE_FRAGMENT */
)) : _createCommentVNode("v-if", true)

从 Vue3 编译代码可以看到,没有多余的计算,对性能没有影响。


//例子2:v-if 为 v-for 的条件

//数据


const numList = [1, 2, 3, 4];
const isShow = false;

//template

{{ item }}

上面这种情况可以运行,但会报不存在属性“item”提示,运行结果是什么东西都不会显示,看下面编译代码。

// Vue 编译模板处理
// 判断 _ctx.item==2,item 未定义,所以 v-for 不会运行,程序逻辑达不到你想要的效果
_ctx.item == 2 ? (_openBlock(), _createElementBlock(
_Fragment,
{ key: 0 },
// 这里进不来
_renderList($setup.numList, (item) => {
  return _createElementVNode(
    "div",
    { key: item },
    _toDisplayString(item),
    1
    /* TEXT */
  );
}),
64
/* STABLE_FRAGMENT */
)) : _createCommentVNode("v-if", true)

从上面代码可以看到,item 是上下文的变量,不是 for 里面的 item,所以变量是没有定义的,最后是没有结果显示。

小结:
当 v-if 为 v-for 的条件时,程序逻辑达不到你想要的效果,你就会想办法解决了。
处理方法还是那两种,一、在数据源处理掉if条件。二、两个指令分开写。

总结:
为了避免 v-if v-for 产生问题最标准的处理方法是两个指令分开写,先 v-if 还是先 v-for,这样逻辑就清晰好多。如果 v-if 是 v-for 的逻辑最好在数据源头处理掉,保持模板的逻辑干净易读,当数据产生变化时渲染函数不用再处理判断,提高性能。

//#1 两个指令分开写,template处理


    
{{ item }}

//#2 先进行数据处理,你也可以使用其它方法,计算属性之类的。
const numList = [1, 2, 3, 4].filter(val => val == 2);

//#2 template


    {{ item }}

如果想看上面的的编译源代码,可以打开谷歌的按下F12,搜索上面的代码关键字numList查找,再导航到页面源代码,带?t=169xxxxx的为编译源代码,从下图可以看到render这个关键字,这样可以帮助你快速分析temaplate最后被编译成什么代码,从中学习好多表面看不到的指令实现知识,也可以帮助你以后用render函数自己实现teamplate编译渲染。

Vue 在一个元素同时出现v-if 和 v-for 指令,谁优先级高?_第2张图片

问题来源,2023.09.01去樟木头张力科技公司面试时被问到的一个问题 v-if v-for 哪个最优先?我回答Vue3哪个优先不是很肯定 ,只是用自己的思路说肯定是 v-if 优先了,这样符合代码逻辑和性能,果不奇然被我懵对了。

你可能感兴趣的:(Vue,vue.js,javascript,前端)