vue2和vue3的v-if和v-for优先级是什么样的?怎样使用呢?

722 阅读2分钟

做个测试如下 vue2示例

<!DOCTYPE html>
<html>
  <head>
    <title>Vue事件处理</title>
  </head>
  <body>
    <div id="demo">
      <h1>v-for和v-if谁的优先级高?应该如何正确使用避免性能问题?</h1>
      <p v-for="child in children" v-if="isFolder">{{child.title}}</p>
      <!-- <template v-if="isFolder">
        <p v-for="child in children">{{child.title}}</p>
      </template> -->
    </div>
    <script src="../dist/vue2.js"></script>
    <script>
      // 创建实例  vue2
      const app = new Vue({
        el: "#demo",
        data() {
          return {
            children: [{ title: "foo" }, { title: "bar" }],
          };
        },
        computed: {
          isFolder() {
            return this.children && this.children.length > 0;
          },
        },
      });
      console.log(app.$options.render);
    </script>
  </body>
</html>

两者同级时,渲染函数如下:

(function anonymous(
) {
with(this){return _c('div',{attrs:{"id":"demo"}},[_c('h1',[_v("v-for和v-if谁的优先
级高?应该如何正确使用避免性能问题?")]),_v(" "),
_l((children),function(child){return (isFolder)?_c('p',
[_v(_s(child.title))]):_e()})],2)}
})
​

_l是对children的循环,判断条件是isFolder可见他是包含在循环里的所以v-for是比v-if的优先级高,其实缺点也是很明显的放在一起每次循环都要去判断是浪费性能的,我们看看vue2的源码

image-20221222204049014.png

源码v-for的优先级也是高于v-if的

_l包含了isFolder的条件判断

(function anonymous(
) {
with(this){return _c('div',{attrs:{"id":"demo"}},[_c('h1',[_v("v-for和v-if谁的优先
级高?应该如何正确使用避免性能问题?")]),_v(" "),
(isFolder)?_l((children),function(child){return _c('p',
[_v(_s(child.title))])}):_e()],2)}
})
​

isFolder条件用template包裹后,条件在前面而循环在后面

同理我们看看vue3

<!DOCTYPE html>
<html>
  <head>
    <title>Vue事件处理</title>
  </head>
  <body>
    <div id="demo">
      <h1>v-for和v-if谁的优先级高?应该如何正确使用避免性能问题?</h1>
      <p v-for="child in children" v-if="isFolder">{{child.title}}</p>
      <!-- <template v-if="isFolder">
        <p v-for="child in children">{{child.title}}</p>
      </template> -->
    </div>
    <script src="../dist/vue3.js"></script>
    <script>
      // vue3
      const app = Vue.createApp({
        template: "",
        data() {
          return {
            children: [{ title: "foo" }, { title: "bar" }],
          };
        },
        computed: {
          isFolder() {
            return this.children && this.children.length > 0;
          },
        },
      });
      app.mount("#demo");
      console.log(app._component.render);
    </script>
  </body>
</html>

两者同级时,渲染函数如下:

(function anonymous(
) {
const _Vue = Vue
const { createElementVNode: _createElementVNode, createCommentVNode: _createCommentVNode } = _Vue
​
const _hoisted_1 = /*#__PURE__*/_createElementVNode("h1", null, "v-for和v-if谁的优先级高?应该如何正确使用避免性能问题?", -1 /* HOISTED */)
​
return function render(_ctx, _cache) {
  with (_ctx) {
    const { createElementVNode: _createElementVNode, renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock, toDisplayString: _toDisplayString, createCommentVNode: _createCommentVNode } = _Vue
​
    return (_openBlock(), _createElementBlock(_Fragment, null, [
      _hoisted_1,
      isFolder
        ? (_openBlock(true), _createElementBlock(_Fragment, { key: 0 }, _renderList(children, (child) => {
            return (_openBlock(), _createElementBlock("p", null, _toDisplayString(child.title), 1 /* TEXT */))
          }), 256 /* UNKEYED_FRAGMENT */))
        : _createCommentVNode("v-if", true),
      _createCommentVNode(" <template v-if="isFolder">\n        <p v-for="child in children">{{child.title}}</p>\n      </template> ")
    ], 64 /* STABLE_FRAGMENT */))
  }
}
})

显然这次的渲染函数isFolder放在了循环前面所以这次的v-if是优先于v-for

结论:

  • vue2
  1. 显然v-for优先于v-if被解析(把你是怎么知道的告诉面试官)
  2. 如果同时出现,每次渲染都会先执行循环再判断条件,无论如何循环都不可避免,浪费了性能
  3. 要避免出现这种情况,则在外层嵌套template,在这一层进行v-if判断,然后在内部进行v-for循环
  4. 如果条件出现在循环内部,可通过计算属性提前过滤掉那些不需要显示的项
  • vue3
  1. 显然v-if优先于for被解析(把你是怎么知道的告诉面试官)

这里补充下_lrenderList关系

从vue3源码找到

image-20221222212909092.png

image-20221222212926616.png

renderList是针对不同类型进行遍历再将其返回

如有大佬的建议,可以点评