Vue3新特性
狐七 3/16/2022 vue
# 1. Vue2和Vue3的区别
查看答案
- 源码:
- Vue3使用 TypeScript 重写了代码,提升了可维护性。
- 项目采用 monorepo 的方式组织项目结构,把不同的模块单独提取到独立的包中,依赖关系明确,每个模块都可以单独使用、单独测试、单独发布。
- 通过 Proxy 重写了响应式系统,解决了数组下标和长度修改、对象删除和单独属性赋值导致的丢失响应式的问题,还避免了初始化的时候递归遍历所有data带来的性能问题,因为Proxy在嵌套对象的时候,只有在访问某个属性的时候才会去递归处理下一级属性。
- 重写 虚拟DOM 。
- 新增功能:
- 添加了 Composition API ,是解决使用2.x开发大型项目时遇到超大组件,使用options API不好拆分和重用的问题。 Vue3在Vue2的 自定义指令 中修改了钩子函数的名称,与组件的钩子函数名称保持了一致比较容易理解,但是与组件钩子函数的执行方式很不一样。Vue2.x是在bind和update的时候执行,Vue3.0是在mounted和updated的时候执行。
- 优化编译过程:
- Vue3中 标记和提升所有的静态节点,diff的时候值需要对比动态节点的内容。Vue2.x的时候首先要在构建过程中将模板编译成render函数,在编译的时候会编译静态根节点和静态节点,diff的过程会跳过静态根节点,但是静态节点还需要在进行diff,这个过程没有被优化。
- Vue3中新引入了 Fragments —— 片段特性 ,模板中不需要再创建唯一的一个根节点,模板里面可以直接放文本内容或者很多同级的标签。
- Vue3中通过 patchFlag标记动态节点 ,大大提升了虚拟DOM的diff的性能。vue2中重新渲染的时候需要去重新创建新旧VNode,除了会跳过静态根节点,会对比剩下的每一个新旧VNode,哪怕这个节点什么都没有做。
- Vue3中添加了 cacheHandlers —— 缓存事件处理函数 ,绑定就永远不会发生变化,除非在运行函数的时候,会获取最新的handler
- Vue3使用 按需引入 ,这样可以减少不必要的引用。
- 源码体积优化:
- Vue3.0中 移除了一些不常用的API ,可以让最终的体积变小。移除的filter可以使用methods或者计算属性实现。
- Vue3.0对 Tree-shaking 的支持更好,依赖ES Module,通过编译阶段的静态分析,找到没有引入的模块,在打包的时候直接过滤掉,让打包之后的体积更小。
- Vue3不再构建 UMD模块化 的方式,因为UMD模块化的方式会让代码有更多的冗余,3中把cjs,es module和自执行函数 的方式分别打包到了不同的文件中。
- 新工具:
- 新增官方开发工具 Vite ,在开发阶段我们测试项目不需要打包,可以直接运行项目,提升开发效率。
# 2. Composition API 和 Options API的区别
查看答案
# Options API
包含一个描述组件选项(data、methods、props等)的对象来创建组件的方式
# Composition API
Vue3.0新增API,是一组基于函数的API,可以更灵活的组织组件的逻辑
# Composition API 解决了 Options API 的什么问题?
- 我们看别人的组件,同一个功能可能会同时涉及data、methods、props、mounted等选项,其代码会被拆分到不同的选项,项目开发属性需要来回拖动,且增加一个小功能要同时修改多个选项。
- 使用这种API还难以提取组件中可重用的逻辑,虽然有mixin混入机制,可以把重复的代码提取并重用,但是mixin使用的过程也有问题,例如:命名冲突或者数据来源不清晰等。
# 3. 说说 Vue3 用 Proxy 实现响应式的优化点在哪里?
查看答案
Vue2的响应式实现的和核心是defineProperty,在初始化的时候遍历data中的所有成员,通过defineProperty,把对象的属性转化成getter和setter。而Vue3用proxy重写了响应式系统。
- proxy的性能本身比defineProperty要好
- proxy对代理对象可以有更强大的功能,可以拦截属性的访问、赋值、删除等操作
- 初始化的时候defineProperty需要对data的每一个属性递归绑定响应式,即使没使用也做了响应式的处理,proxy不需要初始化的时候遍历所有的属性,有嵌套对象的时候,只有在访问某个属性的时候才会去递归处理下一级的属性。
- Vue2的对象动态添加属性需要调用Vue.set方法,而使用proxy对象默认可以监听到动态添加的属性。
- defineProperty无法监听删除的属性,proxy可以
- defineProperty监听不了数组的索引和length属性,proxy可以
# 4. 为什么不在Vue2.x的时候使用proxy
查看答案
当时es6的普及性不高,proxy的兼容性不好,2.x尽量做到向下兼容。到了3版本的时候,是一个大的版本升级,浏览器对proxy的兼容性越来越好。
# 5. 说说Vue.mixin的问题
查看答案
- 命名冲突
- 数据来源不清晰
# 6. Vue3有哪些语法?
查看答案
- createApp:创建Vue对象app,没有使用$开头,以后基本不用给这个对象新增成员,app.mount和app.unmount替换$mount和$destroy方法。
- setup:composition API的入口。
- setup是在beforeCreate和created两个函数中间,也就是props被解析完毕,在组件实例被创建之前执行的。
- 无法通过this访问实例,也无法访问组件中的data,methods,computed。
- reactive:将对象转化成响应式对象,并且该对象的嵌套属性也应该成为响应式对象。
- ref:将所有类型转化成响应式对象
- toRefs:将reactive生成的proxy对象转化成ref对象,参数不是proxy对象直接返回
- effect:effect函数,定义的时候首次会执行,每次修改里面的响应式数据,函数就会再次调用
- watch:和之前的$watch和选项中的watch一样,侦听器
- watchEffect:是watch函数的简化版本,也用来监视数据的变化,内部实现和watch调用的是同一个函数。WatchEffect接收一个函数作为参数,监听函数内响应式数据的变化,它会立即执行一次这个函数。
# 7. ref 和 reactive 的区别是什么?
查看答案
# 入参和返回值
- reactive只能把对象转换成响应式对象,不能转基本数据类型。原理是内部创建拦截器对象 handler,设置 get/set/deleteProperty,并且返回一个 Proxy 对象。
- ref的参数:
- 如果是对象且ref创建的对象,直接返回
- 如果是普通对象就用reactive创建并返回
- 如果是原始值,就创建一个有value属性的对象返回
# 访问
- reactive可以直接访问
- ref需要访问其value属性,如果一个对象成员很多的时候,ref并不方便
# 丢失响应式
- reactive返回的对象重新赋值丢失响应式,不可以解构,如果要解构的话需要toRefs函数
- 返回的对象重新赋值成对象也是响应式的,可以解构使用
# 8. Vue3的生命周期钩子函数有哪些?
查看答案
setup是在beforeCreate和created两个函数中间执行的
- onBeforeMount
- onMounted
- onBeforeUpdate
- onUpdated
- onBeforeUnmount
- onUnmounted
- onErrorCaptured
- onRenderTracked —— 调用render的时候触发,首次调用render会触发
- onRenderTriggered —— 调用render的时候触发,首次调用render不会触发
# 9. Vue3中对于虚拟DOM的优化有哪些?
查看答案
# patch flag
- 将动态的节点使用patch flag进行标记,注释内容会告诉我们只是文本改变了,还是其某个属性也有变化。
- Vue3 在 Vdom 的更新时,只会关注它有变化的部分。这样的优化使 Vue3 既跳出了 Vdom 的性能瓶颈,又依然保留了可以手写 render function 的灵活性。相当于 Vue3 既有 react 的灵活性,又有基于模板的性能保证。——尤雨溪
# 静态提升(静态树的提升和静态属性的提升)
- 处理后的 Vdom 都在 _createBlock 函数之中,而所有的静态元素都被放在了 _createBlock 函数之外了,也就是说他们只会在页面初始的时候被渲染一次,而在更新的时候,静态元素是不需要再关注的。
# 事件侦听器缓存
- 当页面在不断的更新的时候,事件侦听器并不会重复地销毁再创建,而是以缓存的形式存在。
- Vue3 在 @click 中,直接手写内联函数也会被缓存起来,这一点是 react 做不到的。
- 在 Vue3 中父组件的更新并不会直接触发子组件的更新,使得事件侦听器缓存在组件的层面可以提现出来更高的价值。