我来聊聊面向模板的前端开发

本文首发于 欧雷流。因为我会时不时对文章进行补充、修正和润色,为了保证所看到的是最新版本,请阅读 原文

在软件开发中,研发效率永远是开发人员不断追求的主题之一。于公司而言,在竞争激烈的互联网行业中,产出得快和慢也许就决定着公司的生死存亡;于我的而言,效率高了就能够少加班,多出时间去提高本身、发展爱好、陪伴家人,工做、生活两不误。前端

提高效率的途径,无外乎就是「方法」和「工具」。以一个开发者的思惟来想,就是将工做内容进行总结、概括,从一组类似的工做内容中提炼共同点,抽象出解决这一类问题的方法,从而造出便于在从此的工做中更为快速解决这类问题的工具。这个「工具」能够是个函数、组件、中间件、插件,也能够是 IDE、其余开发工具的扩展,甚至是语言。web

面向组件

在现代前端开发中,若是去问一个业务前端开发:「如何提高团队开发效率?」对方所回答的内容中,极有可能会出现「组件库」。没错,在前端工程化趋近完善的今天,在近几年 React、Vue 等组件化库/框架的影响下,面向组件开发的思惟方式早已深刻人心。前端工程化

组件库提效有限

如今,组件库已是一个前端团队的必备设施了,长远来看,团队必定且必需要有本身的组件库。开源的第三方组件库再好,对于一家企业的前端团队来讲也只是短时间用来充饥的,由于它们没法彻底知足一家公司的业务场景,而且出于多终端支持的考虑,一定要进行二次开发或者自研。框架

组件库有了,团队和公司中推广的效果也不错,绝大多数的人都在用。使用组件开发页面相对 jQuery 时代要每块功能区都得从 <span><div> 等 HTML 标签码起来讲确实提高了效率,然而有限;要搞出页面须要反复去引入组件,而后组合拼装出来,就像工厂流水线上的工人拼装零件,仍然要去作不少重复动做。frontend

只要以为当前的开发方式重复的动做多了,就表明还能继续提效,得想个法子减小重复无心义动做。ide

面向组件的开发方式,是现代前端页面开发提效的初级阶段,也是一个团队所要必经的阶段。函数

更高层面的提效

在以前写的文章中有段话——工具

组件能够很简单,也能够很复杂。按照复杂程度从小到大排的话,能够分为几类:组件化

  1. 基础组件;
  2. 复合组件;
  3. 页面;
  4. 应用。

对,不用揉眼睛,你没有看错!布局

站在更高的角度去看,「页面」和「应用」也是一种「组件」,只不过它们更为复杂。在这里我想要说的不是它们,而是「基础组件」和「复合组件」。

——欧雷《我来聊聊面向组件的前端开发

文中提到了「页面」和「应用」也能够看做是种「组件」。虽然与当时的想法有些差别,但本文的内容就是要在那篇文章的基础上简单聊聊在「页面」层面的提效。

通常来讲,「页面」是用户所能看到的最大、最完整的界面,若是能在这个层面有个很好的抽象方案,在作业务开发时与单纯地面向组件开发相比,应该会有更大的提效效果。

GUI 发展了几十年,人机交互的图形元素及布局方式已经相对固定,只要不是出现像 Google Glass 之类的革命性交互设备,就不会发生重大改变。在业务开发中界面形式更是千篇一概,尤为是 web 页面,尤为是中后台系统的 web 页面,必定能够经过什么方式来将这种「千篇一概」进行抽象。

试着来回想下,本身所作过的中后台系统的绝大部分页面是否是我所描述的这样——

页面总体是上下或左右布局。若是是上下布局的话,上面是页头,下面的左侧可能有带页面导航的侧边栏,或者没有侧边栏直接将页面导航所有集中在页头中,剩余区域是页面主体部分,承载着这个页面的主要数据和功能;若是是左右布局,左侧毋庸置疑就是有页面导航的侧边栏,页头跑到了右侧上面,其他是页面主体。

中后台系统的主要功能就是 CRUD,即业务数据的增删改查,相对应的页面展示及交互形式就是列表页、表单页和详情页。列表页汇总了全部业务数据的简要信息,并提供了数据的增、删、改和更多信息查看的入口;表单页肩负着数据新增和修改的功能;详情页可以看到一条业务数据记录最完整的信息。

每新增一个业务模块,就要又写一遍列表页、表单页和详情页……反复作这种事情有啥意思呢?既然这三种页面会反复出现,那干脆封装几个页面级别的组件好了,有新需求的时候就建几个页面入口文件,里面分别引入相应的页面组件,传入一些 props,完活儿!

这种方式看起来不错,然而存在几个问题:

  • 没有描述出页面内容的结构,已封装好的页面组件对于使用者来讲算是个黑盒子,页面内容是什么结构不去看源码不得而知;
  • 若是新需求中虽然须要列表页、表单页和详情页,但与已封装好的可以覆盖大部分场景的相关组件所支持的页面有些差别,扩展性是个问题;
  • 每来新需求就要新建页面入口文件而后在里面引入页面组件,仍是会有不少无心义重复动做和重复代码,时间长了仍是以为烦。

我须要一种既能看一眼就理解内容结构和关系,又具有较好扩展性,还能减小重复代码和无心义动做的方式——是的,兜了一个大圈子终于要进入正题了——面向模板开发。

面向模板

面向模板的前端开发有三大要素:模板;节点;控件。

富有表达力的模板

我所说的「模板」的主要做用是内容结构的描述以及页面的配置,观感上与 XHTML 相近。它主要具有如下几个特征:

  1. 字符所有小写,多单词用链接符「-」链接,无子孙的标签直接闭合;
  2. 包含极少的具有抽象语义的标签的标签集;
  3. 以特定标签的特定属性的形式支持有限的轻逻辑。

为何不选择用 JSON 或 JSX 来描述和配置页面?由于模板更符合直觉,更易读,而且中立。用模板的话,一眼就能几乎不用思考得看出都有啥,以及层级关系;若是是 JSON 或 JSX,还得在脑中进行转换,增长心智负担,而且拼写起来相对复杂。Vue 上手如此「简单」的缘由之一,就是它「符合直觉」的设计。

要使用模板去描述页面的话,就得自定义一套具备抽象语义的标签集。

页面的总体布局能够用以下模板结构去描述:

<layout>
  <header>
    <title>欧雷流</title>
    <navs />
  </header>
  <layout>
    <sidebar>
      <navs />
    </sidebar>
    <content>...</content>
  </layout>
  <footer>...</footer>
</layout>

看起来是否是跟 HTML 标签很像?但它们并非 HTML 标签,也不会进行渲染,只是用来描述页面的一段文本。

总体布局能够描述了,但承载整个页面的主要数据和功能的主体部分该如何去描述呢?

在上文中提到,咱们习惯将中后台系统中与数据的增删改查相对应的页面称为「列表页」、「表单页」和「详情页」。虽然它们中都带有「页」,但真正有区别的只是整个页面中的一部分区域,一般是页面主体部分。它们能够被分别当作是一种视图形式,因此能够将称呼稍微改变一下——「列表视图」、「表单视图」和「详情视图」。通常状况下,表单视图和详情视图长得基本同样,就是一个能编辑一个不能,能够将它们合称为「表单/详情视图」。

「视图」只描述了一个数据的集合该展现成啥样,并无也无法去描述每一个数据是什么以及长啥样,须要一个更小粒度的且可以去描述每一个数据单元的概念——「字段」。这样一来,用来描述数据的概念和模板标签已经齐活儿了:

<view>
  <field name="name" label="姓名" />
  <field name="gender" label="性别" />
  <field name="age" label="年龄" />
  <field name="birthday" label="生日" />
</view>

虽然数据可以描述了,但还有些欠缺:表单/详情视图中想将字段分组展现无法描述;对数据的操做也没有描述。为了解决这两个问题,再引入「分组」和「动做」。这下,表单/详情视图的模板看起来会是这样:

<view>
  <group title="基本信息">
    <field name="name" label="姓名" />
    <field name="gender" label="性别" />
    <field name="age" label="年龄" />
    <field name="birthday" label="生日" />
  </group>
  <group title="宠物">
    <field name="dogs" label="🐶" />
    <field name="cats" label="🐱" />
  </group>
  <action ref="submit" text="提交" />
  <action ref="reset" text="重置" />
  <action ref="cancel" text="取消" />
</view>

模板很好地解决了内容结构描述和配置的问题,但如何去动态地调整结构和更改配置呢?在日常的业务页面开发时也许不会太凸显出问题,但碰到流程表单设计或页面可视化编辑这种灵活性很高的需求时,问题就会被暴露出来了。

充满控制力的节点

在这里,我要将定义好的标签集所拼成的模板解析成节点树,经过更改树的结构和节点的属性去影响页面最终的呈现效果。每一个节点都会有节点的基本信息、对应标签的属性和一些节点操做方法:

{
  name: "field",
  tag: "field",
  attrs: {
    name: "name",
    label: "姓名"
  },
  parent: {},
  children: [],
  remove: function() {},
  insert: function() {}
}

在页面模板化且节点化以后,理想状况下,页面长啥样已经不受如 React、Vue 等运行时技术栈的束缚,控制权彻底在解析模板所生成的节点树上,要想改变页面的视觉效果时只需更改节点便可。

极具表现力的控件

页面内容的描述经过模板来表达了,页面内容的控制权集中到节点树中了,那么页面内容的呈如今这种体系下应该如何去作呢?负责这块的,就是接下来要说的面向模板开发的第三大要素——控件。

「控件」这个词不新鲜,但在我所说的这个面向模板开发的体系中的含义,须要被从新定义一下:「控件」是一个可复用的,显示的信息排列可由用户改变的,能够进行交互的 GUI 元素。

在这个面向模板开发的体系中,模板和节点树彻底是中立的,即不受运行时的技术栈所影响;而控件是创建在运行时技术栈的基础之上,但没必要限于同一个技术栈。也就是说,可使用 React 组件,也能够用 Vue 组件。

每一个控件在使用前都须要注册,而后在模板中经过 widget 属性引用:

<view widget="form">
  <group title="基本信息" widget="fieldset">
    <field name="name" label="姓名" widget="input" />
    <field name="gender" label="性别" widget="radio" />
    <field name="age" label="年龄" widget="number" />
    <field name="birthday" label="生日" widget="date-picker" />
  </group>
  <group title="宠物" widget="fieldset">
    <field name="dogs" label="🐶" widget="select" />
    <field name="cats" label="🐱" widget="select" />
  </group>
  <action ref="submit" text="提交" widget="button" />
  <action ref="reset" text="重置" widget="button" />
  <action ref="cancel" text="取消" widget="button" />
</view>

这样,一个面向模板开发的普通表单页出来了!

思想总结

面向模板的开发方式很好,可以大幅度提升业务前端开发效率,必定程度上减小了业务系统的搭建速度;做为核心的模板和节点树是保持中立的,大大下降了运行时技术栈的迁移成本,且可以应对多端等场景。

面向模板的开发方式初期投入成本很高,标签集、模板解析和控件注册与调用机制等的设计和实现须要较多时间,而且这仅仅是视图层,逻辑层也须要作出相应的变化,不能简单地用 props 和事件绑定进行处理了。

这个体系建成以后,在业务开发上会很简单,但机制理解上会增长部分开发人员的心智负担。

为了效率,一家公司里的业务前端开发到最后必定是面向模板,而非面向组件。

相关文章
相关标签/搜索