来自 前端知识 2019-11-28 13:24 的文章
当前位置: 金沙澳门官网网址 > 前端知识 > 正文

UI组件化的一些思考

前端 UI组件化的一些思考

2017/04/10 · 基础技术 · 组件化

原文出处: 王一蛋   

最近公司推起了共用 UI 组件化的大潮,创建了一个新的 Repo 来放置共用的 UI 组件,比如下拉菜单等。出于对历史版本的表单组件的不满,我从两周前开始踏上了自己的 React 表单组件制作之路,踩了不少坑也有了不少感悟,之后也会写一篇文章关于我是如何写这个组件的(对 React 感兴趣的可以点这里 Hyo ,中文文档)。之后公司群里分享了这么一个演讲视频:Best Practices on building a UI component library for your company (David Wells) – FSF 2016 ,看完之后感触良多,本文算是该演讲内容的一个梗概与探讨。

回到正题,如果你在一个大型团队工作,或者你的企业有许多部门,你们该如何实现全局 UI 组件来跨越各个板块的界限?想象一个场景,如果你的整个公司都在使用同一段 UI 代码处理公共组件,财务工具在使用它,博客工具在使用它,在线聊天工具在使用它,且无论是在移动端,桌面端还是 web 端都能见到它,那该有多便利?无需累赘而繁复地一遍又一遍实现功能类似的表单,按钮或是列表。这是一个相对理想的设置,因为无论你在哪儿你都只需要维护一个代码库,且所有全局资源也都在同一个地方,开发者们可以方便地找到所需的代码并对其贡献。同时,共享 UI 组件同事也会给你的用户带来相容的体验,无论他在浏览或使用哪个工具,移动端或是桌面端,他的所见所感都是相一致的。注意的是同步这一概念,对于拥有很多产品的公司来说如果共享 UI ,那就意味着一次 UI 升级整个公司的产品都会受其影响。这从大部分意义上来说是一件好事,但有时又会带来很多麻烦,之后会说到。同时你的组件也应当是完备的,不与任何你所在团队所使用的第三方包相冲突。综上,如何设计你团队产品的 UI 架构,使得其兼具上述优点的同时还有良好的可扩展性与性能,是我们今天所要讨论的重点。

在本文中,我们主要使用 React 作为UI组件化的例子,将页面细分组件化是 React 的核心哲学,我们可以非常方便的将本文中的理念引入其中。

我们先来看一个关于 UI 设计指南典型的例子,这是 Salesforce 的 UI 库 Lightning Design System,他给了非常详细的 UI 规则,各个产品的页面、组件应当如何被处理,非常值得我们学习与借鉴。先来看一个 style guide 应当有些什么内容:

  1. 文档 由你团队成员所写的,如果使用 React 你可以直接通过注释 Proptypes 的方法,通过 React-docgen 生成文档。
  2. 代码预览 你应当提供一个可以让开发者实时调试代码的地方,使其他这些组件的使用者可以更好地理解各个props 。
  3. 使用实例 提供一些如何将其数据导入 UI 的实例代码,使其他开发者可以更快上手与他们的使用情况。
  4. 相容性 譬如怎样使用警告、载入信息等额外内容的规范,来提供用户相一致的体验。

那么,如何搭建一个组件库呢?为了回答这个问题我们可以将其细分为如下几个小步骤:

  1. 将整体的问题拆开成细目。
  2. 如何处理 CSS ?
  3. 如何将资源如变量,图标等公有化?
  4. 如何将其打包,便于使用?
  5. 开始从中获取收益!

首先,我们现讲如何将问题拆解,我们应当将页面上显示的一切看作是组件。也就是说每当你拿到设计师的稿件,第一件事应当就是讲页面上一切你所能看到的元素翻译成无数个小组件,这也是 React 的理念:复用组件。

图片 1

下一步,我们再将小组件组合成为较大的组件。这里不得不提到 Brad Frost 所提出的 Atomic Design。它所阐述的理念与本文所要说的观点相似,即由“原子”组成“分子”,“分子”构成“组织”,从而形成模板,进而生成页面。看下这些例子,标签,输入,按钮各是一个“原子”,合在一起即成了一个“分子”。

图片 2图片 3

其次, CSS 一直以来都是一个非常棘手的问题。我们应当如何处理类名冲突?如何使用第三方库的 CSS 文件?如何保证与 CSS 文件不冲突?如何确保相互独立?对于这些问题现在已经有了不少解决方案。

David Wells 在演讲中提到的与我们公司现在所使用的都是通过 PostCSS + CSS modules的解决方案。关于 CSS Modules 搭配 React 的用法,这里有个很好的例子:Modular CSS with React 。具体来说可以见此用例:

JavaScript

/* Thumbnail.jsx */ import styles from './Thumbnail.css'; render() { return (<img className={styles.image}/>) }

1
2
3
4
5
/* Thumbnail.jsx */
import styles from './Thumbnail.css';
render() {
  return (<img className={styles.image}/>)
}

JavaScript

/* Thumbnail.css */ .image { border-radius: 3px; }

1
2
3
4
/* Thumbnail.css */
.image {
  border-radius: 3px;
}

Hash 后生成的 HTML tag 与 CSS 看起来会是这样:

JavaScript

/* Rendered DOM */ <img class="Thumbnail__image___1DA66"/>

1
2
/* Rendered DOM */
<img class="Thumbnail__image___1DA66"/>

JavaScript

/* Processed Thumbnail.css */ .Thumbnail__image___1DA66 { border-radius: 3px; }

1
2
3
4
/* Processed Thumbnail.css */
.Thumbnail__image___1DA66 {
  border-radius: 3px;
}

此处将在我们 Thumbnail.jsx 文件中通过 CSS modules 引入 CSS 文件,再通过引入的 style 变量获取 hash 后的 CSS 类名。

此处提到的另一个工具 PostCSS 会将你的css文件全加上前缀名以适应不同浏览器,解决 CSS 4 的兼容性问题。

所以你真的需要使用 PostCSS 和 CSS Modules 么?你可以问自己如下问题:你在一个团队中工作么?你使用第三方库的 CSS 文件么?你的产品在第三方环境中运行么?你想要你的产品在任何环境中体验一致么?如果你回答是,那你可以选择尝试这一方案,因为这一解决方案基本解决了类名冲突与浏览器兼容的问题。

第三,关于如何处理共享资源。对于全局变量与 mixin ,我们建议通过几个 PostCSS 的插件来解决,而非使用sass等预处理器语言。可以通过一个简单的Postcss config来解释:

JavaScript

var vars = require('postcss-simple-vars'); var mixins = require('postcss-mixins'); var postCSSConfig = [ mixins({ mixins: require('./mixins') }), vars({ variables: require('./variables') }), ]

1
2
3
4
5
6
7
var vars   = require('postcss-simple-vars');
var mixins   = require('postcss-mixins');
 
var postCSSConfig = [
  mixins({ mixins: require('./mixins') }),
  vars({ variables: require('./variables') }),
]

此处我们从一个 mixins.js 文件中提取全局mixin,一个 varibles.js 文件中提取全局变量,他将会在你所有通过 PostCSS 编译的 CSS 文件中生效。实际使用中与less和sass十分相似,见例:

JavaScript

.hyo { @mixin MarsPower; /* 在 mixin.js 文件中定义 */ color: $MarsRed; /* 在 variables.js 文件中定义 */ }

1
2
3
4
.hyo {
  @mixin MarsPower; /* 在 mixin.js 文件中定义 */
  color: $MarsRed; /* 在 variables.js 文件中定义 */
}

对于图标,由于其轻量型与便利性我们一般选择 svg。基本的工作流程是由设计师制作 svg ,在你的 JS 代码中引入 svg ,通过 ’webpack-svgstore-plugin’ 优化 svg 并生成 sprite ,将 sprite 注入 DOM 。此处我们可以使用 svg use 标签,形式如:

XHTML

<svg><use id=“icon-aaa”></svg>

1
<svg><use id=“icon-aaa”></svg>

第四步,也是最后一步,我们应当如何搭建以及打包?

首先,我们有非常多的工具来使得开发 React 组件变得令人心情愉悦,推荐几个常用的第三方库:
carte-blanche 这是个非常牛b的 React 开发工具,只需简单几步就可已在浏览器中测试你的 React 组件,同时还支持随机生成 prop 来测试你的组件会不会应为 prop 异常而崩溃。
react-storybook 这是一个 carte-blanche 非常相似的选择,也是我用来开发 Hyo 的工具。
react-docgen 文档生成工具,你可以直接导入一个react文件夹,如果你在proptype中谢了注释它将会自动为你生成文档。

在版本更新时,注意使用语义化版本。每当你要开始写一个新的组建时,可以先在 Github 上搜索一下前人的实现方法,站在巨人的肩膀上做事才会事半功倍。

最后,关于如何打包,DW 推荐的方法是如下文件结构:

图片 4

对此我表示很赞同。分开打包每个小的组件入口,扁平化你的文件结构,组件之间可以相互依赖使用,对于开发效率与扩展化能力十分有帮助。

有些时候很难去查阅你在哪个页面使用了哪个组件。这里你可以使用一个监视器组件来查询你使用的组件。这在很多时候非常便利,譬如你想升级某一个组件,你会想去了解哪些页面或是组件依赖了这个组件从而进行修改,DW 提供了一个实现,我们可以根据我们的需求来实现自己的 Monitor Component。

图片 5

最后的最后,小结几个开发 React 组件中常遇见的问题。(至少我是碰到了- -)首先,做之前想明白要实现的 Feature,与设计师讨论并写下自己的需求,市面上是否有可用的替代品,尽可能不要定义过多的 prop,不然在之后维护会非常辛苦。其次,尽可能地给予使用者客制化的权利,譬如内容如何渲染,排序如何进行等,最好开放一个 api 使得使用者可以自己定义,因为你永远无法预测并满足所有使用者的需求。第三,在所有浏览器上进行测试,老生常谈了但有时还是会忘。最后,从开始便定义好 lint 的规则并遵从它,可以参考 AirBnB 的配置作为起始点。

啰啰嗦嗦写了这么多,希望大家都能从中能收获些许。最后再安利一下 Hyo,也算是自己的第一个认真做的开源项目,希望大家多多点星! | Demo点这里 | 文档点这里 |

1 赞 1 收藏 评论

图片 6

让CSS更完美:PostCSS-modules

2017/01/22 · CSS · POSTCSS

原文出处: Alexander Madyankin   译文出处:众成翻译   

译者注(GeoffZhu): 这篇适合一些使用过预处理CSS的开发者,比如less,sass或stylus,如果你都没用过,那你一定不是个好司机。在PostCSS中早就可以使用CSS Modules了,该篇作者贡献了一个新工具,可以让更多开发者方便的使用最新的CSS Modules。

我们和全局作用域的css斗争了多年,现在终于是时候结束它了。不管你用的是什么语言还是框架,CSS命名冲突将不再是个问题。我将给你展示一下PostCSS和PostCSS-modules如何使用,并且可以在服务端使用它们。 CSS起初只是一个美化文档的工具,但是事情到1996年发生了变化。浏览器中不再单单只有文档了,即时通讯,各种软件,游戏,没什么是浏览器不能承载的。

当今,我们在HTML和CSS方面已经走了很远很远,开发者们激发出了CSS所有的潜力,甚至创造出了一些CSS本身都快驾驭不了的东西。

每一个有经验的开发者都知道 — 每次使用全局命名空间都是留下了一个产生bug的隐患,因为很快就可能出现类似命名冲突之类的问题,再加上其他方面(项目越来越大等)的影响,代码越来越不易维护。

对于CSS来说,这意味着有问题的布局。CSS特异性和CSS宽泛性之间,一直存在着如史诗般的对决。仅仅是因为每个选择器都可能会影响到那些不想被影响的元素,使之产生了冲突。

基本所有编程语言都支持局部作用域。和CSS朝夕相伴的JavaScript有AMD, CommonJS和最终确定的ES6 modules。但是我们并没有一个可以模块化CSS的方法。

对于一个高质量项目来说,独立的UI组件(也就是组件化)非常重要的 — 每个组件小巧独立,可以拼合成复杂的页面,这让我们节省了很多的工作。但是我们始终有一个疑问,如何防止全局命名冲突那?

解决方法

因为有前人的探寻,现在我们有Object-Oriented CSS, BEM, SMACSS等等,这些都是非常棒并且非常有用的方法。他们通过增加前缀的办法,解决了命名冲突的问题。

通过增加前缀的办法解决命名冲突是个体力活(manual mangling)。我们手动的去编写长长的选择器。你也可以使用预编译的css语言,但是它们并没有从根本上解决问题(还是体力活)。下面是我们用BEM规范书写的一个独立组件(对于现有的除BEM之外的方法,思想上基本也是这样):

CSS

/* 普通 CSS */ .article { font-size: 16px; } .article__title { font-size: 24px; } /* 使用css预处理语言 */ .article { font-size: 16px; &__title { font-size: 24px; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* 普通 CSS */
.article {
  font-size: 16px;
}
 
.article__title {
  font-size: 24px;
}
 
/* 使用css预处理语言 */
.article {
  font-size: 16px;
 
  &__title {
    font-size: 24px;
  }
}

本文由金沙澳门官网网址发布于前端知识,转载请注明出处:UI组件化的一些思考

关键词: