Vue 面试题整理
呛再首 3/6/2023 其他面试
# vue3 与 vue2 的区别
- 性能比 vue2 快了 1.2-2 倍
- 使用 proxy 替代 Object.defineProperty 解决 vue2 中新增删除属性监听不到的问题,同时 proxy 支持对数组的监听,不需要像 vue2 对数组的方法拦截重写
- diff 算法优化:增加静态标记(patchflag),虚拟节点对比时,只会对这些标记了的节点对比
- 静态提升,vue3 对于不参与更新的元素,会做静态提升,只会创建一次,渲染时直接复用即可,不需要像 vue2 中每次更新都会重新创建并渲染
- 事件侦听器缓存:默认情况下 onClick 会被视为动态绑定,所以每次都会追踪它的变化,但是因为是同一个函数,所以不用追踪变化,直接缓存起来复用即可
- 更好的 treeSharking
- 组合式 api,hooks 更好的逻辑复用
- 更好的 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
2
provide 和 inject 绑定的数据是非响应式的,即如果提供的数据发生变化,不会触发子组件的重新渲染。
需要注意的是如果提供的数据是一个对象或数组,那么在子组件中修改该对象或数组的值会影响到父组件中的值。
- Vue3 中的 provide 和 inject
用法与 Vue 2.x 中基本相同,不过有以下几点变化:
- provide 和 inject 中可以使用 ref 和 reactive,这意味着提供的数据可以是响应式的。、
- inject 可以使用 default 来设置默认值。
父组件中使用 provide:
import { provide, ref } from 'vue'; export default { setup() { const message =
ref('Hello, World!'); provide('message', message); } }
1
2
2
子组件中使用 inject:
import { inject } from 'vue'; export default { setup() { const message =
inject('message', 'Default message'); console.log(message.value); // 输出
'Hello, World!' } }
1
2
3
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
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
2
3
4
5
6
7
8