[翻译]怎么写一个React组件库(二)
本文同步发布于知乎专栏 https://zhuanlan.zhihu.com/p/27434018,喜欢本文的就去知乎点个赞支持下吧~
引言
该系列文章将通过创建一个组件库来引导你学习如何构建自己的组件库。
这是该系列的第二部分。如果你还没有阅读 Part 1,我推荐你先阅读它。另外,我们将会讨论有关原子设计的内容。如果你不熟悉相关概念,阅读一些相关内容 (这儿)_ 将对你很有帮助。_
在该部分我们将讨论:
-
通过
styled-components
使得我们的组件变得可配置性更强 -
添加一个调色板到我们的库
-
使用一些
polished
的功能 -
使用
npm link
,babel
和eslint
的高效开发流程 -
将原子设计原则应用到我们的组件库结构
原子设计 & 组件
现在我们已经完成许多初始化配置,接下来我们将花时间思考如何构建一个实用的组件库。
为了实现这目标,我们将借用 Brad Frost 的原子设计的一些概念。这本书绝对值得一读,你可以购买它如果你想了解更多的相关内容。但为了简洁起见,我们将只了解一些高维抽象概念。Brad 将web UI分为五个独立的部分:原子(atoms),分子(molecules),实体(organisms),模版(templates),页面(pages)。
我们的组件库将由原子和分子组成。开发者可以通过组件库快速构建实体,模版和页面。
Source: http://bradfrost.com/wp-content/uploads/2013/06/atomic-design.png
原子(Atoms) -> 元素(Elements)
原子是构成UI中最小的不可分割的单位。想想按钮,链接,输入框等等。在本教程中,我们统称为它们为元素。
还记得我们创建了按钮组件然后将其放入 /elements
目录么? 💡
我们将从创建元素开始来写我们的组件库。一旦我们有足够的元素,我们将添加一个分子。我喜欢从元素开始因为这可以让我们的组件不过于复杂。每个元素都应该是独立的,我们要能够通过组合这些元素创建分子。他们(元素)应该像乐高积木一样开箱即用,无需任何电工工具。 当我们开始构建分子,如果某些东西不合适,那么我们需要回到我们的元素去重新审视它们的设计。
分子(Molecules) -> 组件(Components)
如上所述,分子是简单的,是原子的不同组合。接下来我们将称这些为组件。“组件”一词对React世界来说非常自然,但我们将以一种特殊的方式使用它。一个例子是搜索区域,它由一个标签,一个输入框和一个按钮组成。另一个例子是一个下拉列表,它由一个按钮(触发下拉) ,一个列表和列表项组成。
好的,但是什么不是组件呢?
好问题。谢谢你的提问。一个导航栏从定义上来说不是一个组件。一个导航栏更像是一个实体。它有很多组件构建而成,能随着组成的内容的变化而发生很大变化。一个登录表单是另一个实体的例子。它可能包含一个标题,表单的实体标签,输入框和按钮,一个重置密码的链接和一个包含所有元素的div。
为什么不添加实体到组件库?
另一个好问题。🏆添加实体到组件库没有问题。但当它们出现的时候我们应该抛开这些妄想。组件库的目的是为了构建可扩展和可复用的组件。如果我们从构建许多实体开始,我们将限制用户只能遵循我们的特定模式。我们正在添加组件以便用户可以快速构建一致的UI。但如果他们需要一些不同的东西,或者不喜欢我们的特定的模式,那么他们可以轻易地回到元素从而构建自己的模式。
请记住有一些情景下添加实体是有意义的。比如,假设你有三个主要的应用程序用于你的业务,你希望这些应用都有一致的登录表单。好的,那就将登录表单的实体放入你的库。
好,现在我们已经涵盖了组件库背后的很多理论。我们进入有意思的部分,开始构建。 🛠
添加有效的开发工作流
第一部分中,我们以_“… 在我们发布到npm之前,有一个用来试验的本地测试环境将会很棒。”结束。_正如我们所承诺的,这将是我们现在所做的。
配置我们的本地环境
我们需要一个本地环境去试用我们的组件。很幸运,我有一个小应用作为此环境。你需要从GitHub上把它pull down下来并安装依赖。
$ git clone git@github.com:alanbsmith/component-lib-playground.git
$ cd component-lib-playground
$ npm install
如果你在使用Yarn,运行yarn
。
如果你运行npm run dev
或 yarn dev
,在你的浏览器上打开 http://localhost:8080,然后看见“Hello, World!”,很棒! 如果你进入 src/components/App.js
文件然后修改部分JSX,你也将注意到它是热加载更新的。这对于测试我们的库是很棒的一点。接下里我们将把我们的应用和组件库连接起来。
连接我们的组件库
⚠️注意: 你可能要在一个终端窗口里保持打开组件库,在另一个里保持打开应用。
首先我们要添加build:watch
脚本到组件库的package.json
文件。-w
告诉了Babel注意lib
目录下的任何变化并即时更新build
目录下的内容。
"scripts": {
"build": "babel lib -d build",
"build:watch": "babel lib -w -d build",
"lint": "eslint lib/**; exit 0",
...
现在我们将在本地创建一个我们库的符号链接。如果你想知道更多有关npm link
,这里有 一些有用的文档。在我们组件库的根目录运行npm link
。你可能注意到控制台正在运行prepublish
。
现在我们将告知我们的测试应用我们将要使用符号链接的库。在应用的根目录运行:
⚠️注意: 请记住用你组件库的名字取代 component-lib
。
npm link component-lib
就是这样!我们准备去使用我们的组件库在测试应用中!
添加按钮到测试应用
在src/components/App.js
中我们将像使用其他外部库一样引入和调用我们的组件:
import React from 'react';
import PropTypes from 'prop-types';
import { Button } from 'component-lib'
...
const App = ({ name }) => {
return (
<div>
<h1>Hello, {name}!</h1>
<Button>Click Me!</Button>
</div>
);
};
...
一旦更新,测试应用将热加载更新,按钮将会出现!
添加了我们的第一个组件到测试应用!
💡 注意到我们的测试应用完全不知道 styled-components 是什么。任何人都可以不用安装其他支持库来使用我们的库。这是我们把所有东西放在 devDependencies 的理由。
⚠️译者注:译者在运行测试应用如果不引入styled-components和polished会发生报错,具体已经向原作者进行提问,欢迎关注后续和提出见解!
很好!现在让我们对Button
做一些改变。如果按钮是不同的颜色将非常棒。或许紫色?
const Button = styled.button`
background: #7E5BEF;
...
&:hover {
background: #592DEA;
}
`;
你将注意到当我们的 lib 目录更新的时候,测试应用并没有反映出这变化。那是因为我们需要再次运行npm run build
更新build
目录。这不是最好的做法。每次文件更新后都需要手动重新构建有点蠢和痛苦。还记得先前我们添加的build:watch
脚本?现在我们可以使用它了。
$ npm run build:watch
咚!现在我们的组件库每一次变化都能自动更新!🎊 当我们进行上述操作时,我们进行分屏然后运行npm run eslint:watch
从而可以立即看到我们是否有语法错误。你的终端看上去可能像这样:
分别用终端打开测试应用,build:watch 脚本和 lint:watch 脚本运行。
现在我们库的变化立即反映在应用中,我们可以轻松地进行试验。
添加调色板
按钮的静态颜色限制了这个元素很多。有一个用户可以选择颜色的调色板将会很棒,调色板可以通过传递一个属性实现。让我们在组件库中添加新文件colors.js
到/lib/styles
。 在里面我们添加如下内容:
module.exports = {
// light shades
white: '#FFFFFF',
snow: '#F9FAFC',
darkSnow: '#EFF2F7',
extraDarkSnow: '#E5E9F2',
// dark tones
silver: '#8492A6',
slate: '#3C4858',
steel: '#273444',
black: '#1F2D3D',
// dark shades
smoke: '#E0E6ED',
darkSmoke: '#D3DCE6',
extraDarkSmoke: '#C0CCDA',
// blue shades
lightBlue: '#85D7FF',
blue: '#1FB6FF',
darkBlue: '#009EEB',
// purple shades
lightPurple: '#A389F4',
purple: '#7E5BEF',
darkPurple: '#592DEA',
// pink shades
lightPink: '#FF7CE5',
pink: '#FF49DB',
darkPink: '#FF16D1',
// orange shades
lightOrange: '#FF9E7C',
orange: '#FF7849',
darkOrange: '#FF5216',
// green shades
lightGreen: '#29EB7F',
green: '#13CE66',
darkGreen: '#0F9F4F',
// yellow shades
lightYellow: '#FFD55F',
yellow: '#FFC82C',
darkYellow: '#F8B700',
// ui colors
info: '#1FB6FF',
success: '#13CE66',
danger: '#FF4949',
warning: '#FFC82C',
};
这些颜色来自Marvel’s styleguide。欢迎你使用自己的颜色,但这些已经足够达到我们的目的。
现在我们将更新按钮元素去使用这些颜色:
...
import * as colors from '../styles/colors';
const Button = styled.button`
background: ${({ bgColor }) => colors[bgColor]};
...
color: ${({ fontColor }) => colors[fontColor]};
...
&:hover {
background: ${({ hoverColor }) => colors[hoverColor]};
}
`;
Button.defaultProps = {
bgColor: 'blue',
fontColor: 'white',
hoverColor: 'darkBlue',
};
export default Button;
很酷。现在我们的用户可以在bgColor
,fontColor
和hoverColor
属性中使用调色板中自己想要的颜色。我们也对每个颜色属性增加了defaultProps
,所以如果用户不传递任何属性,事情也不会变得很糟。
好!当我们的测试应用重渲染时,按钮应该变成蓝色。让我们增加一些属性然后声明新的颜色。我在这里将设置为橘黄色,但你可以从调色板随意使用颜色。
const App = ({ name }) => {
return (
<div>
<h1>Hello, {name}!</h1>
<Button
bgColor="orange"
hoverColor="darkOrange"
>
Click Me!
</Button>
</div>
);
};
很棒!
Nice!对我们用户来说,能够快速更新按钮颜色而不做任何配置是非常美好的。必须要添加 hoverColor
有点烦人。但如果我们不那么做,我们将看到同样烦人的darkBlue
。或许 polished
会有帮助?
添加一些 Polish
Polished是一个为我们提供了一些方便Sass功能的轻量级的工具集。我们已经在组件库中安装了它,因此我们现在只需要引入它。我们将添加darken
函数去取代hoverColor
属性。
import styled from 'styled-components';
import { darken } from 'polished';
import * as colors from '../styles/colors';
const Button = styled.button`
background: ${({ bgColor }) => colors[bgColor]};
...
color: ${({ fontColor }) => colors[fontColor]};
...
&:hover {
background: ${({ bgColor }) => darken(0.1, colors[bgColor])};
}
`;
Button.defaultProps = {
bgColor: 'blue',
fontColor: 'white',
};
请注意我们已经完全删除了hoverColor
属性。现在我们可以使用darken
和bgColor
去得到我们新的悬停背景颜色。0.1
是我们使颜色变暗的量。我们也可以删除hoverColor
属性。
...
<Button bgColor="orange">
Click Me!
</Button>
...
好!这将会让我们的组件更加容易使用!请再次注意测试应用并_不知道 Polished 是什么_。
Wrapping Up
⚠️注意: 我们最好保存我们的项目然后commit
。
$ git status
$ git add -A
$ git commit -m 'adds color palette and dynamic styling for Button'
现在我们已经有了一个高效的工作流,一个很棒的调色板和针对我们按钮元素的动态样式。在Part 3我们将继续添加其他元素到我们的库。
我希望这对你有帮助。如果你喜欢它,请让我知道!欢迎分享如果你觉得这对他人有帮助!