從零到一搭建React組件庫(kù)
作者:ToSmile
來(lái)源:Segmentfault 思否
最近一直在搗鼓如何搭建React組件庫(kù),至于為什么會(huì)產(chǎn)生這個(gè)想法,主要是因?yàn)榻M件庫(kù)對(duì)于前端生態(tài)來(lái)說(shuō)究極重要,每一個(gè)著眼于長(zhǎng)遠(yuǎn)發(fā)展、看重開(kāi)發(fā)效率的的互聯(lián)網(wǎng)公司基本上都會(huì)量身定制自己的組件庫(kù),它的好處不用多說(shuō)。對(duì)于前端工程師而言,去理解以及掌握它,可以讓我們?cè)诮窈蟮墓ぷ髦幸约皯?yīng)聘過(guò)程中多出一項(xiàng)特殊技能,并且對(duì)自身的縱向發(fā)展也就是很有利的。下面是我記錄我在搭建組件庫(kù)的過(guò)程。
初始化工程
搭建工程不打算采用 create-react-app 腳手架來(lái)搭建,因?yàn)槟_手架封裝好了很多東西,而有些東西對(duì)于組件庫(kù)并不適用,用來(lái)搭建組件庫(kù)過(guò)于臃腫,因此我不打算借助任何腳手架來(lái)搭建工程。
首先,先創(chuàng)建一個(gè)工程文件夾 pony-react-ui,在該文件夾下執(zhí)行如下命令:
npm init // 生成package.json
tsc --init // 生成tsconfig.json
然后,按照如下目錄結(jié)構(gòu)初始化工程:
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,拋出每一個(gè)組件
├── index.js // 入口文件,package.json中main字段指定的文件
├── package.json
├── tsconfig.json
├── webpack.config.js
└── README.md
編寫(xiě)一個(gè)Button組件
Button組件應(yīng)該滿足一下需求:
不同尺寸 不同類型 不同顏色 禁用狀態(tài) 點(diǎn)擊事件
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;
// 禁用狀態(tài)
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>
);
}
export * from './Button';
// 單獨(dú)引入組件樣式
import { Button } from 'pony-react-ui';
import 'pony-react-ui/lib/styles/button.scss';
// 全局引入組件樣式,打包時(shí)抽離出來(lái)的樣式
import 'pony-react-ui/lib/styles/index.scss';
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>
)
<style type="text/css">
// Button.scss的樣式
</style>
<style type="text/css">
// index.module.scss的樣式
</style>
編寫(xiě)樣式
├── styles
├── _button.scss
├── _dialog.scss
├── _mixins.scss
├── _variables.scss
└── pony.scss
// _mixins.scss
@mixin colors($text, $border, $background) {
color: $text;
background-color: $background;
border-color: $border;
}
// 設(shè)置按鈕大小
@mixin button-size($padding-x, $height, $font-size) {
height: $height;
padding: 0 $padding-x;
font-size: $font-size;
line-height: ($height - 2);
}
$values: #ff0000, #00ff00, #0000ff;
.primary {
@include colors($values...);
}
.primary {
color: #ff0000;
background-color: #00ff00;
border-color: #0000ff;
}
$button-font-size: 14px !default;
$button-xl-font-size: 16px !default;
$button-lg-font-size: 16px !default;
$button-sm-font-size: 12px !default;
@import 'variables';
@import 'mixins';
@import 'button';
@import 'dialog';
...
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
loader: 'css-loader',
options: {
modules: false // 禁止css modules
}
]
}
]
<Button className="btn">按鈕</Button>
// 修改Button內(nèi)部樣式,假如組件內(nèi)部樣式有個(gè)樣式類名為pony-button-promary
.btn {
:global {
.pony-button-promary {
color: #da2227;
}
}
}
.btn {
:global {
// 下次修改Button組件構(gòu)建后,生成的hash不一定為sadf6756
.pony-button-promary-sadf6756 {
color: #da2227;
}
}
}
打包輸出UMD規(guī)范
打包輸出es module規(guī)范
docz生成組件使用文檔
發(fā)布到npm倉(cāng)庫(kù)

評(píng)論
圖片
表情
