Kyligence Copilot - AI 数智助理,以 AI 变革企业经营与管理! 立即了解更多

前端组件化开发实践

陆国圣
2017年 12月 01日

作者:陆国圣

编辑:Sammi

什么是前端组件化开发?

我们在前端项目的开发流程中,把一个需求在一定的颗粒度范围内进行拆分,拆分后的单元具有独立功能和可复用性,具有可视和可交互的能力。通过这些单元之间的组合,能够完成具有一定复杂度的页面,这样的开发流程就可以认为是前端组件化开发。

有哪些类型的组件?

在组件化开发的项目中,一切皆组件。

组件的颗粒度可大可小,可以是一个按钮,一个输入框,也可以是一个表单,一个穿梭框,一个菜单,一棵信息树,也可以是一个模块页面。

按照组件层次上来分,组件可以是父子组件(子组件可以继续向下嵌套),兄弟组件。

按组件的功能来分,组件可以是纯展示型组件,开关型组件,业务型组件。

按组件封装性来分,组件可以是全局通用组件,局部通用组件和一次性组件。

按组件来源来分,组件可以是外部组件和自定义组件。

我们把需求拆解成组件时往往很难把握颗粒度的大小,有的时候拆解过度了,导致组件通信和状态管理成本反而加大。拆解的技巧是我们要能按照上面的分类来捋清楚其中会出现什么类型的组件,拆解下来的组件需要能够方便的在其他场景里无缝拼接,更重要的是组件里的业务是独立的,完整的。

什么是组件状态?

每一个组件都有若干种状态,根据功能的不同,状态数量和存储形态也大不相同。比如一个按钮组件有初始化状态,鼠标悬浮状态,鼠标点击状态,禁用状态,Focus 状态等等,更复杂的组件拥有更多可能的状态。组件的状态可以是全局的,也可以是局部的,全局的状态往往是为了方便在全局范围内的状态通信。局部状态主要是供组件内部使用。我们操控组件,其实就是在处理组件的状态。让状态的改变驱动着组件表现出不一样的效果。

组件如何通信?

当多个组件开始配合工作的时候,我们需要让他们产生各种组合和依赖关系。例如想在列表组件加载完成前通知 Loading 组件显示加载进度条的效果,在加载完成后通知其隐藏进度条;比如弹窗组件关闭的时候,我们需要通知弹窗组件内部的表单组件进行 Reset 操作等等。组件通信的手段有很多种,有广播机制,冒泡机制,共享机制。 广播机制主要是针对父组件向它的子孙组件进行消息广播,子孙组件要提前对父组件进行监听,冒泡机制主要是子组件向父组件进行消息冒泡。共享机制主要是将状态信息放置于一个全局的位置,需要响应该全局状态的组件只要添加对该消息的监听就可以轻松拿到这些状态,该机制比广播和冒泡更加高效和简约,尤其是在组件关系嵌套很深的情况或者组件没有父子关系的情况。

组件状态分析很重要吗?

一个复杂的系统往往会拥有大量的组件,每个组件又有大量的状态,几乎每个状态我们都要做一定的处理,有的基础状态处理我们可以借助一些第三方的库来覆盖(比如一些 UI 组件库,它们为我们处理好了一些例如按钮,文本框,多选框之类的基础状态效果)。在开发的过程中,任何一个状态的处理遗漏都会导致产品的功能缺失和体验下降。因此分析出每个组件的状态以及管理好状态对应的逻辑就成了整个开发过程中最重要的任务。

很多人拿到设计稿的时候直接就动手写代码,这样很容易写出耦合度高,逻辑不清晰的代码。该篇将通过一个简单组件实例来说明如何分析组件状态,比如当我们接到一个登陆框需求的时候,我们需要分析一个登陆框会有多少种状态(登陆框包括了两个输入框和一个登陆按钮,输入框和按钮的基础状态通过 UI 组件框架来覆盖,这里不做讨论)。

  1. 初始化状态:

表单正常显示,数据都已经 清空,按钮处于初始可点击状态,输入框处于可输入状态。

2. 默认填充状态:

表单默认填充上次登录过的保存在 cookie 中用户名信息。

3. 表单校验不通过状态:

表单输入为空或者输入格式不正确的校验状态。

4. 表单校验通过提交中的状态:

表单校验通过,提交数据到后台还未返回时的防止重复提交的锁定状态。

5. 表单提交成功状态:

后台验证登陆成功后提示用户登陆成功或者通知控制组件进行页面模块跳转。

6. 表单提交失败状态:

后台验证登陆失败后提示用户登陆失败并切换到初始化状态。

7. 其它语言状态:

表单接受到多语言切换组件的切换语言的通信后,切换自身的语言状态。

分析完登录框的所有的状态,我们就可以确定需求的工作量、工作细节,以及后面的 Test Plan。按照状态的顺序我们就可以合理的布局和安排我们的代码了。

借助框架实现组件化

除了用原生方法自己封装组件外,我们可以借助很多现成的框架来帮我们更加方便的开发和组织自定义组件,目前流行的框架都具有比较好的组件系统,例如 Angular、Vue、React 等,结合高效的数据双向绑定,让我们能够更加深刻的体验到状态驱动组件 View 的快感。

本文举例使用 vue 框架。Vue 框架提供给我们高效的数据绑定和灵活的组件系统,定义一个组件相当简单。

注册之后即可在父组件模板中以自定义元素的形式调用一个子组件:

该组件提供了组件内部常用的模版和数据状态,通过 Vue 的双向绑定机制实现数据的交互。Vue 还提供了基于构建工具实现的单文件组件(Webpack+Vue-loader)的功能,通过以 *.vue 作为后缀的文件书写 Vue 组件。 比如下面写一个基于 Element 的框架的名为 pager.vue 的组件文件,实现的是一个二次封装的分页组件。

在一个独立的文件里定义了一个组件的所有要素: Html 模块定义组件基本 DOM 结构,JavaScript 提供组件状态管理和状态改变监听函数,CSS 部分提供组件的展示效果。在项目的其它地方只要想引用用该组件,都可以通过局部引用或者全局注册的方式来重复的利用该组件。

代码组织分模块按照业务的不同拆分成不同的组件放置在不同的文件夹下(如下图)。

上面描述了一个组件化的页面,由菜单组件,项目选择组件,树组件,tab 组件,语言切换组件,编辑器组件等等拼接而成。在开发过程中,开发人员通过自由的组合,便可快速迭代出界面。一旦出现问题,也能够快速定位到对应的组件。

总结

除了 Vue、Angular、React 还有很多框架都有提供组件化的系统,比如:

  • KnockoutJS Components
  • Backbone Components
  • CanJS Components
  • Famous Components

篇幅有限,本文不做深入讨论,框架虽各有千秋,但组件化的思想几乎都大同小异,组件化不是越来越被重视,而是一直都很重视,不管是从设计、需求还是开发。它的确提高了开发的效率,降低了维护的成本。

添加企微

kyligence
关注我们

kyligence