当前世界中,技术发展非常迅速并且变化迅速,开发者需要更多的开发工具来解决不同的问题。本文就对于当下主流的前端开发技术React、Vue、Angular这三个框架做个相对详尽的探究,目的是为了解开这些前端技术的面纱,看看各自的庐山真面目。
React(也被称为React.js或ReactJS)是一个用于构建用户界面的JavaScript库。它由Facebook和一个由个人开发者和公司组成的社区来维护。
React可以作为开发单页或移动应用的基础。然而,React只关注向DOM渲染数据,因此创建React应用通常需要使用额外的库来进行状态管理和路由,Redux和React Router分别是这类库的例子。
下面是一个简单的React在HTML中使用JSX和JavaScript的例子。
Greeter函数是一个React组件,它接受一个属性问候语。变量App是Greeter组件的一个实例,其中问候语属性被设置为 "Hello World!"。然后,ReactDOM.render方法将我们的Greeter组件渲染在DOM元素(id为 myReactApp)中。
在web浏览器中显示时,结果将是:
React代码由称为组件的实体组成。组件可以使用React DOM库渲染到DOM中的一个特定元素。当渲染一个组件时,可以传入被称为 "props "的值。
React中声明组件的两种主要方式是通过功能函数组件和基于类的组件。
功能组件是用一个函数声明,用来返回一些JSX。
基于类的组件是使用ES6类来声明的。它们也被称为 "有状态 "组件,因为它们的状态可以在整个组件中保持,并且可以通过props传递给子组件。
另一个值得注意的特点是React使用了虚拟文档对象模型,也就是虚拟DOM。React创建了一个内存中的数据结构缓存,计算得出变化差异,只渲染实际变化的子组件, 从而高效地更新浏览器显示的DOM。
生命周期方法是指在组件的生命周期内,允许在设定的点执行代码的hooks处理函数。
shouldComponentUpdate允许开发者在不需要渲染的情况下,通过返回false来防止不必要的重新渲染组件。
componentDidMount是在组件 "挂载 "后调用的(组件已经在用户界面中创建了,通常是通过将其与DOM节点关联起来)。这通常用于通过API从远程数据源触发数据加载。
componentWillUnmount是在组件被拆解或 "解挂 "之前立即调用的。这通常用于清除组件的资源依赖关系,这些依赖关系不会随着组件的卸载而简单地被移除(例如,移除任何与组件相关的setInterval()实例,或者因为组件的存在而在 "文档 "上设置的 "eventListener")。
render是最重要的生命周期方法,也是任何组件中唯一必须存在的方法。它通常在每次更新组件的状态时都会被调用。
JSX,即JavaScript XML,是对JavaScript语言语法的扩展。JSX在外观上类似于HTML,它提供了一种开发者熟悉的语法结构化组件渲染的方法。React组件通常是使用JSX编写的,尽管不一定非要使用JSX(组件也可以用纯JavaScript编写)。JSX类似于Facebook为PHP创建的另一种名为XHP的扩展语法。
JSX代码的一个例子:
同一层次上的多个元素需要被包裹在一个容器元素中,如上图中的<div>元素。
JSX提供了一系列的元素属性,旨在对应HTML提供的属性。这些自定义的属性也可以传递给组件,所有的属性都会被组件作为props接收。
JavaScript表达式(但不是语句)可以在JSX内部通过大括号{}使用。
上面代码的显示结果是:
条件语句
If-else语句不能在JSX中使用,但可以使用条件表达式来代替。下面的例子当i为1时将 { i === 1 ? 'true' : 'false' } 呈现为字符串 'true'。
结果会是:
函数和JSX可以用于条件表达式中:
结果会是:
用JSX编写的代码需要被Babel等工具进行转换以后才能被Web浏览器所理解,这种处理一般是在软件构建过程中进行的,然后再部署构建后的应用程序。
React的基本架构不仅仅适用于在浏览器中渲染HTML。例如,Facebook有动态图表,可以渲染到<canvas>标签,而Netflix和PayPal使用通用加载,在服务器和客户端上渲染相同的HTML。
React Hooks
Hooks是让开发者从函数组件中 "钩入"React状态和生命周期特性的函数。它们使代码具有更强的可读性且更易理解。Hooks并不在类组件内工作,它的终极目标是在React中消除类组件的存在。
React提供了一些内置的Hooks,如useState、useContext、useReducer和useEffect等。它们都在Hooks API参考书中做了说明。使用最多的是useState和useEffect,分别在React组件中控制状态和检测状态变化。
Hooks也有一些规则,在使用Hooks之前必须遵循这些规则:
钩子只能在顶层调用(不能在循环或if语句中调用)。
钩子只能在React函数组件中调用,不能在普通函数或类组件中调用。
构建自己的Hooks,也就是所谓的自定义Hooks,可以让你把组件逻辑提取到可重用的函数中。自定义钩子是一个名称以 "use "开头的JavaScript函数,它可以调用其他的钩子。钩子的规则也适用于它们。
React并没有试图提供一个完整的 "应用程序库"。它是专门为构建用户界面而设计的,因此并不包括许多一些开发者认为构建应用程序所需的工具。这使得开发者可以选择任何一个库来完成诸如执行网络访问或本地数据存储等任务。这种情况也就决定了React技术在创建网页应用时标准无法统一。
为了支持React的单向数据流的概念(与AngularJS/Angular的双向数据流形成对比),Flux架构是流行的模型-视图-控制器(MVC)架构的具有代表性的替代方案。Flux的特点是,数据动作通过中央调度器发送到一个存储仓库,而对存储仓库数据的变化会被传送回视图。当与React一起使用时,这种传送是通过组件属性完成的。
Flux可以被认为是观察者模式的一个变种。
Flux架构下的React组件不应该直接修改传递给它的任何props,而是应该传递回调函数,这些回调函数可以创建由调度器发送的数据动作来修改存储仓库。数据动作是一个对象,其职责是描述已经发生的事情:例如,一个数据动作描述的是一个用户 "follow"另一个用户。它可能包含如下数据:
用户ID,
目标用户ID,
以及USER_FOLLOWED_ANOTHER_USER枚举类型。
存储仓库,是一个数据模型,可以根据从调度器接收到的数据动作来改变自己。
这种模式有时被表述为 "属性向下流动,数据动作向上流动"。自Flux诞生以来,Flux的许多实现被创造出来,其中最著名的是Redux,它的特点是单一的存储仓库,通常被称为单一的数据真相源。
React是由Facebook的软件工程师Jordan Walke创建的,受PHP的HTML组件库XHP的启发,发布了React的早期原型,名为 "FaxJS",。它于2011年首次部署在Facebook的News Feed上,后来于2012年部署在Instagram上。2013年5月在美国JSConf大会上开源。
React Native是2015年2月在Facebook的React Conf上宣布的,2015年3月开源的React Native,实现了原生的Android、iOS和UWP开发。
2017年4月18日,Facebook宣布了React Fiber,这是React库的一个新的核心算法,用于构建用户界面,React Fiber将成为React库未来任何改进和功能开发的基础。
2017年9月26日,React 16.0正式对外发布。
2019年2月16日,React 16.8正式对外发布,该版本引入了React Hooks。
创建工程:
npx create-react-app my-app
开发环境运行:
npm start
生产环境打包:
npm run build
16.13.1于2020年3月19日
【授权】
MIT License
Angular(通常被称为 "Angular 2+"或 "Angular v2及以上版本")是一个基于TypeScript的开源Web应用框架,由Google的Angular团队和由个人以及企业组成的社区领导。 Angular是由构建AngularJS的同一个团队从零开始重写的。
Angular没有 "Scope"或控制器的概念,相反,它使用组件的层次结构作为其主要的架构特征。
Angular有不同的表达式语法,重点是"[]"用于属性绑定,"() "用于事件绑定
模块化 - 许多核心功能已转移到模块上
Angular推荐使用微软的TypeScript语言,它引入了以下特性。
(1)静态键入,包括Generics
(2)注解
TypeScript是ECMAScript 6 (ES6)的超集,向后兼容ECMAScript 5(即:JavaScript)。
动态加载
异步模板编译
由RxJS提供的迭代回调。RxJS限制了状态的可见性和调试,但这些问题可以通过像ngReact或ngrx这样的反应式附加组件来解决。
支持Angular Universal,可以在服务器上运行Angular应用程序。
最初,AngularJS的重写被称为 "Angular 2",但这导致了开发人员的迷糊。为了澄清,团队宣布,每个框架使用不同的术语,其中 "AngularJS "指的是1.X版本, "Angular " 指的是2及以上版本。
Angular 2.0在2014年10月22-23日的ng-Europe大会上宣布。2.0版本的剧烈变化在开发者中引起了相当大的争议。
2015年4月30日,Angular开发者宣布Angular 2从Alpha转为开发者预览版,2015年12月Angular 2转为Beta版,2016年5月发布了第一个发布候选版本,2016年9月14日发布了最终版本。
2016年12月13日Angular 4发布,跳过了3,避免了因路由器包的版本错位导致的混乱,当时已经发布的版本为v3.3.0。最终版本于2017年3月23日发布,Angular 4向后兼容Angular 2。
Angular 4.3版本是一个小版本,它是4.x.x版本的替换版本。
介绍了HttpClient,一个更小、更容易使用、更强大的HTTP请求库。
为守护者和解析器提供了新的路由器生命周期事件。四个新事件。GuardsCheckStart、GuardsCheckEnd、ResolveStart、ResolveEnd加入了现有的NavigationStart等生命周期事件集。
有条件地禁用动画。
Angular 5于2017年11月1日发布,Angular 5的主要改进包括支持渐进式Web应用、构建优化器以及与Material Design相关的改进。
Angular 6于2018年5月4日发布。这个版本,关注的重点不在于底层框架,更多的是工具链,以及让Angular在未来的更新和升级更加容易,比如:ngupdate、ng add、Angular元素、Angular Material+CDK组件、Angular Material入门组件、CLI工作区、库支持、树形摇动提供者、动画性能提升、RxJS v6。
Angular 7已于2018年10月18日发布。更新内容涉及到应用性能、Angular Material & CDK、虚拟滚动、Selects的可访问性改进、现在支持自定义元素使用Web标准的内容投影,以及关于Typescript 3.1、RxJS 6.3、Node 10(仍支持Node 8)的依赖性更新。
Angular 8已于2019年5月28日发布。具有所有应用代码的差异化加载、惰性路由的动态导入、Web工作者、TypeScript 3.4支持、以及Angular Ivy作为预览版可配置使用。Angular
Ivy预览包括:
生成的代码,在运行时更容易阅读和调试。
更快的重建时间
减少有效载荷
改进了模板类型检查
向后兼容
Angular 9已于2020年2月6日发布。第9版在默认情况下使用Ivy编译器。Angular可以与TypeScript 3.6和3.7兼容。除了数百个bug修复之外,Ivy编译器和运行时还提供了许多优势:
更小的软件包
更快的测试
更好的调试
改进的CSS类和样式绑定
改进的类型检查
改善了构建错误
改善了构建时间,默认开启AOT功能
提高国际化功能
一个组件例子
Html部分
Typescript部分
路由
定义服务类
调用服务类
从终端上,全局安装Angular CLI:
npm install -g @angular/cli
使用 ng new 命令创建一个新的 Angular CLI 工作区:
ng new my-project-name
开发环境运行:
ng serve
生产环境打包:
ng build --prod
9.1.2于2020年4月15日
MIT License
Vue.js(通常被称为Vue;发音为/vjuː/,类似于 "view")是一个开源的Model-view-viewmodel JavaScript框架,用于构建用户界面和单页面应用程序。它由Evan You创建,由他和来自Netlify和Netguru等多家公司的核心成员维护。
Vue.js的特点是,它采用了一个渐进式的架构,专注于声明式渲染和组件合成。复杂应用所需的高级功能,如路由、状态管理和构建工具等,都是通过官方维护的支持库和包提供的,其中Nuxt.js是最受欢迎的解决方案之一。
Vue.js可以让你用称为指令(directives)的HTML属性来扩展HTML。
Vue是由Evan You创建的。在Google工作期间,他使用AngularJS技术参与了多个项目的开发的,之后创建了Vue。他后来总结了自己的思考过程。"我想,如果我可以把AngularJS真正优秀的部分提取出来,然后构建一些轻量级的东西,会怎么样呢?" 项目的第一个版本源码提交日期是2013年7月,Vue在2014年2月首次发布。
Vue 组件扩展了基本的 HTML 元素来封装可重用的代码。从高层次的角度看,组件是Vue编译器附加行为的自定义元素。在Vue中,组件本质上就是一个带有预设选项的Vue实例。下面的代码片段包含了一个Vue组件的例子。该组件显示了一个按钮,并打印出按钮被点击的次数。
Vue使用基于HTML的模板语法,允许将渲染的DOM绑定到Vue实例的底层数据。所有 Vue 模板都是有效的 HTML,可以被符合规范的浏览器和 HTML 解析器解析。Vue 将模板编译成虚拟 DOM 渲染函数。虚拟文档对象模型(或 "DOM")允许Vue在更新浏览器之前在其内存中渲染组件。结合反应式系统,Vue能够计算出需要重新渲染的组件的最小数量,并在App状态发生变化时,启动最小量的DOM操作。
Vue用户可以使用模板语法,也可以选择使用JSX直接编写渲染函数,渲染函数允许从软件组件中构建应用程序。
Vue的特点是采用了反应式系统,它使用纯JavaScript对象和优化的重渲染。每个组件在渲染过程中都会跟踪其反应式的依赖关系,因此系统可以精确地知道什么时候重新渲染,以及哪些组件需要重新渲染。
当从DOM中插入、更新或删除项目时,Vue提供了多种方法来部署变换效果。这包括了以下工具:
自动应用CSS变换和动画的类
集成第三方CSS动画库,如Animate.css等。
在变换hooks期间,使用JavaScript直接操作DOM。
集成第三方JavaScript动画库,如Velocity.js等。
当在变换组件中的元素被插入或移除时,会出现这样的情况:
Vue会自动检测到目标元素是否应用了CSS变换或动画。如果有,CSS变换类将在适当的时间添加/删除。
如果变换组件提供了JavaScript hooks,这些hooks将在适当的时间被调用。
如果没有检测到CSS变换/动画,并且没有提供JavaScript hooks,那么插入和/或移除的DOM操作将在下一帧中立即执行。
单页面应用程序(SPA)的一个传统缺点是无法分享到特定网页中的确切 "子 "页面的链接。由于SPA只向用户提供一个基于URL的服务器响应(它通常服务于index.html或index.vue),因此通常情况下,将某些屏幕作为书签或分享到特定部分的链接是很困难的,甚至是不可能的。为了解决这个问题,许多客户端路由器用 "hashbang"(#!)来划分动态URL,例如http://page.com/#!/。然而,在HTML5中,大多数现代浏览器都支持不使用hashbang的路由。
Vue提供了一个界面,可以根据当前的URL路径来改变页面上显示的内容 – 可以有多种方式(无论是通过电子邮件链接、刷新还是页面内链接)。此外,当某些浏览器事件(如点击)发生在按钮或链接上时,使用前端路由器可以有意识地转换浏览器路径。Vue本身并没有自带前端路由。但开源的 "vue-router "包提供了一个API来更新应用程序的URL,支持返回按钮(导航历史记录),并支持电子邮件密码重置或电子邮件验证链接的认证URL参数。它支持将嵌套路由映射到嵌套组件,并提供精细化的过渡控制。添加了vue-router后,组件只需映射到它们所属的路由,父/根路由必须指明子路由的渲染位置。
上面的代码:
在http://websitename.com/user/<id>中设置一个前端路径。
这将在(const User...)中定义的User组件中呈现。
允许用户组件使用$route对象的params键输入用户的特定ID:$route.params.id。
这个模板(根据传递到路由器中的参数变化)将被渲染到DOM的div#app里面的<router-view></router-view>。
最后生成的HTML将是:http://websitename.com/user/1:
核心库自带的工具和库都是由核心团队和贡献者开发的。
Devtools - 用于调试Vue.js应用程序的浏览器devtools扩展。
Vue CLI - 用于快速开发Vue.js的标准工具书
Vue Loader - 一个webpack加载器,允许以单文件组件(SFCs)的格式编写Vue组件。
Vue Router - Vue.js的官方路由器
Vuex – 基于 Flux模式的 Vue.js 的集中式状态管理。
Vue Server Renderer - 用于 Vue.js 的服务器端渲染。
安装工具
npm install -g @vue/cli
创建工程:
vue create my-project
开发环境运行:
npm run serve
生产环境打包:
npm run build
2.6.1于2019年12月13日
MIT License
本文对于当前顶级的前端技术做了较为详尽的探索,前端技术一个大的方向是单页应用 (SPA,Single Page Application),我们在选取针对本业务的前端技术时需要结合如下几个方面来考虑:
1. 成员当前技能,这是一个很现实的问题,大多数程序员会选择自己比较熟悉的技术。这里要思考一下,目前自己熟悉的技术是不是最优选项?
2. 可利用的学习时间,如果发现要使用的技术需要一些时间学习,这个时间的开销到底会不会与开发进度有冲突?
3. 能否保证项目的复杂度最低,这个是比较关键的因素。先进技术之所以先进就是因为可以让开发者把时间和精力放在真正的业务开发上面来,如果要使用的技术需要进行很多与业务不相关的配置,就需要问一个问题,有没有更好的办法?
最后,希望本文对现有或者以后的业务开发有指导或者借鉴作用。
联系客服