客户端框架简介
我们从对该领域的一般概述开始我们对框架的考察,考察了 JavaScript 和框架的简要历史,框架存在的原因以及它们带给我们的东西,如何开始思考选择要学习的框架以及客户端框架有哪些替代方案。
先决条件 | 熟悉核心 HTML、CSS 和 JavaScript 语言。 |
---|---|
目标 | 了解客户端 JavaScript 框架是如何诞生的,它们解决了什么问题,有哪些替代方案,以及如何选择一个框架。 |
简史
当 JavaScript 在 1996 年首次亮相时,它为一个原本由静态文档组成的 Web 添加了偶尔的交互性和兴奋感。Web 不仅仅成为了一个阅读内容的地方,而是做事情的地方。JavaScript 的受欢迎程度稳步上升。使用 JavaScript 的开发人员编写了工具来解决他们遇到的问题,并将它们打包成可重用包,称为库,以便他们可以与其他人分享他们的解决方案。这个共享的库生态系统帮助塑造了 Web 的发展。
现在,JavaScript 是 Web 的一个重要组成部分,在所有网站中使用率为 98%,而 Web 是现代生活中不可或缺的一部分。用户用文本、音频或视频聊天即时撰写论文、管理预算、流媒体音乐、观看电影并与他人进行远程交流。Web 使我们能够完成以前只能通过安装在我们计算机上的原生应用程序才能完成的事情。这些现代、复杂、交互式的网站通常被称为Web 应用程序。
现代 JavaScript 框架的出现使构建高度动态、交互式应用程序变得更加容易。框架是一个提供关于软件构建方式的意见的库。这些意见允许应用程序中的可预测性和同质性;可预测性允许软件扩展到庞大规模并仍然可维护;可预测性和可维护性对于软件的健康和寿命至关重要。
JavaScript 框架为现代 Web 上的大部分令人印象深刻的软件提供动力 - 包括您可能每天使用的许多网站。您当前正在阅读的 MDN Web 文档使用 React/ReactDOM 框架为其前端提供动力。
有哪些框架?
那里有很多框架,但目前被认为是“四大天王”的框架有以下几种。
Ember
Ember 最初于 2011 年 12 月发布,是 SproutCore 项目中开始的工作的延续。它是一个较旧的框架,用户比 React 和 Vue 等更现代的替代方案少,但由于其稳定性、社区支持和一些巧妙的编码原则,它仍然享有相当高的知名度。
Angular
Angular 是一个开源的 Web 应用程序框架,由 Google 的 Angular 团队以及个人和公司组成的社区领导。它是来自构建 AngularJS 的同一个团队的完全重写。Angular 于 2016 年 9 月 14 日正式发布。
Angular 是一个基于组件的框架,它使用声明式 HTML 模板。在构建时,框架的编译器透明地将模板转换为优化的 JavaScript 指令。Angular 使用 TypeScript,它是 JavaScript 的超集,我们将在下一章中更详细地介绍它。
Vue
React
Facebook 于 2013 年发布了 React。到那时,它已经使用 React 在内部解决了它的许多问题。从技术上讲,React 本身不是一个框架;它是一个用于渲染 UI 组件的库。React 与其他库结合使用来构建应用程序 - React 和 React Native 使开发人员能够构建移动应用程序;React 和 ReactDOM 使他们能够构建 Web 应用程序,等等。
由于 React 和 ReactDOM 通常一起使用,因此 React 在口头上被理解为一个 JavaScript 框架。在您阅读本模块时,我们将使用这种口头上的理解。
React 使用类似 HTML 的语法扩展了 JavaScript,称为 JSX。
为什么存在框架?
我们已经讨论了激发框架创建的环境,但实际上并没有讨论开发人员为什么需要创建它们。探索原因首先需要检查软件开发的挑战。
考虑一种常见的应用程序:一个待办事项清单创建器,我们将在以后的章节中使用各种框架来实现它。此应用程序应允许用户执行诸如渲染任务列表、添加新任务和删除任务等操作;并且它必须在可靠地跟踪和更新应用程序底层数据的同时执行此操作。在软件开发中,这种底层数据被称为状态。
我们的每一个目标在孤立的情况下理论上都很简单。我们可以迭代数据以渲染它;我们可以添加一个对象来创建一个新任务;我们可以使用一个标识符来查找、编辑或删除任务。当我们记住应用程序必须通过浏览器让用户完成所有这些操作时,就会出现一些裂痕。真正的问题是:每次更改应用程序的状态时,都需要更新 UI 以匹配。
我们可以通过查看待办事项应用程序的一个功能来检查这个问题的难度:渲染任务列表。
DOM 更改的冗长性
在浏览器中构建 HTML 元素并在适当的时间渲染它们需要令人惊讶的大量代码。假设我们的状态是一个结构类似于此的对象数组
const state = [
{
id: "todo-0",
name: "Learn some frameworks!",
},
];
我们如何向用户展示其中一个任务?我们希望将每个任务表示为一个列表项 - 一个位于无序列表元素(<ul>
)内的 HTML <li>
元素。我们如何制作它?这可能看起来像这样
function buildTodoItemEl(id, name) {
const item = document.createElement("li");
const span = document.createElement("span");
span.textContent = name;
item.id = id;
item.appendChild(span);
item.appendChild(buildDeleteButtonEl(id));
return item;
}
在这里,我们使用 document.createElement()
方法来创建我们的<li>
,以及更多行代码来创建它需要的属性和子元素。
前面的代码段引用了另一个构建函数:buildDeleteButtonEl()
。它遵循与我们用于构建列表项元素的模式类似的模式
function buildDeleteButtonEl(id) {
const button = document.createElement("button");
button.setAttribute("type", "button");
button.textContent = "Delete";
return button;
}
此按钮目前还没有任何作用,但稍后在我们决定实现删除功能时它将发挥作用。将在页面上渲染我们的项目的代码可能如下所示
function renderTodoList() {
const frag = document.createDocumentFragment();
state.tasks.forEach((task) => {
const item = buildTodoItemEl(task.id, task.name);
frag.appendChild(item);
});
while (todoListEl.firstChild) {
todoListEl.removeChild(todoListEl.firstChild);
}
todoListEl.appendChild(frag);
}
现在我们已经有了将近三十行代码专门用于UI - 仅用于在 DOM 中渲染内容 - 而且我们还没有添加任何可以稍后用来设置列表项样式的类!
直接使用 DOM,就像在这个例子中一样,需要了解有关 DOM 工作原理的很多知识:如何创建元素;如何更改其属性;如何将元素彼此放在一起;如何将它们放在页面上。这些代码都没有实际处理用户交互,也没有解决添加或删除任务的问题。如果我们添加这些功能,我们必须记住在正确的时间和正确的方式更新我们的 UI。
JavaScript 框架的创建是为了让这类工作变得更加容易 - 它们的存在是为了提供更好的开发人员体验。它们不会为 JavaScript 带来自带全新的力量;它们让您更容易访问 JavaScript 的力量,以便您能够为今天的 Web 构建应用程序。
如果您想查看本节中代码示例的实际应用,您可以查看 CodePen 上应用程序的工作版本,该版本还允许用户添加和删除新任务。
了解有关本节中使用的 JavaScript 功能的更多信息
另一种构建 UI 的方法
每个 JavaScript 框架都提供了一种以更声明式的方式编写用户界面。也就是说,它们允许您编写描述 UI 应该如何显示的代码,框架将在幕后完成 DOM 中的操作。
以重复的方式构建新 DOM 元素的 vanilla JavaScript 方法在乍一看很难理解。相比之下,以下代码块说明了您可能使用 Vue 来描述我们的任务列表的方式
<ul>
<li v-for="task in tasks" v-bind:key="task.id">
<span>{{task.name}}</span>
<button type="button">Delete</button>
</li>
</ul>
就是这样。此代码段将近三十行代码减少到了六行。如果这里的花括号和v-
属性对您来说很陌生,那没关系;您将在本模块的后面了解有关 Vue 特定语法的更多信息。这里要带走的是,这段代码看起来像它所代表的 UI,而 vanilla JavaScript 代码则没有。
感谢 Vue,我们不必为构建 UI 编写自己的函数;框架将以优化的、高效的方式为我们处理这些工作。我们在这里唯一需要做的是向 Vue 描述每个项目应该是什么样子。熟悉 Vue 的开发人员可以在加入我们的项目时快速了解正在发生的事情。Vue 并非孤军奋战:使用框架可以提高团队和个人效率。
在 vanilla JavaScript 中可以做类似的事情。模板字面量字符串 使得编写表示最终元素外观的 HTML 字符串变得容易。这对于我们待办事项应用程序这样简单的应用程序可能是一个有用的想法,但对于管理数千条数据记录的大型应用程序而言,它无法维护,并且可能在用户界面中渲染同样多的唯一元素。
框架提供的其他功能
让我们看看框架提供的其他优势。正如我们之前提到的,框架的优势可以在 vanilla JavaScript 中实现,但使用框架消除了必须自己解决这些问题的认知负担。
工具
由于本模块中的每个框架都有一个庞大而活跃的社区,因此每个框架的生态系统都提供了可以提高开发人员体验的工具。这些工具使添加诸如测试(以确保您的应用程序按预期运行)或 linting(以确保您的代码没有错误并且在样式上一致)等功能变得容易。
注意:如果您想了解有关 Web 工具概念的更多详细信息,请查看我们的 客户端工具概述。
隔间化
大多数主流框架鼓励开发者将用户界面的不同部分抽象成组件——可维护、可复用的代码块,这些代码块可以相互通信。与特定组件相关的代码可以保存在一个文件中(或几个特定文件中),这样你作为开发者就可以清楚地知道要在哪里进行更改。在一个普通的 JavaScript 应用中,你必须创建一套自己的约定来以高效、可扩展的方式实现这一点。许多 JavaScript 开发者,如果任其自由发挥,最终可能会将与 UI 的一部分相关的代码分散在整个文件中——甚至是在另一个文件中。
路由
网络最重要的功能是允许用户从一个页面导航到另一个页面——毕竟,它是一个相互链接的文档网络。当你点击这个网站上的一个链接时,你的浏览器会与服务器通信并获取新的内容来显示给你。在这个过程中,地址栏中的 URL 会发生变化。你可以保存这个新的 URL 并稍后返回该页面,或者与他人分享,以便他们可以轻松找到相同的页面。你的浏览器会记住你的导航历史记录,并允许你向前和向后导航。这被称为服务器端路由。
现代 Web 应用程序通常不会获取和渲染新的 HTML 文件——它们加载一个单一的 HTML 外壳,并不断更新其中的 DOM(称为单页面应用程序或SPA),而不会将用户导航到网络上的新地址。每个新的伪网页通常被称为一个视图,默认情况下,没有路由。
当 SPA 足够复杂并渲染足够的独特视图时,将路由功能引入你的应用程序非常重要。人们习惯于能够链接到应用程序中的特定页面,在他们的导航历史记录中前进和后退等,当这些标准网络功能被破坏时,他们的体验就会受到影响。当路由以这种方式由客户端应用程序处理时,它被恰当地称为客户端路由。
使用 JavaScript 和浏览器的原生功能来创建路由是可能的,但是流行的、积极开发的框架都有配套的库,这些库使路由成为开发过程中的一个更直观的组成部分。
使用框架时需要考虑的事项
成为一名有效的 Web 开发人员意味着使用最适合工作的工具。JavaScript 框架使前端应用程序开发变得容易,但它们不是解决所有问题的灵丹妙药。本节将讨论在使用框架时应该考虑的一些事项。请记住,你可能根本不需要框架——要小心不要仅仅为了框架而使用框架。
对工具的熟悉度
就像普通的 JavaScript 一样,框架需要时间学习,并且有自己的怪癖。在你决定为一个项目使用框架之前,请确保你有时间学习足够的特性,以便它对你有用,而不是对你不利,并确保你的团队成员也对它感到舒适。
过度设计
如果你的 Web 开发项目是一个包含几个页面的个人投资组合,并且这些页面几乎没有或根本没有交互功能,那么框架(及其所有 JavaScript)可能根本没有必要。也就是说,框架不是整体的,其中一些比其他框架更适合小型项目。在 Smashing Magazine 的一篇文章中,Sarah Drasner 撰写了关于Vue 如何取代 jQuery作为使网页的一部分交互式工具。
更大的代码库和抽象
框架允许你编写更具声明性的代码——有时甚至可以编写更少的代码——通过为你处理 DOM 交互,在幕后进行操作。这种抽象对于你作为开发者的体验来说很棒,但它不是免费的。为了将你编写的代码转换为 DOM 更改,框架必须运行自己的代码,这反过来会使你的最终软件更大,并且操作起来在计算上更加昂贵。
一些额外的代码是不可避免的,而支持树形摇动(在构建过程中删除应用程序中实际没有使用的任何代码)的框架将允许你保持应用程序的体积小,但这仍然是你需要在考虑应用程序性能时牢记的一个因素,特别是在网络/存储受限的设备上,例如手机。
框架的抽象不仅影响你的 JavaScript,也影响你与网络本身本质的关系。无论你如何为网络构建,最终结果,即用户最终交互的层,都是 HTML。用 JavaScript 编写整个应用程序可能会让你忽略 HTML 及其各种标签的目的,并导致你生成一个非语义且不可访问的 HTML 文档。事实上,有可能编写一个完全依赖 JavaScript 的脆弱应用程序,如果没有 JavaScript,该应用程序将无法正常工作。
框架不是我们问题的根源。在优先级错误的情况下,任何应用程序都可能变得脆弱、臃肿且不可访问。然而,框架确实放大了我们作为开发者的优先级。如果你优先考虑的是制作一个复杂的 Web 应用程序,那么很容易做到这一点。但是,如果你的优先级没有仔细保护性能和可访问性,框架会放大你的脆弱性、臃肿和不可访问性。现代开发者优先级,被框架放大后,在许多地方颠覆了网络结构。网络不再是一个健壮的、以内容为中心的文档网络,而是经常将 JavaScript 放在首位,将用户体验放在最后。
框架驱动的 Web 上的可访问性
让我们在上一节的基础上,再谈谈可访问性。使用户界面可访问始终需要一些思考和努力,而框架可能会使这个过程变得复杂。你通常必须使用高级框架 API 来访问本机浏览器功能,例如 ARIA 活动区域或焦点管理。
在某些情况下,框架应用程序会创建传统网站不存在的可访问性障碍。其中最大的例子是前面提到的客户端路由。
对于传统的(服务器端)路由,在网络中导航会产生可预测的结果。浏览器知道将焦点设置为页面顶部,辅助技术会宣布页面的标题。这些事情在你每次导航到新页面时都会发生。
对于客户端路由,你的浏览器不会加载新的网页,因此它不知道它应该自动调整焦点或宣布新的页面标题。框架作者投入了大量时间和精力来编写 JavaScript 以重新创建这些功能,即使这样,也没有任何框架能够完美地做到这一点。
总而言之,你应该从每个 Web 项目的开始就考虑可访问性,但要记住,如果不小心,使用框架的抽象代码库更容易出现重大的可访问性问题。
如何选择框架
本模块中讨论的每个框架都采用不同的方法来进行 Web 应用程序开发。每个框架都在不断改进或改变,并且都有其优缺点。选择合适的框架是一个依赖于团队和项目的流程,你应该自己进行研究,以发现最适合你需求的框架。也就是说,我们已经确定了一些可以用来更有效地研究你的选择的问题。
- 框架支持哪些浏览器?
- 框架使用哪些特定领域的语言?
- 框架是否有强大的社区和良好的文档(以及其他支持)?
本节中的表格概述了每个框架目前提供的浏览器支持,以及它可以使用的特定领域语言。
总的来说,特定领域语言 (DSL)是在软件开发的特定领域相关的编程语言。在框架的上下文中,DSL 是 JavaScript 或 HTML 的变体,它使使用该框架进行开发变得更容易。重要的是,没有任何框架要求开发者使用特定的 DSL,但它们几乎全部都是围绕着特定的 DSL 设计的。选择不使用框架的首选 DSL 将意味着你错过了原本可以改善开发者体验的功能。
在为任何新项目做出选择时,你应该认真考虑框架的支持矩阵和 DSL。不匹配的浏览器支持可能成为用户的一道障碍;不匹配的 DSL 支持可能成为你和你的团队成员的一道障碍。
框架 | 浏览器支持 | 首选 DSL | 支持的 DSL | 引用 |
---|---|---|---|---|
Angular | 现代 | TypeScript | 基于 HTML;TypeScript | 官方文档 |
React | 现代 | JSX | JSX;TypeScript | 官方文档 |
Vue | 现代(Vue 2 中的 IE9+) | 基于 HTML | 基于 HTML、JSX、Pug | 官方文档 |
Ember | 现代(Ember 版本 2.18 中的 IE9+) | Handlebars | Handlebars、TypeScript | 官方文档 |
注意:我们描述为“基于 HTML”的 DSL 没有官方名称。它们不是真正的 DSL,但它们是非标准的 HTML,因此我们认为它们值得强调。
框架是否有强大的社区?
这可能是最难衡量的指标,因为社区规模与易于访问的数字没有直接关系。你可以查看项目的 GitHub 星级数量或每周的 npm 下载量,以了解其受欢迎程度,但有时最好的方法是在几个论坛上搜索或与其他开发者交谈。这不仅关乎社区的规模,还关乎其欢迎和包容程度,以及现有文档的质量。
网络上的观点
不要仅仅相信我们的话——网络上到处都有讨论。维基媒体基金会最近选择使用 Vue 来构建其前端,并发布了框架采用意见征集 (RFC)。RFC 的作者 Eric Gardner 花时间概述了维基媒体项目的需要,以及为什么某些框架是团队的好选择。这个 RFC 是一个很好的例子,说明了你计划使用前端框架时应该为自己做哪种研究。
The State of JavaScript survey 是来自 JavaScript 开发者的一份有用的反馈集合。它涵盖了与 JavaScript 相关的许多主题,包括有关框架使用情况和开发者对框架情绪的数据。目前,有几年的数据可用,允许你了解框架的受欢迎程度。
Vue 团队已经全面比较了 Vue 与其他流行框架。这种比较可能存在一些偏差(他们也注意到了这一点),但它仍然是一个宝贵的资源。
客户端框架的替代方案
如果你正在寻找可以加快 Web 开发流程的工具,并且你知道你的项目不需要密集的客户端 JavaScript,那么你可以使用其他几种构建 Web 的解决方案。
- 内容管理系统
- 服务器端渲染
- 静态网站生成器
内容管理系统
服务器端渲染
服务器端渲染 (SSR) 是一种应用程序架构,其中服务器负责渲染单页应用程序。这与客户端渲染相反,客户端渲染是构建 JavaScript 应用程序最常见和最直接的方式。服务器端渲染对客户端设备更容易,因为您只需将渲染后的 HTML 文件发送给他们,但与客户端渲染的应用程序相比,它可能很难设置。
本模块中介绍的所有框架都支持服务器端渲染和客户端渲染。查看 Next.js(用于 React)、Nuxt(用于 Vue - 是的,这很令人困惑,而且这两个项目没有关系!)、FastBoot(用于 Ember)和 Angular Universal(用于 Angular)。
注意:一些 SSR 解决方案是由社区编写和维护的,而另一些则是由框架维护者提供的“官方”解决方案。
静态网站生成器
静态网站生成器 是动态生成多页网站的所有网页(包括任何相关的 CSS 或 JavaScript)的程序,以便它们可以发布到任何数量的地方。例如,发布主机可以是 GitHub Pages 分支、Netlify 实例或您选择的任何私有服务器。这种方法有很多优点,主要围绕性能(用户的设备不会使用 JavaScript 构建页面;它已经完成)和安全性(静态页面攻击向量更少)。这些网站仍然可以在需要时使用 JavaScript,但它们并不依赖于它。静态网站生成器需要时间学习,就像任何其他工具一样,这可能成为开发过程的障碍。
静态网站可以拥有任意数量的唯一页面。就像框架使您能够快速编写客户端 JavaScript 应用程序一样,静态网站生成器为您提供了一种快速创建您原本需要单独编写的 HTML 文件的方法。与框架一样,静态网站生成器允许开发人员编写组件来定义网页的通用部分,并将这些组件组合在一起以创建最终页面。在静态网站生成器的上下文中,这些组件称为模板。由静态网站生成器构建的网页甚至可以是框架应用程序的所在地:例如,如果您希望静态生成的网站的某个特定页面在用户访问该页面时启动 React 应用程序,您可以这样做。
静态网站生成器已经存在了相当长的时间,并且它们一直在不断优化和创新。存在各种选择,包括 Astro、Eleventy、Hugo、Jekyll 和 Gatsby,它们建立在各种技术栈之上并提供独特的特性。其他选项,例如 Docusaurus 和 VitePress,使用客户端框架而不是模板,但生成类似的优化静态文件。
如果您想了解有关静态网站生成器的更多信息,请查看 Tatiana Mac 的 Eleventy 入门指南。在该系列的第一篇文章中,他们解释了什么是静态网站生成器,以及它如何与其他发布网站内容的方式相关。