GX博客

分享个人 Full-Stack JavaScript 项目开发经验

构建 UI 框架

一般地,网站项目的开始是先与客户沟通确认需求,然后基于需求设计交互原型图。接受客户的提议后,修改原型图,并交由设计师设计网站界面图。网站界面图经过客户确认之后,就会把需求确认书和网站界面图一并交给前端开发人员开发静态交互界面。本文将介绍一个基于 Grunt 构建 UI 框架的流程方案。


为什么要先独立开发静态交互界面?

  • 它可以作为高精度交互原型交付给客户,进一步确认产品需求细节。
  • 可以对静态交互界面独立测试,确保界面的标准化、稳定性和兼容性。
  • 它不依赖于具体的数据绑定技术,相对而言它更容易维护和对界面升级。
  • 我们可以在这阶段处理好静态交互界面资源从开发环境到生产环境的过度。

所以,首先我们要根据需求确认书和网站界面图,构建一个 UI 框架。前端项目构建工具有很多,Grunt 就是其中之一。不应该用好坏去比较它们,在个人实践中,Grunt 表现出色,能满足大部分开发需求,所以我继续使用它。


UI 框架有哪些要求?它要完成哪些任务?

  • Mission ①:要对从 PSD 设计图切下来的图片进行无损压缩和优化,减少应用加载时间。
  • Mission ②:维护一套基于框架设计的、组件化的 Sass 样式。在开发环境提供 sourcemap 源文件映射,在生产环境提供压缩的、自动添加浏览器前缀的兼容 css 文件。
  • Mission ③:维护一套组件化开发的交互 js 脚本。在开发环境可以单独开发和测试,在生产环境提供自动合并压缩并混淆的 js 文件。
  • Mission ④:提供一套与需求确认书和界面设计图一致的交互 html,用于与客户沟通并细化需求,还用于界面测试。

下面从一个具体的开发目录开始逐步实现上述要求和任务:

frontend/ ------(根目录)
├── html/ ------(模块化的 html 页面目录)
├     ├── 测试/ ------(各静态、交互组件 html 测试目录)
├     ├── 模块A/
├     ├── 模块B/
├     ├── ......
├     └── index.html
├── public/
├     ├── fonts/ ------(网络字体目录)
├     ├── images/
├     ├── stylesheets/
├     ├     └── index.css ------(UI 框架生产环境 css 文件)
├     └── javascripts/
├           ├── vendor/ ------(第三方脚本库目录)
├           ├── src/ ------(组件化交互脚本目录)
├           ├    ├── 组件A.js
├           ├    ├── ......
├           ├    └── 组件B.js
├           └── index.js ------(UI 框架生产环境 js 文件)
├── sass/
├     ├── vendor/ ------(第三方库样式目录)
├     ├── component/ ------(组件样式文件目录)
├     ├     ├── 组件A.scss
├     ├     ├── ......
├     ├     └── 组件B.scss
├     ├── mixins/ ------(@mixin文件目录)
├     ├── page/ ------(除组件外的,包括全局样式、页面样式和公共样式等的样式文件目录)
├     ├── _mixins.scss ------(@mixin汇总文件)
├     ├── _utilities.scss ------(实用样式)
├     ├── _variables.scss ------(sass 全局变量文件)
├     └── index.scss ------(样式表的主入口文件)
├── Gruntfile.js ------(Grunt文件)
└── Grunt.config.js ------(Grunt任务中的路径配置文件)

切图和图片的压缩优化

要进行前端页面开发,需要对 PSD 设计图的一些特殊图标进行切图。有设计师帮忙当然最好,我们可以告诉他们前端想要的切图效果。此外,我们也可以使用像cutterman这样的 Photoshop 切图插件帮助我们快速切图。

对于切图,有两个需要注意的地方。第一,能用 CSS3 实现的不要使用切图,这里我们可以使用像pxcook这样的工具,帮助我们快速地从设计图中获得标准的样式代码。第二,对于大量的小图标应该进行图片拼接,以减少请求次数。

在获得切图后,我们利用 Grunt 的 grunt-contrib-imagemin 插件对图片进行无损压缩,较少图片体积。如果你还未使用过该插件,你可以先阅读文章使用Grunt的grunt-contrib-imagemin插件压缩图片


构建和划分Sass样式

使用 html 进行界面开发,并编写 Sass 样式之前,需要先分析界面设计图。我们要明确整套界面中,哪些元素应该作为组件被重复使用,哪些样式应该作为全局的界面标准,哪些样式应该使用变量控制,而剩下的其它则可划分到具体页面样式中。

Sass 样式的组件化是 UI 框架维护和分工的基础。确定好上述问题后,我们的 scss 主入口文件大致会包含以下内容:

// 重置样式
@import "normalize";

// 第三方库
@import "vendor/icheck";
// ......

// 使用 sass 封装的 css 框架
// http://compass-style.org/
@import "compass";

// 全局变量
@import "variables";

// 自定义 @mixins,作为 compass 的补充
@import "mixins";

// 实用样式
@import "utilities";

// 全局的标准化样式
@import "page/global";

// 各组件样式
@import "component/header";
// ......

// 各页面样式
@import "page/about";
// ......

因为 Sass 不能直接被浏览器解释,所以我们还需要一个 Sass 的自动编译环境。若你还没配置过环境,可以先参阅Sass环境安装。然后再使用 grunt-contrib-compass 插件,让它监听 frontend/sass 目录下的 scss 文件,并自动编译到 public/stylesheets 的目录下供 html 页面引用。

在开发环境中,应开启 sourcemap,使浏览器开发者工具选择元素样式时可映射到 scss 文件的具体位置。最后使用 grunt-postcss、autoprefixer 和 grunt-contrib-cssmin 等插件,以兼容 ie 10+ 和其它现代浏览器最新两个版本的要求为编译后的 css 文件添加浏览器前缀,并压缩成生产环境版本。


开发 js 组件交互插件

对于依赖 js 实现交互的组件,如弹窗、下拉菜单等,我们可以用插件的形式封装交互。jQuery 插件则比较常见,因为它易于实现 DOM 操作,且兼容性好。以下是 Bootstrap 插件封装的模式,值得借鉴:

// 使用 + 号使函数声明转成表达式,后面可使用 () 直接调用
+function ($) {

  // 使用严格模式编写
  'use strict';

  // 定义构造函数 Alert
  var dismiss = '[data-dismiss="alert"]'
  var Alert   = function (el) {
    $(el).on('click', dismiss, this.close)
  }

  // 设置版本号和配置属性
  Alert.VERSION = '3.3.7'
  Alert.TRANSITION_DURATION = 150
  Alert.prototype.close = function (e) {
    // ......
    // 这里插入另一个 Modal 插件的代码段示例用于说明自定义事件的机制
    // 自定义事件发布和事件阻止时候终止执行余下代码
    var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
    this.$element.trigger(e)
    if (this.isShown || e.isDefaultPrevented()) return
  }

  // 遍历元素,使用参数实例化插件,并把实例保存在各自的 data 上
  function Plugin(option) {
    return this.each(function () {
      var $this = $(this)
      var data  = $this.data('bs.alert')
      if (!data) $this.data('bs.alert', (data = new Alert(this)))
      if (typeof option == 'string') data[option].call($this)
    })
  }

  // 将插件方法和构造函数添加到 jQuery 原型对象上,并设置冲突回退方法
  var old = $.fn.alert
  $.fn.alert             = Plugin
  $.fn.alert.Constructor = Alert
  $.fn.alert.noConflict = function () {
    $.fn.alert = old
    return this
  }

  // 设置特定命名空间的事件委托
  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)

}(jQuery);

这些插件会与交互组件一一对应,它们可以独立开发、测试和维护。最后可以使用 grunt-contrib-uglify 和 grunt-contrib-concat 插件进行合并混淆和压缩,输出一个可用于生产环境的 UI 框架交互 js 文件。


html 界面开发

不管是 Sass 样式开发,还是组件交互脚本开发,都依赖 html 进行呈现和测试。上述 html 目录中包含了测试目录和网站各个功能模块的目录。一般地,我们可先在测试目录中对各个组件进行开发和单元测试,稳定后再用于发具体模块的 html 页面。因为这阶段还没对组件的 html 进行封装,如果后面出现问题,需要修改 html,则使用到它的页面都得调整。

另外,html 页面一定要保持良好的注释,每个组件都应给予独立的注释,让我们知道这块 html 后面就应该替换成对应的 React 组件。

html 页面的开发过程中,少不了在 html、scss 和 js 文件发生修改时刷新页面,让浏览器重载最新的代码。Grunt 中有插件为我们自动完成这个枯燥的事情,具体可参阅使用Grunt实时重载静态页面


到此,我们已经完成了构建 UI 框架的基本要求和任务。其中,Grunt 负责完成了开发过程中的一些自动化工作,并且把项目代码以 CLI 命令的方式从开发版本打包成生产环境版本。Grunt 使项目易于组件化开发,而组件化开发利于分工、测试和维护。一个组件对应着一个 scss 和一个 js,可以任意组装,甚至独立出来。

版权声明:

本文为博主原创文章,若需转载,须注明出处,添加原文链接。

https://leeguangxing.cn/blog_post_26.html