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

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

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

Github地址: https://github.com/Tencent/QMUI_Web

背景

2014 年中,QMUI 团队支持的主要项目是 QQ 邮箱,Web 端的邮箱是个庞大的项目,但其并没有统一的 UI 基础库,多年的高速迭代使得项目的 UI 代码变得混乱,各个模块之间各自开发,除了在代码层面表现出混乱和不可控之外,表现层面也并没有很好地统一起来。因此,项目急需一套统一的团队编码规范以及一个 UI 基础库。

恰好,这个时候 Sass 等 CSS 预处理器已经发展成熟,自动化工作流的工作模式也日趋完善,因此,我们决定基于这些技术制作一套通用于不同项目的 Web UI 框架。框架的场景定位很明确:需要控制整体样式,并且可以适应频繁迭代打磨的大型项目。所以,这套即将诞生的 Web UI 框架的特性也很明确:需要方便地控制项目的整体样式,应对频繁的界面变动,并保持项目质量稳健。

此后经过三年的发展,QMUI Web 最终发展为包含编码规范、样式工具方法与样式管理、内置工作流,配套的 GUI 桌面 App,以及拥有完整文档的解决方案。

设计理念

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

  • 框架和组件需要剥离业务。作为 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_mod、resume_text、resumelist),个人信息(profile)页面的非公共组件部分,则可以以 profile 作为前缀(profile_statge、profile_stage_title)。

命名空间作为一种基础的隔离,把组件与业务,以及不同的业务之间的 Class-name 命名隔离开来,避免冲突,而后父子元素之间逐级展开编写,保证了项目内多人协助不易冲突,同时命名带有语义,也方便理解和阅读。

业务与组件的拆分

接着,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 问题,同时方便地通过调整这些变量的值而快速修改整个项目的样式。

组合而不是继承

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

颗粒度

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

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

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

具体组成

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

基础配置与组件

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

内置工作流

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

Sass 增强支持

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

扩展组件

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

GUI

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

优化和开源

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

在加入开源的大环境后,我们从 Github、社区论坛中都获取了不少建议,除了 bug 的反馈外,也指出了一些待完善的地方和提出一些优化的解决方案,从而使得 QMUI Web 注入了更多活力,因此我们也逐步进行了如“自动化测试用例”、“gulp 结构化”,“引入 SassDoc 自动化生成文档”,“编译 Sass 时引入增加更新”等优化,其中不少优化点我们也在项目的 Github Wiki (链接:https://github.com/Tencent/QMUI_Web/wiki/%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB)中进行了详细的分享,有兴趣的用户可以自行浏览。

总结与展望

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

关注 QMUI Web Github地址: https://github.com/Tencent/QMUI_Web 来 Github 给QMUI_Web star 吧!

转载自【腾讯开源】公众号,腾讯官方开源资讯,期待您的关注。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏深入浅出区块链技术

详解 Solidity 事件Event - 完全搞懂事件的使用

很多同学对Solidity 中的Event有疑问,这篇文章就来详细的看看Solidity 中Event到底有什么用?

1475
来自专栏Java学习网

如何编写出优秀软件

如何编写出优秀软件   软件必须是自由的   优秀软件是自由软件。我将避免使用“开源”,因为它根本没有包含社会层面,它和技术本身同等重要。你可以从这里了解更多...

2105
来自专栏Android群英传

Android工程模块化平台的设计

514
来自专栏FreeBuf

看我如何回怼手机黑客?黑回去!

本文中,以色列研究者通过反编译恶意APK应用GlanceLove,向攻击者服务器上传了webshell,实现了Hack Back(黑回去)。

843
来自专栏Netkiller

以太坊·将自定义数据写入到区块链中

本文节选自电子书《Netkiller Blockchain 手札》

58010
来自专栏张善友的专栏

微软Enterprise Library 4.0将支持依赖注入

下一个微软Enterprise Library的版本——V4——将预置支持依赖注入。依赖注入将通过容器以独立或作为库的一部分来提供。 特别值得一提的是,下一个E...

18010
来自专栏IT大咖说

前端老牌框架衰退,IMVC(同构 MVC)成未来趋势?

1452
来自专栏IMWeb前端团队

聊聊移动端跨平台开发的各种技术

介绍 最近出现的 React Native 再次让跨平台移动端开发这个话题火起来了,曾经大家以为在手机上可以像桌面那样通过 Web 技术来实现跨平台开发,却大多...

2115
来自专栏阮一峰的网络日志

CSS 框架 Bulma 教程

网页样式需要大量时间开发,最省事的方法就是使用 CSS 框架。 Bootstrap 是最著名的 CSS 框架,但是今天我想推荐另一个更轻量化、更易用的框架---...

2794
来自专栏即时通讯技术

最火移动端跨平台方案盘点

跨平台一直是老生常谈的话题,cordova、ionic、react-native、weex、kotlin-native、flutter等跨平台框架的百花齐放,颇...

1282

扫码关注云+社区