腾讯 Web UI 解决方案 QMUI Web —— 探索与沉淀

做者简介: 李浩成(Kayo),腾讯广州研发部 UI 工程师。git

通过长时间的打磨迭代,QMUI Web 做为腾讯广研 QMUI 团队的一个开源项目,正式发布到 Tencent Github。QMUI Web 是一个 Web UI 的解决方案,从零开始,由编码规范,到组件和工具方法的制做,再到工做流的整合,不断在迭代,也不断在优化,走过了很多的路。趁着发布的机会,咱们正好回顾这一路的探索过程,分享其中的点滴,也但愿能借此让你们更了解 QMUI Web。github

背景

2014 年中,QMUI 团队支持的主要项目是 QQ 邮箱,Web 端的邮箱是个庞大的项目,但其并无统一的 UI 基础库,多年的高速迭代使得项目的 UI 代码变得混乱,各个模块之间各自开发,除了在代码层面表现出混乱和不可控以外,表现层面也并无很好地统一块儿来。所以,项目急需一套统一的团队编码规范以及一个 UI 基础库。 刚好,这个时候 Sass 等 CSS 预处理器已经发展成熟,自动化工做流的工做模式也日趋完善,所以,咱们决定基于这些技术制做一套通用于不一样项目的 Web UI 框架。框架的场景定位很明确:须要控制总体样式,而且能够适应频繁迭代打磨的大型项目。因此,这套即将诞生的 Web UI 框架的特性也很明确:须要方便地控制项目的总体样式,应对频繁的界面变更,并保持项目质量稳健。 此后通过三年的发展,QMUI Web 最终发展为包含编码规范、样式工具方法与样式管理、内置工做流,配套的 GUI 桌面 App,以及拥有完整文档的解决方案。gulp

设计理念

在制做框架的过程当中,咱们把框架须要的特性进行整理和思考,造成了一套对于该框架的设计理念,在这些设计理念之中,最核心的关键为通用于多个项目高效迭代保持代码稳健,框架的设计也遵循这三个核心点,体如今框架上,具体就是:浏览器

  • 框架和组件须要剥离业务。做为 UI 框架,框架内整合的组件和样式必须有能力剥离业务,才能跨项目使用。
  • 能轻易控制总体样式。须要高效地迭代项目,样式的总体控制必不可少。
  • 保持代码稳健。

而具体到代码层面,则能够概括为两个方面:框架

  • Class-name 命名规范。
  • 基础样式配置与半封装组件。

Class-name 命名规范

做为一个 Web UI 框架,编写代码主要是 CSS 与 HTML,而提到 CSS 与 HTML 的编写,首先要处理的是 Class-name 的命名,在过往的开发中,Class-name 的命名并无固定的规范,开发人员各自进行开发,一个项目通过长时间的迭代后,常常会遇到如命名冲突,命名混乱等问题,这使得项目的迭代变得笨重,也很差维护。所以,咱们须要一套具备以下特色的 Class-name 命名规范:工具

  • 命名有迹可循,容易编写。
  • 避免命名冲突,包括内部多人协做命名冲突,以及外部库引入时的被动污染。
  • 命名具备语义,能晰地描述整个页面,方便理解上下文。

所以,最终 QMUI Web 制定了一套以命名空间为核心的命名方式,这个命名方式主要由“命名空间”,“业务与组件的拆分”,“精确表达 View”三个部分构成。测试

命名空间

一个 QMUI Web Class-name 应该包含一个命名空间,也是 Class-name 的开头,若是是业务,则以业务内容为命名空间,若是是公共组件,则全局使用项目的名字(或缩写)为命名空间。如一个名为 Demo 的项目,项目缩写能够是 dm,那么该项目下的项目组件和公共类能够这样命名: dm_btn(按钮)、dm_icon(图标)、dm_ipt(输入框)、dm_toolbar(工具栏)。 逻辑模块命名以具体业务做为前缀,如简历(resume)功能里面的非公共组件部分,以 resume_ 做为前缀(resume_modresume_textresume_list),我的信息(profile)页面的非公共组件部分,则能够以 profile_ 做为前缀(profile_statgeprofile_stage_title)。 命名空间做为一种基础的隔离,把组件与业务,以及不一样的业务之间的 Class-name 命名隔离开来,避免冲突,然后父子元素之间逐级展开编写,保证了项目内多人协助不易冲突,同时命名带有语义,也方便理解和阅读。字体

image_1bouo6vnb1jsg1q31af418351e129.png-85.3kB

image_1bouo7q7t1lsi1f7kqkktsk1tn9m.png-61.8kB

业务与组件的拆分

接着,QMUI Web 中把项目的代码划分为通用组件(跨项目的组件),项目全局组件(适用于某个具体项目),业务组件(适用于某个业务),以及业务逻辑代码,这样区分出4个颗粒度可使得代码更容易被组织和复用,一个模块随着设计元素迭代,也能够在这4个颗粒度之间进行迭代,从而使得模块在迭代时会更加稳健。而 QMUI Web 框架中的组件应该只收纳通用组件,即跨项目组件。优化

精准表达 View

精准表达 View 是指在命名 DOM 节点时要明确这是一个怎样的 View,这里的 View 指的就是 UI 层面上这个元素表示的含义,常见的场景是,一个命名为 resume_head 的元素,在经历屡次迭代后实际在代码中却充当了页脚,这样的命名在多人协做时很容易给后面的开发者形成困扰,而精准表达 View 则要求咱们明确一个 UI 元素的含义,并在命名时准确地表达。编码

基础样式配置与半封装组件

前面的“Class-name 命名规范”主要是在规范层面上去实践 QMUI Web 的核心理念,而接着更多地就是在代码层面上去实践了,主要包括三点:

  • 半封装组件,即面向项目的组件。
  • 使用组合而不是继承。
  • 颗粒度的把控。

半封装组件即面向项目的组件

前文提到,QMUI Web 把组件划分为通用组件,项目全局组件,业务组件三种组件,而 QMUI Web 框架收纳的则是通用组件,也是跨项目的组件,但每一个项目的 UI 表现并没有关联,如何处理跨项目组件就成为了一个问题。为此,QMUI 在处理组件时采起的是“半封装”的处理方式,QMUI 框架封装的是代码,所谓半封装,即封装那些与项目具体 UI 表现没有必然联系的代码。例如按钮组件,QMUI Web 中只封装了文字居中对齐,鼠标手型,浏览器样式重置,低版本 IE 兼容性处理等代码,而经常使用的样式如边框、背景、字体表现等,都抽取成变量控制,这些组件的变量最终都聚集到一个配置表 Sass 文件中,配合全局的颜色变量、字体变量等变量,就能够作到跨项目抽取组件,每一个新项目只须要关注具体 UI 表现而无需再处理各类常见的 UI 问题,同时方便地经过调整这些变量的值而快速修改整个项目的样式。

image_1boupcrpp1okoc05117ar1g1g9h13.png-224.3kB

组合而不是继承

在处理组件时,继承的方式是指一个组件类承担复杂的功能,而组合的方式则是把组件类拆分红一个基类,以及多个子类,每一个子类承担的功能不重复,对于咱们的主场景——频繁迭代,保持稳健,显然组合会更加适合,这种方式避免了在频繁的迭代中须要不断修改组件类,每次迭代只须要修改对应的子类便可。

颗粒度

对于组件的抽取,时常要考虑颗粒度的划分,颗粒度自己就是一个比较开放性的问题,在这里与你们分享一些沉淀的经验:

  • 抽取组件以 UI 表现为区分,例如一个删除按钮,是以删除 icon + 删除文案做为内容的,但在表现上它就是一个带 icon 的文字按钮,所以就抽取出一个支持 icon 的文字按钮,而不用只局限于按“删除”这个业务来命名组件。
  • 抽取组件能够选择较大的颗粒度,也能够选择较小的颗粒度。颗粒度较大的组件实现复杂,能对应复杂的场景,但扩展性也会所以降低,而颗粒度较小的组件则实现简单,能轻松实现一个主场景,但又方便扩展,能灵活地应对变化。所以建议是像按钮、输入框、下拉菜单这类一般位于页面 DOM Tree 末端的元素能够抽取成尽可能简单的组件,同时经过扩展的方式去处理各类场景差别。而其余复杂的组件则能够专一于一个业务,没必要过多地考虑不一样的场景,不然组件很容易变得难以维护。

以上即是 QMUI Web 具体的设计理念,经过命名规范、基础样式配置与半封装组件来保证多人协做时的高效率与可维护性,也使得一个 UI 框架能为不一样的项目服务。

具体组成

做为一个框架,QMUI Web 主要提供了四种能力来提高 UI 开发的效率与质量,对应前文提到的框架设计理念,QMUI Web 提供的这些功能都是为了帮助开发者方便地控制项目总体样式,应对频繁变更,同时保持代码稳健。

基础配置与组件

前文提到,框架中会有一份配置表,是各类 Sass 的变量,这些变量控制了一个网页基本的字体样式,连接颜色,通用组件的样式配置等基础样式,在建立一个新项目时,应该先根据设计稿配置好这些信息,当这些信息配置完成,那么一个项目的基本样式就能够快速实现了。例以下图中这些配置属于 QMUI 通用配置,经过修改这些配置则能够快速修改项目的字体策略、正文字体大小,连接颜色等 UI 经常使用的 CSS 属性。

image_1bouqhakqcnr163ruqeubm1n8d1g.png-449.6kB

内置工做流

QMUI 中包含一个基于 gulp 的内置工做流,用于快速解决大量重复劳动力的工做,从而提高效率。QMUI 的 gulp 中预先实现了监控 Sass 文件并自动编译和优化,雪碧图处理,模板 include 能力(能够传参和使用条件判断),浏览器自动刷新,图片压缩,文件清理,文件合并以及自动变动等能力。

image_1bour0k6d13ff1o8k170hed81o8v1t.png-256.4kB

Sass 加强支持

QMUI 中提供了大量基于 Sass 的 CSS 预处理的方法,包括 CSS Reset,一些常见的 CSS 类(例如清除浮动),计算长度值的简便方法(例如获取 padding 在某个方向的值,计算两个长度值的中间值),快速实现一些样式效果的工具方法(例如实现 border 三角形,适应多倍屏幕的 1px 边框等),这些都是用于提升样式开发的效率和质量。

扩展组件

扩展组件并非由 QMUI Web 的主源码提供,而是由 Demo 提供,一般是由于这类组件结构较复杂,所以业务性没法很好地剥离,从而不能抽取成公共组件,所以这类组件就放在一个 Demo 页,以参考组件的形式帮助开发。

GUI

咱们提供了一个用于管理 QMUI Web 项目的桌面 App,在代码层面它独立于 QMUI Web 的源码。它经过 GUI 界面处理 QMUI Web 的服务开启/关闭,并提供了编译提醒,出错提醒,进程关闭提醒等额外的功能,在处理多项目,多分支时能更方便地进行开发。

image_1boura6cn1qm81sqj1hlev127tj2a.png-192.8kB

优化和开源

在经历较长时间的迭代后,QMUI Web 也逐渐完善起来,此时咱们也开始将 QMUI Web 进行开源。开源意味着 QMUI Web 会进入更加全面的环境中去打磨,在框架的非主体内容如代码规范、注释、文档上面也须要更费心思,考虑的点也须要更加周全。这对团队来讲无疑是个很好的机会,能够有更多的渠道审视框架,吸取建议,持续进行优化。

在加入开源的大环境后,咱们从 Github、社区论坛中都获取了很多建议,除了 bug 的反馈外,也指出了一些待完善的地方和提出一些优化的解决方案,从而使得 QMUI Web 注入了更多活力,所以咱们也逐步进行了如“自动化测试用例”、“gulp 结构化”,“引入 SassDoc 自动化生成文档”,“编译 Sass 时引入增长更新”等优化,其中很多优化点咱们也在项目的 Github Wiki 中进行了详细的分享,有兴趣的用户能够自行浏览。

总结与展望

至此,QMUI Web 发展为如今这套完整的方案,也终于开源到 Github Tencent 与你们分享,咱们指望经过开源与你们进行更多的交流,也使得 QMUI Web 进入更加全面的环境中去打磨,造成对代码规范、注释、项目文档感谢公司与部门给咱们提供了一个平台,能够在大型项目中经历迭代和沉淀。开源只是一个开始,咱们后续仍会不断进行探索和优化,期待更好的 QMUI Web。

关注 QMUI Web, 来 Github 给咱们 star 吧!

https://github.com/Tencent/QMUI_Web

相关文章
相关标签/搜索