# Vue 面试题

# 一、v-if 和 v-for 的区别

# 1. 两者的作用

  • v-if 指令:用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 true 值的时候被渲染

  • v-for 指令:基于一个数组来渲染一个列表。v-for 建议设置 key 值,并且保证每个 key 值是独一无二的,这便于 diff 算法进行优化。需要使用 item in items 形式的特殊语法(item 是被迭代的数组元素的别名,items 是源数据数组或者对象)。

两者在用法上区别如下:

<div v-if="isShow" >123</div>

<li v-for="item in items" :key="item.id">
  {{ item.label }}
</li>

# 2. 两者的优先级

  • 2.x 版本中在一个元素上同时使用 v-if 和 v-for 时,v-for 的优先级高。
  • 3.x 版本中 v-if 总是优先于 v-for 生效。

# 3. 注意事项

首先在官方文档中明确指出 v-for 和 v-if 不建议一起使用。

永远不要把 v-if 和 v-for 同时用在同一个元素上,带来性能方面的浪费(每次渲染都会先循环再进行条件判断),如果避免出现这种情况,则在外层嵌套 template(页面渲染不生成 dom 节点),在这一层进行 v-if 判断,然后在内部进行 v-for 循环

<template v-if="isShow">
  <p v-for="item in items">
</template>

如果条件出现在循环内部,可通过计算属性 computed 提前过滤掉不需要显示的项。

computed: {
    items: function() {
        return this.list.filter(function (item) {
            return item.isShow
        })
    }
}

# 二、v-if 与 v-show 的区别

  1. 共同点: 都是动态显示 DOM 元素。

  2. 区别:

v-if v-show
手段 通过控制 DOM 节点的存在与否来控制元素的显隐 通过设置 DOM 元素的 display 样式,(block 为显示,none 为隐藏)
编译条件 惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译 是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且 DOM 元素保留
编译过程 切换有一个局部编译 / 卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件 只是简单的基于 css 切换
性能消耗 有更高的切换消耗 有更高的初始渲染消耗
使用场景 适合运行条件很少改变 适合频繁切换

# 三、Vue / React 项目中的 key

  1. 作用:
  • 为了在 diff 算法执行时更快的找到对应的节点,提高 diff 速度,更高效的更新虚拟 DOM。
  • 为了在数据变化时强制更新组件,以避免“就地复用”带来的副作用。
  1. 开发中如何选择 key?
    最好使用每条数据的唯一标识符作为 key,比如 id、手机号、身份证号、学号等唯一值。

# 四、组件中的 data 函数

data 为什么是一个函数?

如果 data 是对象的话,对象属于引用类型,会影响到所有的实例。new Vue 的实例,是不会被复用的,所以为了保证组件不同的实例之间 data 不冲突,data 必须是一个函数。

# 五、Vue 组件的通信方式

  • 父子组件 props / $emit、$on:

    • 父 ──> 子:用 props,可以极大的提高组件的复用性
    • 子 ──> 父:用 $on、$emit,获取父子组件实例 parent、children Ref 获取实例的方式调用组件的属性或者方法。
    • 父 ──> 子孙:用 Provide、inject 官方不推荐使用,但是写组件库时很常用。
  • 兄弟组件 $emit / $on
    Event Bus 实现跨组件通信 Vue.prototype.$bus = new Vue() 自定义事件。

  • 跨级组件 Vuex: Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。

# 六、Vue 的生命周期

每个 Vue 实例在创建时都会经过一系列的初始化过程,vue 的生命周期钩子,就是说在达到某一阶段或条件时去触发的函数,目的就是为了完成一些动作或者事件。

  • create 阶段:vue 实例被创建。

    • beforeCreate创建前,vue 实例的挂载元素 el 和数据对象 data 都为 undefined,还未初始化。
    • created创建后,vue 实例的数据对象 data 中有值,el 还没有
  • mount 阶段: vue 实例被挂载到真实 DOM 节点。

    • beforeMount:vue 实例的 eldata 都初始化了挂载之前为虚拟 DOM 节点,data 尚未替换。
    • mounted: vue 实例挂载完成,data 成功渲染,此时可以操作 DOM
  • update 阶段:当 vue 实例里面的 data 数据变化时,触发组件的重新渲染。

    • beforeUpdate:更新前
    • updated:更新后
  • destroy 阶段:vue 实例被销毁。

    • beforeDestroy:实例被销毁前,此时可以手动销毁绑定的事件(通过 removeEventListener)。
    • destroyed:销毁后。vue 实例已经解除了事件监听以及 dom 的绑定,但是 dom 结构依然存在。