JavaScript 框架这一年:React、Angular 们正在互相渗透
点击上方“CSDN”,选择“置顶公众号”
关键时刻,第一时间送达!
如果说 2016 是 JavaScript 的疲劳年,那么 2017 年肯定是融合的一年。大多数 JavaScript 框架使用的工具和概念都趋于一致。
在这篇文章中,我将重点介绍 JavaScript 框架之间的一些相似之处,剖析框架之间的设计和思想是如何相互渗透的。
基于组件的架构
组件(components)是一个很棒的概念。设计师喜欢它们,因为通过组件,设计师可以和开发人员拥有共同的语言,能够把系统的设计清楚的表达出来;开发人员喜欢它们,因为这意味着他们可以专注于构建小型,自包含且可重用的特性,然后把它们组合起来构建更大的视图和整个应用程序本身;产品经理喜欢它们,因为可以在多个应用之间共享这些组件。
React 为现代前端开发普及了组件模型的概念。在 Angular 的 1.x 版本时期,社区就有人开始编写基于组件的指令(https://www.airpair.com/angularjs/posts/component-based-angularjs-directives#1-component-based-directives-in-angularjs)。接着在 Angular 1.6 版本中引入了 angular.component(),从而能够更容易的编写基于组件的指令。到了 2016 年,Angular 2.0 带来了真正的组件。同时,Vue 一开始就将组件作为其核心特性之一。
下面是使用这三个框架编写组件的例子,可以看到代码相似度很高:
当然三个框架的代码也存在差异,例如,在 React 中我们可以用函数来实现组件。Angular 和 Vue 可以引用定义在 HTML 文件中的模板。Vue 还可以在一个独立的 `.vue` 文件中编写集 HTML,CSS 和 JS 于一体的组件。然而,组件的核心思想在所有三个框架中都是相同的。
视图的定义
组件的视图(View)部分是当在应用程序的某个地方使用组件时,我们希望框架渲染的内容。在 Angular 中,我们将视图定义为模板,它们是 HTML 的变种,使用类似 mustache/handlebars 的语法来绑定数据——使用两个大括号把 JavaScript 表达式(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions)包裹起来。这些模板同时支持几个内置的组件和指令,允许我们定义模板逻辑,例如条件语句和列表渲染。
React 使用 JSX(https://facebook.github.io/jsx/),可以在 JavaScript 中使用类 XML 的语法定义视图。绑定操作很像模板,JSX 使用一个大括号把 JavaScript 表达式包裹起来。JSX 和模板最大的区别是添加控制语句和模板逻辑的方式。模板依赖于内置的组件和指令,而 JSX 直接使用 JavaScript 语言特性,例如 if 语句,三元操作符或者 `Array.map` 方法等。虽然 JSX 有一定的学习曲线,但你会惊奇的发现其实模板的很多用法和概念是可以迁移到 JSX 中的。
Vue 同时支持上面两种方式。Vue 模板的灵感来源于 Angular,两者的模板逻辑几乎使用相同的组件和指令,数据绑定也都使用两个大括号。通过定义 render 函数(https://vuejs.org/v2/guide/render-function.html#Basics)我们还可以在 Vue 中使用 JSX,而不用使用模板属性。
JSX 的主要好处之一是可以在一个文件中就完成一个组件所有代码的编写,也就是说,这个组件的视图,JavaScript 逻辑甚至样式都可以放在一个文件中。Vue 也支持单文件组件(https://vuejs.org/v2/guide/single-file-components.html)的编写,同时不局限于 JavaScript 代码,你还可以使用 HTML 模板或者 Pug,或者使用 render 函数来实现视图。样式可以使用 CSS,SCSS 或者 PostCSS 等编写。
样式和封装
组件的样式的使用通常有三种不同的风格:
经典:所有的 CSS 都是全局可见的,组件可以使用所有的样式;
封装:每个组件有专属于自己作用域内的局部样式,它不使用任何全局的样式,同时组件内部的样式对外部也不可见;
混合:组件大部分情况下使用自己作用域内的局部样式,但也有一些全局的样式可以级联继承下来。
你是否对其中某种风格更加情有独钟呢?好消息是,三种框架都支持这三种风格。全局 CSS 天然就支持,我们可以在模板中使用 class属性,或者在 JSX 中使用 className 来引用全局的 CSS。
Angular 也内置支持组件作用域内的样式,我们可以从三种封装策略(https://angular.io/api/core/ViewEncapsulation)中选择任何一个,而且样式在加载进组件之前,可以通过 Sass 或者 PostCSS 执行预处理。
Vue 通过单文件组件语法提供对局部样式的支持,直接在 style 标签中添加 scoped 属性即可。和 Angular 类似,我们在 Vue 中也可以配置构建工具实现加载 CSS 之前进行预处理。
CSS Modules(https://github.com/css-modules/css-modules)是另外一种实现模块化和局部 CSS 的流行的做法。在 Vue 中使用 CSS Modules只需要给 `style` 标签添加 `module` 属性即可:
React 没有内置的局部样式支持,然而 React 社区有很多充满活力和创新的解决方案来实现编写组件的局部 CSS。当然我们也可以使用 CSS Modules。
当然,在 React 中实现局部 CSS 更多的情况是使用基于 CSS-in-JS 的函数库,例如 styled-components(https://www.styled-components.com/),glamorous(https://glamorous.rocks/),emotion(https://emotion.sh/)以及其他函数库(https://github.com/MicheleBertoli/css-in-js)。
如果你更倾向于使用 CSS-in-JS 的方案,也有一些函数库支持 Vue,例如 styled-components/vue-styled-components(https://github.com/styled-components/vue-styled-components),emotion-vue styled(https://github.com/emotion-js/emotion/blob/d5d34c0df2be5bae19d21da4e950b03fae03a1b7/README.md#vue-styled)。
组件数据的传递
组件之间是相互隔离的,但组件可以从它的父组件接收数据。在 React 和 Vue 中我们称之为 props,在 Angular 中称之为 inputs。
Props 和 inputs 都是只读的数据,可以在组件的视图中使用,也可以进一步传递给子组件使用,这些数据在组件树中从上往下单向流动。当数据发生更新时,将会触发使用它们的组件进行重新渲染。
子组件必须明确声明它希望接收的 props 或 inputs,我们也可以给这些数据指定类型。在 React 中可以使用 PropsType 函数库(https://www.npmjs.com/package/prop-types)来指定类型,例如:
Vue 也对 props 的校验提供了类似的支持:
Angular 2+ 主要使用 TypeScript 来编写代码,因此,对输入数据的类型校验就交给 TypeScript 了。你只需要使用注解给输入属性指定类型就行。
静态类型检查器功能强大,甚至可以在执行前就能指出代码中存在的问题,从而改善开发流程。对大型应用效果更为显著。因此,在 2017 年初 PropTypes 从 React core 中移除了,现在官方(对大型应用)的建议(https://reactjs.org/docs/static-type-checking.html#flow)是使用 Flow 或者 TypeScript。
TypeScript 对 Vue 的支持并不如 React 和 Angular 那么健壮,但它也在快速改进中。例如微软维护了一个 TypeScript-Starter(https://github.com/Microsoft/TypeScript-Vue-Starter)框架,Vue 官方甚至提供一个函数库(https://vuejs.org/v2/guide/typescript.html#Class-Style-Vue-Components)可以使用 class 风格的语法来编写 Vue 组件。
事件
这三个框架都可以在组件中指定事件处理器,从而实现对 DOM 事件的监听,并在它们被触发时执行某些 JavaScript 代码。
Props 和 Inputs 允许数据在组件树中从上到下流动,但我们通常需要把某些变化从下往上反馈回去。Angular 和 Vue 可以通过发射自定义事件来实现,组件可以绑定到这些自定义事件来实现监听变化。
在 Vue 中可以通过 $emit 来触发自定义事件:
在 Angular 中自定义事件可以通过使用 @Output 修饰符给 EventEmitter 实例添加注解来实现,并通过调用 event emitter 的 emit 方法来触发这个自定义事件:
React 实现自定义事件的方式有点不同,它不是把自定义事件往上抛出,而是让父组件将事件处理器作为 props 传递给子组件,然后等待子组件在合适的时机调用。
总结
本文我重点介绍这三个框架在组件这个概念上的相似点,但事实上框架间在其他很多地方都是相似的。在应用打包,状态管理,响应性和 CLIs 等其他方面,这些框架也在相互学习,最终选用的解决方案也大同小异。将来的某一天也许我们可以共享使用不同框架编写的组件(https://github.com/TheLarkInn/unity-component-specification)。
在过去的几年,前端领域的开发者们都会感觉有些焦虑,因为几乎每隔一个月就会出现一个新的框架需要学习。大家担心时间花费在错误的框架上。现在事情已经发生变化,对其中任何一个框架的投资都将得到回报。你在一个框架中学到的知识几乎都可以迁移到其他框架中。
原文:JavaScript Frameworks: The Year of Convergence
链接:http://blog.rangle.io/javascript-frameworks-the-year-of-convergence/
作者:Varun Vachhar
译者:顾浩鑫
责编:苏宓
以上是 JavaScript 框架这一年:React、Angular 们正在互相渗透 的全部内容, 来源链接: utcz.com/z/382935.html