Vue 面试题整理

3/6/2023 其他面试

# vue3 与 vue2 的区别

  1. 性能比 vue2 快了 1.2-2 倍
  2. 使用 proxy 替代 Object.defineProperty 解决 vue2 中新增删除属性监听不到的问题,同时 proxy 支持对数组的监听,不需要像 vue2 对数组的方法拦截重写
  3. diff 算法优化:增加静态标记(patchflag),虚拟节点对比时,只会对这些标记了的节点对比
  4. 静态提升,vue3 对于不参与更新的元素,会做静态提升,只会创建一次,渲染时直接复用即可,不需要像 vue2 中每次更新都会重新创建并渲染
  5. 事件侦听器缓存:默认情况下 onClick 会被视为动态绑定,所以每次都会追踪它的变化,但是因为是同一个函数,所以不用追踪变化,直接缓存起来复用即可
  6. 更好的 treeSharking
  7. 组合式 api,hooks 更好的逻辑复用
  8. 更好的 ts 支持

Object.defineProperty 会直接改变原始数据,而 Proxy 不会直接修改原始数据

# 对于虚拟dom(vnode)的理解

本质上是一个js对象,通过对象的形式来表示dom结构,配合不同的渲染工具,跨平台渲染成为可能(React Native 、ssr),直接操作真实的 DOM 会消耗大量的计算资源和内存开销,因此虚拟 DOM 的出现可以减少大量的 DOM 操作以及重排、重绘,提高了性能和用户体验。

优点:

  • 无需手动获取dom ,操作 DOM
  • 跨平台: 虚拟 DOM 本质上是 JavaScript 对象,而 真实DOM 与平台强相关,相比之下虚拟 DOM 可以进行更方便地跨平台操作,例如服务器渲染 (SSR,uniapp) 开发等等。
  • 虚拟DOM具有批处理和高效的Diff算法,最终表现在更新视图时只会渲染变化的部分,可以保证非常高效的渲染,优化性能 ;

虚拟dom真的比真实dom性能更好吗?

缺点:

  • **首次渲染大量 dom **时,由于多了一层虚拟 dom 的计算,会比直接使用 innerHTML 插入慢

# Vue 组件通讯有哪几种方式

  • props 和 $emit:父组件 props 传递数据给子组件,子组件通过 $emit 触发一个自定义事件,并且可以传递参数
  • $parent / $children: 可以通过 $parent 和 $children 来访问组件的父级和子级组件实例。
  • $refs: 可以使用 $refs 获取子组件实例或者 dom 元素。
  • eventBus 兄弟组件数据传递 这种情况下可以使用事件总线的方式
  • vuex 状态管理
  • provide 和 inject:父组件通过 provide 提供数据,子组件通过 inject 注入数据。这种方式适用于层级较深的组件之间的通讯。

# vue2 和 vue3 使用 provide 和 inject

  • vue 2 中

在父组件中,通过 provide 提供数据:

export default { provide: { message: 'Hello a, shuge!' } }
1

子组件中,可以通过 inject 来注入父组件提供的数据:

export default { inject: ['message'], mounted() { console.log(this.message); //
输出 'Hello, World!' } }
1
2

provide 和 inject 绑定的数据是非响应式的,即如果提供的数据发生变化,不会触发子组件的重新渲染。

需要注意的是如果提供的数据是一个对象或数组,那么在子组件中修改该对象或数组的值会影响到父组件中的值。

  • Vue3 中的 provide 和 inject

用法与 Vue 2.x 中基本相同,不过有以下几点变化:

  1. provide 和 inject 中可以使用 ref 和 reactive,这意味着提供的数据可以是响应式的。、
  2. inject 可以使用 default 来设置默认值。

父组件中使用 provide:

import { provide, ref } from 'vue'; export default { setup() { const message =
ref('Hello, World!'); provide('message', message); } }
1
2

子组件中使用 inject:

import { inject } from 'vue'; export default { setup() { const message =
inject('message', 'Default message'); console.log(message.value); // 输出
'Hello, World!' } }
1
2
3

上面的代码中,子组件使用 inject 注入了父组件提供的名为 message 的数据,并使用 default 设置了默认值为 'Default message'。在子组件中,可以通过 message.value 来访问 message 的值。

# 追问:Vue 2 中的 provide 和 inject 父组件更新,会触发子组件的重新渲染吗,为什么

不会,这是因为 Vue 2.x 中的响应式系统是基于 Object.defineProperty 实现的,而 provide 提供的数据是不会被 Vue 的响应式系统所追踪的,所以当提供的数据发生改变时,并不会触发子组件的重新渲染。

但是可以通过 Vue.observable() 方法将一个对象包装成响应式的对象,并将其作为 provide 提供的数据。例如:

import Vue from 'vue';

const parentDataObj = {
  count: 123,
};

export default {
  provide() {
    return {
      dataObj: Vue.observable(parentDataObj),
    };
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13

# vue3 中获取this

<script setup>
import {getCurrentInstance} from 'vue'

// proxy 就是当前组件实例,可以理解为组件级别的 this
const {proxy,appContext} from 'getCurrentInstance'

// 这个 global 就是全局实例
const global = appContext.config.globalProperties
1
2
3
4
5
6
7
8

# keep-alive 用过吗,作用是什么,实现原理能讲讲吗?

是 Vue 源码中实现的一个组件:一般和它搭配使用的有 component 动态组件或者是 router-view。
Last Updated: 5/23/2023, 9:25:41 PM