最近始终在捣鼓如何搭建 React 组件库,至于为什么会产生这个想法,次要是因为组件库对于前端生态来说究极重要,每一个着眼于久远倒退、看重开发效率的的互联网公司基本上都会量身定制本人的组件库,它的益处不必多说。对于前端工程师而言,去了解以及把握它,能够让咱们在今后的工作中以及应聘过程中多出一项非凡技能,并且对本身的纵向倒退也就是很无利的。上面是我记录我在搭建组件库的过程。
初始化工程
搭建工程不打算采纳 create-react-app 脚手架来搭建,因为脚手架封装好了很多货色,而有些货色对于组件库并不实用,用来搭建组件库过于臃肿,因而我不打算借助任何脚手架来搭建工程。
首先,先创立一个工程文件夹 pony-react-ui,在该文件夹下执行如下命令:
npm init // 生成 package.json
tsc --init // 生成 tsconfig.json
而后,依照如下目录构造初始化工程:
pony-react-ui
├── src
├── assets
├── components
├── Button
├── Button.tsx
└── index.ts
└── Dialog
├── Dialog.tsx
└── index.ts
├── styles
├── _button.scss
├── _dialog.scss
├── _mixins.scss
├── _variables.scss
└── pony.scss
└── index.ts // 打包的入口文件,引入 pony.scss,抛出每一个组件
├── index.js // 入口文件,package.json 中 main 字段指定的文件
├── package.json
├── tsconfig.json
├── webpack.config.js
└── README.md
编写一个 Button 组件
Button 组件应该满足一下需要:
- 不同尺寸
- 不同类型
- 不同色彩
- 禁用状态
- 点击事件
Button.tsx
import React from 'react';
import classNames from 'classnames';
export interface IButtonProps {
onClick?: React.MouseEventHandler;
// 类型
primary?: boolean;
secondary?: boolean;
outline?: boolean;
dashed?: boolean;
link?: boolean;
text?: boolean;
// 尺寸
xLarge?: boolean;
large?: boolean;
small?: boolean;
xSmall?: boolean;
xxSmall?: boolean;
// 色彩
success?: boolean;
warn?: boolean;
danger?: boolean;
// 禁用状态
disabled?: boolean;
className?: string;
style?: React.CSSProperties;
children?: React.ReactNode;
}
export const Button = (props: IButtonProps) => {
const {
className: tempClassName,
style,
onClick,
children,
primary,
secondary,
outline,
dashed,
link,
text,
xLarge,
large,
small,
xSmall,
xxSmall,
success,
danger,
warn,
disabled,
} = props;
const className = classNames(
{
'pony-button': true,
'pony-button-primary': primary,
'pony-button-secondary': secondary && !text,
'pony-button-outline': outline,
'pony-button-dashed': dashed,
'pony-button-link': link,
'pony-button-text': text && !secondary,
'pony-button-text-secondary': secondary && text,
'pony-button-round': round,
'pony-button-rectangle': noRadius,
'pony-button-fat': fat,
'pony-button-xl': xLarge,
'pony-button-lg': large,
'pony-button-sm': small,
'pony-button-xs': xSmall,
'pony-button-xxs': xxSmall,
'pony-button-long': long,
'pony-button-short': short,
'pony-button-success': success,
'pony-button-warn': warn,
'pony-button-danger': danger,
'pony-button-disabled': disabled,
},
tempClassName
);
return (
<button
type="button"
className={className}
style={style}
onClick={onClick}
disabled={disabled}>
<span className="pony-button__content">{children}</span>
</button>
);
}
在 Button/index.ts 文件中抛出 Button 组件以及定义的类型
export * from './Button';
这样,一个示例组件就根本实现了,有同学必定会有这么一个疑难,为什么在 Button.tsx 中没有引入它的款式文件_button.scss,而是在应用时引入全局款式或者独自引入_button.scss 呢?
// 独自引入组件款式
import {Button} from 'pony-react-ui';
import 'pony-react-ui/lib/styles/button.scss';
// 全局引入组件款式,打包时抽离进去的款式
import 'pony-react-ui/lib/styles/index.scss';
因为这跟款式的权重无关,通过 import 引入的款式权重将低于 JSX 中 className 定义的款式,因而才能够在组件内部批改外部的款式。
举个实例:
import {Button} from 'pony-react-ui';
import 'pony-react-ui/lib/styles/button.scss';
import styles from './index.module.scss';
const Demo = () => (<div className={styles.btnBox}>
<Button onClick={submit}>submit</Button>
</div>
)
引入组件库中的 Button.scss 和本地的 index.module.scss 在打包后会以 <style></style> 注入到页面中,而且程序必定是:
<style type="text/css">
// Button.scss 的款式
</style>
<style type="text/css">
// index.module.scss 的款式
</style>
因而,index.module.scss 中的款式权重是高于 Button.scss 中的款式,能够在 index.module.scss 中批改 Button.scss 的款式