前言
工欲善其事,必先利其器 --《论语》
在如今被三大框架支配的前端领域,已经很少有人不知道 Vue 了。2014 年,前 Google 工程师尤雨溪发布了所谓的渐进式(Progressive)前端应用框架 Vue,其简化的模版绑定和组件化思想给当时还是 jQuery 时代的前端领域产生了积极而深远的影响。Vue 的诞生,造福了那些不习惯 TS 或 JSX 语法的前端开发者。而且,Vue 较低的学习门槛,也让初学者非常容易上手。这也是为什么 Vue 能在短时间内迅速推广的重要原因。从 State of JS 的调查中可以看到,Vue 的知名度接近 100%,而且整体用户满意度也比较高。
Vue 既强大又易学,这是不是意味着 Vue 是一个完美框架呢?很遗憾,答案是否定的。虽然 Vue 的上手门槛不高,灵活易用,但是这种优势同时也成为了一把双刃剑,为构建大型项目带来了一定的局限性。很多用 Vue 2 开发过大型项目的前端工程师对 Vue 是又爱又恨。不过,随着 Vue 3 的发布,这些开发大型项目时凸显出来的劣势得到了有效解决,这让 Vue 框架变得非常全能,真正具备了跟 “前端框架一哥” React 一争高下的潜力。Vue 3 究竟带来了什么重要的新特性呢?本篇文章将对此进行详细介绍。
Vue 概览
Vue 是前 Google 工程师尤雨溪于 2013 年开发、2014 年发布的前端框架。关于 Vue 的具体定义,这里摘抄 Vue 官网里的介绍。
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
渐进式框架
很多人可能不理解渐进式框架(Progressive Framework)的含义。这里简单解释一下。渐进主要是针对项目开发过程来说的。传统的软件项目开发通常是瀑布流式(Waterfall)的,也就是说,软件设计开发任务通常有明确的时间线,任务与任务之间有明确的依赖关系,这意味着项目的不确定性容忍度(Intolerance to Uncertainty)比较低。这种开发模式在现代日趋复杂而快速变化的商业情景已经显得比较过时了,因为很多时候需求是不确定的,这会给项目带来很大的风险。
而渐进式框架或渐进式开发模式则可以解决这种问题。以 Vue 为例:项目开始时,功能要求简单,可以用一些比较简单的 API;当项目逐渐开发,一些公共组件需要抽象出来,因此用到了 Vue 的组件化功能;当项目变得非常大的时候,可以引用 Vue Router 或者 Vuex 等模块来进一步工程化前端系统。看到了么,这样一来,开发流程变得非常敏捷,不用提前设计整个系统,只用按需开发,因此可以快速开发产品原型以及扩展到生产系统。
框架特性
Vue 是利用模版语法来渲染页面的,这也称做声明式渲染。Vue 好上手的重要原因也是因为这个,因为它符合了前端开发者的习惯。例如下面这个例子。
可以看到,el 指定 Vue 实例绑定的元素,data 中的 message 与 DOM 元素的内容进行绑定。只需要操控 JS 中的数据,HTML 内容也会随之改变。
另外,Vue 将 HTML、CSS、JS 全部整合在同一个文件 .vue 中,以组件化应用构建的方式来组织代码,从语法特性上鼓励 “高内聚、低耦合” 的设计理念,让代码组织变得更加合理,提升了可读性与逻辑性。下面是一个官方网站给出的基础 .vue 文件例子。
{{ greeting }} World!
组件的骨架(HTML)、样式(CSS)和数据或操作(JS)都在同一个地方,开发者需要思考如何将整个系统拆分成更小的子模块,或者组件。这对于构建大型项目是非常有帮助的。
其实,除了上述两个特点,Vue 还有很多其他的实用特性,但限于篇幅的原因,我们这里不详细解释了。感兴趣的读者可以去[官方网站深入了解。
框架缺点
没有什么东西是完美的,Vue 同样如此。当 Vue 的知名度和用户量不断增加时,一些前端开发者开始抱怨 Vue 的灵活性太高导致构建大型项目时缺少约束,从而容易产生大量 bug。甚至使用 Vue 生态圈里的状态管理系统 Vuex 也无法有效解决。关于 Vue 是否适合大型项目的问题,网上有不少争论,甚至尤大本人都亲自上知乎参与了讨论(吃瓜传送门)。
客观来讲,Vue 虽然具有较低的上手门槛,但这并不意味着 Vue 不适合开发大型项目。然而,我们也必须承认大型项目通常要求较高的稳定性和可维护性,而 Vue 框架较高的灵活性以及缺少足够的约束让其容易被经验不足的前端开发者所滥用,从而产生臭不可闻的、难以直视的 “屎山” 代码。其实,代码可维护性并不强制要求较低的灵活性与自由度,只是这种自由可能会对项目的整体稳定带来风险。
Vue 作者尤雨溪其实很早就注意到这个问题,因此才会打算从底层重构 Vue,让其更好的支持 TypeScript。这就是 2020 年 9 月发布的 Vue 3。
Vue 3 新特性
Vue 3 有很多实用的新特性,包括TS 支持、组合式 API 以及 Teleport 等等。本文不是关于 Vue 3 的参考文,因此不会介绍其中全部的新特性,我们只会关注其中比较重要的特性,尤其是能加强代码约束的 TypeScript(简称 TS)。
TS 支持
技术上来说,TS 支持并不是 Vue 3 的新特性,因为 Vue 2 版本就已经能够支持 TS 了。但 Vue 2 版本的 TS 支持,是通过 vue-class-component 这种蹩脚的装饰器方式来实现的。笔者对 “蹩脚” 这个评价深有体会,因为笔者曾经迁移过 Vue 2 版本的生产环境项目,最后发现收益并不高:语法有很大的不同,花了大量时间来重构,发现只提升了一些代码的规范性,但是代码整体变得更臃肿了,可读性变得更差。
而在 Vue 3 中,TS 是原生支持的,因为 Vue 3 本身就是用 TS 编写的,TS 成为了 Vue 3 中的 “一等公民”。TS 支持在我看来是 Vue 3 中最重要的特性,特别是对构建大型前端项目来说。为什么说它重要?因为 TS 有效的解决了前端工程化和规模化的问题,它在代码规范和设计模式上极大的提高代码质量,进而增强系统的可靠性、稳定性和可维护性。关于 TS 的重要性,笔者在该公众号前一篇文章《为什么说 TypeScript 是开发大型前端项目的必备语言》已经做了详细介绍,感兴趣的读者可以继续深入阅读一下。
Vue 3 定义了很多 TS 接口(Interface)和类型(Type),帮助开发者定义和约束各个变量、方法、类的种类。下面就是一个非常基础的例子。
import { defineComponent } from 'vue'
// 定义 Book 接口
interface Book {
title: string author: string year: number
} // defineComponent 定义组件类型
const Component = defineComponent({
data() { return {
book: {
title: 'Vue 3 Guide',
author: 'Vue Team',
year: 2020 } as Book // as Book 是一个断言
}
}
})
上述代码通过 defineComponent 定义了组件类型,而在 data 里定义了内部变量 book,这个是通过接口 Book 来定义的。因此,其他组件在引用该组件时,就能够自动推断出该组件的类型、内部变量类型,等等。如果引用方与被引用方的任何一个接口、变量类型不一致,TS 就会抛错,让你可以提前规避很多错误。
虽然 Vue 3 在传统定义 Vue 实例方式中(Options API)能够很好的支持 TS,但是我们更推荐用 TS 配合另一种新的方式来定义 Vue 实例,也就是接下来要介绍的组合式 API(Compositional API)。
组合式 API
https://segmentfault.com/a/1190000039278732?utm_source=tag-newest
https://segmentfault.com/a/1190000039291984?utm_source=tag-newest
组合式 API 的诞生是来自于大型项目中无法优雅而有效地复用大量组件的问题。如果你已经了解 Vue,你或许应该知道之前版本的 Vue 实例中包含很多固定的 API,包括 data、computed、methods 等。这种定义方式有个比较突出的问题:它将 Vue 实例中的功能按照类型的不同分别固定在不同的 API 中,而没有根据实际的功能来划分,这将导致一个复杂组件中的代码变得非常散乱,就像如下这张图一样。