前端面试系列-Vue篇
说说vue2和vue3的区别
-
响应式:Vue3使用
Proxy
,Vue2使用Object.defineProperty
; -
Vue3 引入了
Composition API
: 如reactive
、ref
、computed
和watchEffect
; -
生命周期:
-
Vue3:
onBeforeMount
、onMounted
、onBeforeUpdate
、onUpdated
、onBeforeUnmount
和onUnmounted
-
Vue2:
beforeCreate
、created
、beforeMount
、mounted
、beforeUpdate
、updated
、beforeDestroy
和destroyed
- Vue3支持:
Fragment
、Teleport
和Suspense
-
Fragment
(允许组件有多个根节点) -
Teleport
(提供了一种方式将子节点渲染到 DOM 中的其他部分) -
Suspense
(用于异步组件的加载状态管理)
Vue 3 的 Composition API 相比 Vue 2 的 Options API 在实际开发中有哪些优势和劣势?
优势
- 更好的逻辑复用:
- Composition API 允许开发者将组件逻辑提取到可复用的函数中,这些函数可以在多个组件之间共享,而不需要使用 mixins 或高阶组件。
- 更灵活的代码组织:
- 使用 Composition API,开发者可以根据自己的喜好和需求自由地组织代码,而不是按照 data、methods、computed 等严格的选项来组织。
- 更易于理解的代码:
- 对于复杂的组件,Composition API 可以使代码更加模块化,每个功能块都相对独立,这使得代码更易于阅读和维护。
- 支持 TypeScript:
- Composition API 与 TypeScript 的集成更加自然,提供了更好的类型推断和类型检查,这对于大型项目和团队协作非常有利。
- 避免命名冲突:
- 在 Options API 中,如果使用了多个 mixins,可能会遇到命名冲突的问题。而 Composition API 通过函数来组织逻辑,可以避免这种情况。
- 更细粒度的响应式控制:
- Composition API 提供了更细粒度的响应式控制,允许开发者精确地指定哪些数据是响应式的,以及如何响应数据变化。
劣势
- 学习曲线:
- 对于习惯了 Options API 的开发者来说,Composition API 可能需要一些时间来学习和适应。
- 代码复杂性:
- 在某些情况下,Composition API 可能会导致代码变得更加复杂,特别是当组件逻辑非常琐碎时。
- 模板中的作用域问题:
- 在 Composition API 中,使用 setup() 函数返回的响应式引用需要在模板中使用 .value 来访问其值,这可能会让模板看起来不那么直观。
- 调试难度:
- 由于 Composition API 允许更灵活的代码组织,这可能会使得调试变得更加困难,特别是在逻辑分散在多个函数中时。
- 兼容性问题:
- 如果项目需要同时支持 Vue 2 和 Vue 3,那么可能需要在两个版本之间进行兼容性处理,这可能会增加开发和维护的复杂性。
- 模板中无法直接访问 this:
- 在 Composition API 中,this 上下文不再存在,这意味着无法直接在模板中访问组件实例的属性和方法
Vue3的Fragment
、Teleport
、Suspense
功能在实际开发中有哪些应用场景?
Fragment(允许组件有多个根节点)
Fragment 允许组件有多个根节点,而不是强制组件必须有一个单一的根节点。
应用场景:
-
布局组件
:在构建布局组件时,可能需要多个根元素来分别表示不同的部分(例如,一个用于导航栏,另一个用于内容区域)。 -
表单组件
:在表单中,可能需要将标签和输入框作为单独的根节点处理,而不是将它们包装在一个容器中。 -
避免不必要的DOM元素
:在某些情况下,开发者可能希望避免添加额外的容器元素,以减少 DOM 的复杂性和提高渲染性能。
Teleport
Teleport 是一个内置组件,它允许将子节点渲染到 DOM 中的其他部分,而不是作为组件的直接子节点。
应用场景:
模态框和对话框:模态框和对话框通常需要被渲染在页面的顶层,以确保它们能够覆盖其他内容。Teleport 可以将这些组件的内容移动到 <body>
标签或其他容器的末尾。
下拉菜单和弹出菜单:类似于模态框,下拉菜单和弹出菜单也需要在视觉上覆盖其他元素。使用 Teleport,这些组件可以被渲染到页面的更高级别。
全局通知和提示:全局通知(如 toast 通知)通常需要出现在页面的特定位置,如屏幕的角落。Teleport 可以将这些通知渲染到页面的任何位置。
避免样式问题:在某些情况下,由于 CSS 样式的层叠和继承,子组件可能无法正确地显示。使用 Teleport,可以将子组件移动到不同的 DOM 层次,以解决样式问题。
Suspense
Suspense
是一个内置组件,用于处理异步组件的加载状态。
- 应用场景:
-
异步组件加载
:在加载大型或异步的组件时,Suspense 允许开发者指定一个加载状态,从而提供更好的用户体验。例如,可以在组件加载时显示一个加载指示器。 -
数据预加载
:在应用启动时预加载某些数据,Suspense 可以在数据加载完成之前显示一个占位符或加载状态。 -
路由级加载状态
:在单页面应用(SPA)中,Suspense 可以用于处理路由变化时的组件加载状态,提供统一的加载体验。
Object.defineProperty
和proxy
的区别
Vue2响应式如何实现?
Vue.js 是采用
数据劫持
结合发布者-订阅者模式
的方式,通过Object.defineProperty()
来劫持各个属性的setter
和getter
,在数据变动时发布消息给订阅者,触发相应的监听回调。
主要分为以下几个步骤:
- 数据劫持(Data Hijacking): 当 Vue 实例被创建时,它会遍历
data
属性中的所有属性,并使用Object.defineProperty()
方法将它们转换为getter
和setter
。这样,
-
当数据被读取时,
getter
将被触发; -
当数据被修改时,
setter
将被触发;
这是 Vue 实现响应式系统的基础。
-
依赖收集(Dependency Collection): 当模板被编译时,将模板中的变量替换成数据,然后初始化渲染页面视图。Vue会解析表达式并记录哪些数据属性被引用。这些依赖关系会被收集在订阅者
Watcher
对象中。Watcher 是 Vue 中的一个核心概念,它负责观察数据的变化,并在变化时触发更新。 -
Watcher监听器: 是
Observer
和Compile(解析器)
之间通信的桥梁,主要做的事情是:-
在自身实例化时往属性订阅器(dep)里面添加自己
-
自身必须有一个
update()
方法 -
待属性变动
dep.notice()
通知时,能调用自身的update()
方法,并触发Compile中绑定的回调,则功成身退。
-
-
MVVM作为数据绑定的入口,整合
Observer
、Compile
和Watcher
三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到:数据变化
->视图更新
、视图交互变化(input)
->数据model变更
的双向绑定效果。