阿卡不拉阿卡不拉
Vue3
阿卡的博客
Vue3
阿卡的博客
  • Vue3

    • 快速入门

      • 搭建工程 👌
      • 模板语法
      • 响应式基础
      • 响应式常用 API
      • 计算属性
      • 类与样式绑定
      • 条件和列表渲染
      • 事件处理
      • 表单处理
      • 生命周期
      • 侦听器
      • 组件介绍
      • Props
      • 自定义事件
      • 组件v-model
      • 插槽
      • 前端路由介绍
      • KeepAlive内置组件
      • 状态管理库
      • 组件库介绍
    • 深入本质

      • 虚拟DOM本质
      • 模板的本质
      • 组件树和虚拟DOM树
      • 数据拦截的本质
      • 响应式数据的本质
      • 响应式的本质
      • 响应式和组件渲染
      • 实现响应式系统 1
      • 实现响应式系统 2
      • 图解EFFECT
      • 实现响应式系统 3
      • 手写computed
      • 手写watch
      • 指令的本质
      • 插槽的本质
      • v-model的本质
      • setup 语法标签
      • 组件生命周期
      • keepalive 生命周期
      • keepalive的本质
      • key的本质
    • 细节补充

      • 【Vue】属性透传
      • 【Vue】依赖注入
      • 【Vue】组合式函数 👌
      • 【Vue】自定义指令
      • 【Vue】插件
      • 【Vue】Transition
      • 【Vue】TransitionGroup
      • 【Vue】Teleport
      • 【Vue】异步组件
      • 【Vue】Suspense
      • 【Router】路由模式
      • 【Router】路由零碎知识
      • 【Router】路由匹配语法
      • 【Router】路由组件传参
      • 【Router】内置组件和函数
      • 【Router】导航守卫
      • 【Router】过渡特效
      • 【Router】滚动行为
      • 【Router】动态路由
      • 【State】通信方式总结
      • 【State】Pinia 自定义插件
      • 【场景】封装树形组件
      • 【场景】自定义 ref 实现防抖
      • 【场景】懒加载
      • 【场景】虚拟列表
      • 【场景】虚拟列表优化
      • 【第三方库】VueUse
      • 【第三方库】vuedragable
      • 【第三方库】vue-drag-resize
      • 【第三方库】vue-chartjs
      • 【第三方库】vuelidate
      • 【第三方库】vue3-lazyload
      • 【场景】Websocket 聊天室
      • 【Vite】✨ 认识 Vite👌
      • 【Vite】配置文件 👌
      • 【Vite】✨ 依赖预构建 👌
      • 【Vite】构建生产版本 👌
      • 【Vite】环境变量与模式
      • 【Vite】CLI
      • 【Vite】Vite 插件
  • 笔面试

    • HTML

      • HTML 面试题汇总
      • 文档声明
      • 语义化
      • W3C 标准组织
      • SEO
      • iframe
      • 微格式
      • 替换元素
      • 页面可见性
    • CSS

      • CSS 面试题汇总
      • CSS 单位总结
      • 居中方式总结
      • 隐藏元素方式总结
      • 浮动
      • 定位总结
      • BFC
      • CSS 属性计算过程
      • CSS 层叠继承规则总结
      • @import 指令
      • CSS3 calc 函数
      • CSS3 媒体查询
      • 过渡和动画事件
      • 渐进增强和优雅降级
      • CSS3 变形
      • 渐进式渲染
      • CSS 渲染性能优化
      • 层叠上下文
      • CSS3 遮罩
    • JavaScript

      • JavaScript 面试题汇总
      • ✨ let、var、const 的区别
      • JS中的数据类型
      • 包装类型
      • 数据类型的转换
      • 运算符
      • ✨ 原型链
      • ✨ this 指向
      • ✨ 垃圾回收与内存泄漏
      • ✨ 执行栈和执行上下文
      • ✨ 作用域和作用域链
      • ✨ 闭包
      • DOM 事件的注册和移除
      • DOM 事件的传播机制
      • 阻止事件默认行为
      • 递归
      • ✨ 属性描述符
      • class 和构造函数区别
      • 浮点数精度问题
      • 严格模式
      • ✨ 函数防抖和节流
      • ✨ WeakSet 和 WeakMap
      • ✨ 深浅拷贝
      • 函数柯里化
      • Node 事件循环
      • 尺寸和位置
    • 浏览器

      • 浏览器面试题汇总
      • ✨ 浏览器的渲染流程
      • ✨ 资源提示关键词
      • 浏览器的组成部分
      • IndexedDB
      • ✨ File API
      • ✨ 浏览器缓存
      • ✨ 浏览器跨标签页通信
      • Web Worker
    • 网络

      • 网络面试题汇总
      • 五层网络模型 👌
      • 常见请求方法 👌
      • ✨cookie👌
      • 面试题
      • 加密
      • ✨JWT👌
      • ✨ 同源策略及跨域问题 👌
      • 文件上传
      • ✨ 输入 url 地址之后
      • 文件下载
      • ✨ session
      • ✨ TCP
      • ✨ CSRF 攻击
      • ✨XSS 攻击 👌
      • ✨ 网络性能优化
      • 断点续传
      • 域名和 DNS
      • SSL、TLS、HTTPS 的关系
      • ✨ HTTP 各版本差异 👌
      • HTTP 缓存协议
      • ✨ WebSocket
    • 工程化

      • CMJ 和 ESM
      • npx
      • ESLint
    • Vue2

      • Vue 面试题汇总相关
      • 组件通信方式总结
      • 虚拟 DOM
      • v-model
      • 数据响应式原理
      • diff
      • 生命周期详解
      • computed
      • 过滤器
      • 作用域插槽
      • 过度和动画
      • 优化
      • keep-alive
      • 长列表优化
      • 其他 API
      • 模式和环境变量
      • 更多配置
      • 更多命令
      • 嵌套路由
      • 路由切换动画
    • Vue3

      • ✨ Vue3 整体变化 👌
      • ✨ Vue3 响应式变化 👌
      • ✨ nextTick 实现原理 👌
      • 两道代码题 👌
      • Vue 运行机制
      • 渲染器核心功能
      • 事件绑定与更新

✨ Vue3 整体变化 👌

面试题:说一下 Vue3 相比 Vue2 有什么新的变化?

主要有这么几类变化:

  1. 源码上的变化
  2. 性能的变化
  3. 语法 API 的变化
  4. 引入 RFC

源码优化

1. Monorepo

Vue2 的源码是托管在 src 目录下面的,然后依据功能拆分出了:

  • compiler:编译器
  • core:和平台无关的通用运行时代码
  • platforms:平台专有代码
  • server:服务端渲染相关代码
  • sfc:单文件组件解析相关代码
  • shared:共享工具库代码

但是各个模块无法单独抽离出来下载安装,也无法针对单个模块进行发布。

Vue3 源码工程的搭建改为了 Monorepo 的形式,将模块拆分到了不同的包里面,每个包有各自的 API、类型定义以及测试。这样一类粒度更细,责任划分更加明确。

image-20240821153730971

2. Typescript

  • Vue1.x:纯 JS 开发,无类型系统
  • Vue2.x:Flow.js,这是 Facebook 推出的类型系统
  • Vue3.x:TypeScript

性能优化

1. 源码体积缩小

  • 移除冷门功能:filter、inline-template 这些特性被去除掉了
  • 生产环境采用 rollup 进行构建,利用 tree-shaking 减少用户代码打包的体积

Rollup 是一个 JavaScript 模块打包器,专门为构建库和框架而设计。相比于 Webpack,Rollup 有以下特点:

  • 专注于 ES6 模块:Rollup 原生支持 ES6 模块语法,能够更好地进行静态分析
  • 更小的打包体积:通过更高效的 tree-shaking 和代码优化,生成的代码更加精简
  • 更适合库的构建:Rollup 生成的代码结构清晰,适合作为库发布
  • 插件生态丰富:拥有丰富的插件系统,可以处理各种资源类型

Tree-shaking 是一种通过静态分析来消除 JavaScript 中未使用代码的技术,其工作原理如下:

  • 静态分析:在编译时分析代码的依赖关系,识别哪些代码被实际使用
  • 死代码消除:移除那些从未被引用或调用的函数、变量和模块
  • ES6 模块支持:依赖于 ES6 的静态模块结构,CommonJS 等动态模块无法进行有效的 tree-shaking
  • 减少包体积:通过移除无用代码,显著减少最终打包文件的大小

在 Vue3 中,通过 Rollup + Tree-shaking 的组合:

// 用户只引入需要的功能
import { ref, computed } from "vue";
// 而不是引入整个 Vue 对象
import Vue from "vue"; // Vue2 的方式

这样可以确保最终打包时只包含用户实际使用的 Vue 功能,大大减少了包体积。

2. 数据劫持优化

  • Vue2.x:Object.defineProperty
  • Vue3.x:Proxy

3. 编译优化

模板本质上是语法糖,最终会被编译器编译为渲染函数。

  1. 静态提升
  2. 预字符串化
  3. 缓存事件处理函数
  4. Block Tree
  5. PatchFlag

4. diff 算法优化

  • Vue2.x: 双端 diff 算法
  • Vue3.x: 快速 diff 算法

语法 API 优化

1. 优化逻辑组织

  • Vue2.x: OptionsAPI,逻辑代码按照 data、methods、computed、props 进行分类
  • Vue3.x: OptionsAPI + CompositionAPI(推荐)
    • CompositionAPI 优点:查看一个功能的实现时候,不需要在文件跳来跳去;并且这种风格代码可复用的粒度更细
16028271652994

2. 优化逻辑复用

Vue2.x: 复用逻辑使用 mixin,但是 mixin 本身有一些缺点:

  • 不清晰的数据来源
  • 命名空间冲突
  • 隐式的跨 mixin 交流

参阅 《Vue3 - 细节补充 - 组合式函数》

3. 其他变化

Vue2

import App from "./App.vue";
// 通过实例化 Vue 来创建应用
new Vue({
    el: "#app",
    components: { App },
    template: "<App/>",
});
// or
new Vue({
    render: (h) => h(App),
}).$mount("#app");

思考 🤔:这种方式存在什么问题?

答案:这种方式缺点在于一个页面如果存在多个 Vue 应用,部分配置会影响所有的 Vue 应用。

<!-- vue2 -->
<div id="app1"></div>
<div id="app2"></div>
<script>
 Vue.use(...); // 此代码会影响所有的vue应用
 Vue.mixin(...); // 此代码会影响所有的vue应用
 Vue.component(...); // 此代码会影响所有的vue应用

new Vue({
   // 配置
 }).$mount("#app1")

 new Vue({
   // 配置
 }).$mount("#app2")
</script>

Vue3

import { createApp } from "vue";
import App from "./App.vue";

createApp(App).mount("#app");

这种方式就能很好的规避上面的问题:

<!-- vue3 -->
<div id="app1"></div>
<div id="app2"></div>
<script>
createApp(根组件).use(...).mixin(...).component(...).mount("#app1")
 createApp(根组件).mount("#app2")
</script>

面试题:为什么 Vue3 中去掉了 Vue 构造函数?

参考答案:

Vue2 的全局构造函数带来了诸多问题:

  1. 调用构造函数的静态方法会对所有 vue 应用生效,不利于隔离不同应用
  2. Vue2 的构造函数集成了太多功能,不利于 tree shaking,Vue3 把这些功能使用普通函数导出,能够充分利用 tree shaking 优化打包体积
  3. Vue2 没有把组件实例和 Vue 应用两个概念区分开,在 Vue2 中,通过 new Vue 创建的对象,既是一个 Vue 应用,同时又是一个特殊的 Vue 组件。Vue3 中,把两个概念区别开来,通过 createApp 创建的对象,是一个 Vue 应用,它内部提供的方法是针对整个应用的,而不再是一个特殊的组件。

引入 RFC

RFC 全称是 Request For Comments. 这是一种在软件开发和开源项目中常用的提案流程,用于收集社区对某个新功能、改动或标准的意见和建议。

RFC 是一种文档格式,它详细描述了某个特性或更改的提议,讨论其动机、设计选择、实现细节以及潜在的影响。在通过讨论和反馈达成共识后,RFC 会被采纳或拒绝。一份 RFC 主要的组成部分有:

  1. 标题:简短描述提案的目的。
  2. 摘要:简要说明提案的内容和动机。
  3. 动机:解释为什么需要这个提案,解决了什么问题。
  4. 详细设计:深入描述提案的设计和实现细节。
  5. 潜在问题和替代方案:讨论可能存在的问题和可以考虑的替代方案。
  6. 不兼容的变更:描述提案是否会引入不兼容的变更,以及这些变更的影响。

通过 RFC,Vue 核心团队能够更好地倾听用户的需求和建议,从而开发出更加符合社区期待的功能和特性。

面试题

说一下 Vue3 相比 Vue2 有什么新的变化?

参考答案:

Vue3 相比 Vue2 的整体变化,可以分为好几大类:

  1. 源码优化
  2. 性能优化
  3. 语法 API 优化
  4. 引入 RFC

源码优化体现在使用 typescript 重构整个 Vue 源码,对冷门的功能进行了删除,并且整个源码的结构变为了使用 Monorepo 进行管理,这样粒度更细,不同的包可以独立测试发布。用户也可以单独引入某一个包使用,而不用必须引入 Vue.

性能上的优化是整个 Vue3 最核心的变化,通过优化响应式、diff 算法、模板编译,Vue3 的性能相比 Vue2 有质的飞跃,基本上将性能这一块儿做到了极致。所以 Vue 的新项目建议都使用 Vue3 来搭建。

不过性能层面的优化,开发者无法直接的感知,开发者能够直接感知的,是语法上的优化,例如 Vue3 提出的 CompositionAPI,用于替代 Vue2 时期的 OptionsAPI. 这样能够让功能逻辑更加集中,无论是在阅读还是修改都更加方便。另外 CompositionAPI 让代码复用的粒度上更细,不需要再像以前一样使用 mixin 复用逻辑,而是推荐使用组合式函数来复用逻辑。

不过 Vue3 也不是完全废弃了 OptionsAPI,在 Vue3 中,OptionsAPI 成为了一种编码风格。

最后就是引入 RFC,尤雨溪和核心团队广泛采用了 RFC 的流程来处理新功能和重大更改。

最近更新:: 2025/7/16 12:57
Contributors: AK
Next
✨ Vue3 响应式变化 👌