Vue常见面试题大汇总

203 阅读2分钟

本文将对Vue2、Vue3中的常见面试题进行详细剖析,部分附带源码

  • v-if和v-for哪个优先级更高?如果两个同时出现,应该怎么优化得到更好的性能?

Vue2

测试代码:

  <!DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>v-for、v-if</title>
  </head>
  <body>
    <div id="demo">
      <p v-for="list of lists" v-if="list.show">{{list.name}}</p>

      <template v-if="lists && lists.length">
        <p v-for="list of lists">{{list.name}}</p>
      </template>
    </div>
    <script src="../../dist/vue.js"></script>
    <script>
      const app = new Vue({
        el: '#demo',
        data() {
          return {
            lists: [{
              name: 'one',
              show: true
            }, {
              name: 'two',
              show: false
            }]
          };
        }
      });
      console.log(app.$options.render);
    </script>
  </body>
  </html>

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

  ƒ anonymous(
  ) {
  with(this){return _c('div',{attrs:{"id":"demo"}},_l((lists),function(list){return (list.show)?_c('p',[_v(_s(list.name))]):_e()}),0)}
  }

_l中包含了条件判断

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

  ƒ anonymous(
  ) {
  with(this){return _c('div',{attrs:{"id":"demo"}},[(lists && lists.length)?_l((lists),function(list){return _c('p',[_v(_s(list.name))])}):_e()],2)}
  }

先判断条件再看是否执行_l

结论:
1、v-for优先于v-if被解析

  // compiler/gencode/index.js 61行
  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 {}

2、如果同时出现,每次渲染都会先执行循环再判断条件,浪费性能
3、避免同时使用v-for和v-if,如果需要使用,外层进行v-if判断,内部进行v-for循环,或者将需要遍历的数据提前通过计算属性进行过滤

Vue3

测试代码:

  <!DOCTYPE html>
  <html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>v-for、v-if</title>
  </head>
  <body>
    <div id="demo">
      <div v-for="list of lists" v-if="list.show">
        <p>{{list.name}} === {{list.show}}</p>
      </div>
    </div>
    <script src="../dist/vue.global.js"></script>
    <script>
      const { createApp } = Vue;
      const app = createApp({
        data() {
          return {
            lists: [{
              name: 'one',
              show: true
            }, {
              name: 'two',
              show: false
            }]
          };
        }
      }).mount('#demo');
    </script>
  </body>
  </html>

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

  (function anonymous(
  ) {
  const _Vue = Vue

  return function render(_ctx, _cache) {
    with (_ctx) {
      const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock, toDisplayString: _toDisplayString, createVNode: _createVNode, createCommentVNode: _createCommentVNode } = _Vue

      return (list.show)
        ? (_openBlock(true), _createBlock(_Fragment, { key: 0 }, _renderList(lists, (list) => {
            return (_openBlock(), _createBlock("div", null, [
              _createVNode("p", null, _toDisplayString(list.name) + " === " + _toDisplayString(list.show), 1 /* TEXT */)
            ]))
          }), 256 /* UNKEYED_FRAGMENT */))
        : _createCommentVNode("v-if", true)
    }
  }
  })

两者同级时,先判断条件再进行遍历渲染,这样由于对象还不存在,所以同级的时候渲染空白或报错(对象不存在)

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

  (function anonymous(
  ) {
  const _Vue = Vue
  const { createCommentVNode: _createCommentVNode } = _Vue

  const _hoisted_1 = { key: 0 }

  return function render(_ctx, _cache) {
    with (_ctx) {
      const { renderList: _renderList, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock, toDisplayString: _toDisplayString, createCommentVNode: _createCommentVNode } = _Vue

      return (_openBlock(true), _createBlock(_Fragment, null, _renderList(lists, (list) => {
        return (_openBlock(), _createBlock("div", null, [
          (list.show)
            ? (_openBlock(), _createBlock("p", _hoisted_1, _toDisplayString(list.name) + " === " + _toDisplayString(list.show), 1 /* TEXT */))
            : _createCommentVNode("v-if", true)
        ]))
      }), 256 /* UNKEYED_FRAGMENT */))
    }
  }
  })

两者不同级的时候正常遍历数组,然后进行条件判断渲染

结论
1、Vue3中禁止将v-for和v-if同级,不能正常渲染,弥补了Vue2中可同级的性能问题
2、如果真需要遍历时使用v-if判断,解决方案可参考Vue2


  • vue组件data为什么必须是个函数而Vue的根实例没有此限制?

源码:src/code/instance/state.js initData()

  • vue中key的作用和工作原理

  • 怎么理解vue中的diff算法?

  • 对vue组件化的理解

  • 对vue的设计原则的理解

  • 谈谈对MVC、MVP和MVVM的理解

  • vue性能优化方案

  • vue3新特性

  • vuex使用及理解

  • vue中组件之间的通信方式

  • vue-router中如何保护指定路由的安全?

  • nextTick实现原理及作用

  • vue响应式原理