最近一直在搗鼓如何搭建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的樣式