Vue3基础与入门

字数:7887, 阅读时间:40分钟,点击阅读原文

从2013年12月8日发布第一个版本至今已,Vue已走过了快八个年头,你了解每个版本名字的意义吗?

版本号 名字 释义 时间
V0.9 Animatrix 黑客帝国动画版 2014.2.25
V0.10 Blade Runner 银翼杀手 2014.3.23
V0.11 Cowboy Bebop 星际牛仔 2014.11.7
V0.12 Dragon Ball 龙珠 2015.6.12
V1.0 Evangelion 新世纪福音战士 2015.10.27
V2.0 Ghost in the Shell 攻壳机动队 2016.9.30
V2.1 Hunter X Hunter 全职猎人 2016.11.22
V2.2 Initial D 头文字D 2017.2.26
V2.3 JoJo's Bizarre Adventure JoJo的奇妙冒险 2017.4.2
V2.4 Kill la Kill 斩服少女 2017.7.13
V2.5 Level E 灵异E接触 2017.10.13
V2.6 Macross 超时空要塞 2019.2.4
V3.0 One Piece 海贼王 2020.9.18
V3.1 Pluto 地上最强机器人 2021.6.8
V3.2 Quintessential Quintuplets 五等分的花嫁 2021.8.10

原来每个版本的名字都是以漫画命名,那么这些动漫,你看过几部呢?

那么接下来我们就重点聊聊Vue3.0。

缘起

一个新工具的出现,一定是为了解决已有工具存在的问题。我们常常听说Vue不适合开发大型复杂的项目,一个根本原因是 Vue 现有的 API 迫使我们通过选项组织代码,但是有的时候通过逻辑关系组织代码更有意义。另一个原因是目前缺少一种简洁且低成本的机制来提取和重用多个组件之间的逻辑。

那么接下来我们就来看看2.0的问题,以及Vue3是如何来解决的。

Option式组织代码的缺陷

options式组织代码,同一个功能分散在各个option中,导致在开发时需要在data、methods、computed等option横跳。

Vue3推出了CompositionApi,目的就是为了解决这个问题,它将分散在各个option中的逻辑组合到一起,下面我们对比看下:

Mixin的问题

对于复杂的功能,我们可能会想到使用Mixin来抽离到单独的文件。但是Mixin会有一些使用上的问题,比如命名冲突、属性来源不明确。

Vue3提出了Hooks的方式,可以将每个功能提取到hooks,一个hooks即是一个独立的函数,所以不会再有上述问题。

TypeScript支持的不健全

现在大型项目都会标配 TypeScript ,Vue 当前的 API 在集成 TypeScript 时遇到了不小的麻烦,其主要原因是 Vue 依靠一个简单的 this 上下文来暴露 property,我们现在使用 this 的方式是比较微妙的。(比如 methods 选项下的函数的 this 是指向组件实例的,而不是这个 methods 对象)。

换句话说,Vue 现有的 API 在设计之初没有照顾到类型推导,这使适配 TypeScript 变得复杂。

当前,大部分使用 TypeScript 的 Vue 开发者都在通过 vue-class-component 这个库将组件撰写为 TypeScript class (借助 decorator)。它必须依赖 decorator——一个在实现细节上存在许多未知数的非常不稳定的 stage 2 提案。基于它是有极大风险的。

Vue3中提出的方案更多地利用了天然对类型友好的普通变量与函数,完美享用类型推导,并且也不用做太多额外的类型标注。

这也同样意味着你写出的 JavaScript 代码几乎就是 TypeScript 的代码。即使是非 TypeScript 开发者也会因此得到更好的 IDE 类型支持而获益。

更好的响应式和性能

众所周知,Vue2的响应式是通过Object.defineProperty 是给对象的某个已存在的属性添加对应的 gettersetter,所以它只能监听这个属性值的变化,而不能去监听对象属性的新增和删除。在 Vue 2 的实现中,在组件初始化阶段把数据变成响应式时,遇到子属性仍然是对象的情况,会递归执行 Object.defineProperty 定义子对象的响应式,会有一些性能问题。而且还有一个常见的问题就是通过索引修改数组、为对象直接新增属性,并不会触发响应式更新机制。

而在Vue3中则使用了Proxy来实现响应式,其实并不是Proxy的本身的性能优于Object.defineProperty,其实恰恰相反。那么为什么还要选择Proxy呢?

因为 Proxy 本质上是对某个对象的劫持,这样它不仅仅可以监听对象某个属性值的变化,还可以监听对象属性的新增和删除。而且在实现响应式时,采用了延时处理的方式,当嵌套较深的对象时,只有在其属性被访问的时候才会处理属性的响应式,在性能上会有一定的提升。

支持全局API Treeshaking

Vue3重构了全局和局部的api,均采用ESModule的命名导出访问,支持tree-shaking,只打包使用到的功能,用户只为实际使用的功能买单,同时包体积的减少,也意味着性能的提升。

// vue2
import Vue from 'vue'

Vue.nextTick(() => {
  // 一些和DOM有关的东西
})
// vue3
import { nextTick } from 'vue'

nextTick(() => {
  // 一些和DOM有关的东西
})

以上就是Vue主要的变化,那么接下来我们就来看看有哪些新特性。

新特性与变更

接下来我们主要看一下一些非兼容的重大变更:

全局API

  • 支持多个应用根实例,防止全局配置污染

    // vue2
    // 这会影响两个根实例
    Vue.mixin({
      /* ... */
    })
    const app1 = new Vue({ el: '#app-1' })
    const app2 = new Vue({ el: '#app-2' })
    // vue3
    import { createApp } from 'vue'
    
    const app = createApp({})
    app.mixin({
      /* ... */
    })

    一些其他全局Api的变更详情请查阅全局 API

  • 全局 API重构为可Treeshaking

    import { nextTick } from 'vue'
    
    nextTick(() => {
      // 一些和DOM有关的东西
    })
    // **** 受影响的API
    // Vue.nextTick
    // Vue.observable (用 Vue.reactive 替换)
    // Vue.version
    // Vue.compile (仅完整构建版本)
    // Vue.set (仅兼容构建版本)
    // Vue.delete (仅兼容构建版本)

模板和指令相关

  • 更好用的v-model

替代原有的v-modelv-bind.sync修饰符,通过参数形式,支持使用多个v-model进行双向绑定。