最近一直在捣鼓如何搭建React组件库,至于为何会产生这个想法,主要是由于组件库对于前端生态来讲究极重要,每个着眼于长远发展、看重开发效率的的互联网公司基本上都会量身定制本身的组件库,它的好处不用多说。对于前端工程师而言,去理解以及掌握它,可让咱们在从此的工做中以及应聘过程当中多出一项特殊技能,而且对自身的纵向发展也就是颇有利的。下面是我记录我在搭建组件库的过程。css
搭建工程不打算采用create-react-app脚手架来搭建,由于脚手架封装好了不少东西,而有些东西对于组件库并不适用,用来搭建组件库过于臃肿,所以我不打算借助任何脚手架来搭建工程。前端
首先,先建立一个工程文件夹pony-react-ui,在该文件夹下执行以下命令:react
npm init // 生成package.json tsc --init // 生成tsconfig.json
而后,按照以下目录结构初始化工程:webpack
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组件应该知足一下需求:web
Button.tsxnpm
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组件以及定义的类型json
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定义的样式,所以才能够在组件外部修改内部的样式。app
举个实例:ui
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的样式