从零到一搭建React组件库
SegmentFault
共 10030字,需浏览 21分钟
· 2021-04-24
作者:ToSmile
来源:Segmentfault 思否
最近一直在捣鼓如何搭建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组件应该满足一下需求:
不同尺寸 不同类型 不同颜色 禁用状态 点击事件
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>
);
}
export * from './Button';
// 单独引入组件样式
import { Button } from 'pony-react-ui';
import 'pony-react-ui/lib/styles/button.scss';
// 全局引入组件样式,打包时抽离出来的样式
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>
编写样式
├── 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;
}
// 设置按钮大小
@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内部样式,假如组件内部样式有个样式类名为pony-button-promary
.btn {
:global {
.pony-button-promary {
color: #da2227;
}
}
}
.btn {
:global {
// 下次修改Button组件构建后,生成的hash不一定为sadf6756
.pony-button-promary-sadf6756 {
color: #da2227;
}
}
}
打包输出UMD规范
打包输出es module规范
docz生成组件使用文档
发布到npm仓库
评论
了解加密货币到加密货币的互换
1、什么是加密货币互换?加密货币到加密货币的互换是指以现行市场汇率将一种加密货币直接兑换为另一种加密货币。与需要法定货币存款和较长流程的传统交易所不同,加密货币到加密货币的互换可以无缝地促进交换。掉期在提高加密货币的流动性和效率方面发挥着重要作用。该功能使用户能够将他们的加密货币与钱包中的其他代币进
区块链头条
0
AI论文写作工具和生成器(一)
随着人工智能和大模型的迅猛发展,AI对研究人员和学生提供了极大的写作便利。本文将介绍市面上常用的AI论文写作工具,帮助你提高论文写作效率并遵循学术道德。请仅将AI论文生成器视为辅助参考手段,切勿直接挪用全文。XPaper AlXPaper AI是由点击式创作工具晓语台推出的一款论文写作生成平台,只需
IQ前端
0
React正在杀死Angular吗?
点击上方 前端Q,关注公众号回复加群,加入前端Q技术交流群作者 |Hassan Trabelsi
策划 & 翻译 |张卫滨这是一个老生常谈的争论(在技术时代,这是在所难免的):Angular 对战 React。这就像“先有鸡还是先有蛋”的难题,不过这个问题是针对 Web 开发
前端Q
0
delorean,一个超级实用的 Python 库!
作者通常周更,为了不错过更新,请点击上方“Python碎片”,“星标”公众号大家好,今天为大家分享一个超级实用的 Python 库 - delorean。Github地址:https://github.com/myusuf3/delorean/时间在计算机科学和软件开发中是一个至关重要的概念。Pyt
Python 碎片
0
零售业降本增效的新举措:从卖场的能耗入手
导语:对于超市企业来讲,通过节能灯具减少40%以上照明电费,是切实可行的节流方案之一。商超节能,势在必行!零售企业的降本增效从何入手?它们更需要怎样的创新产品与照明解决方案?广东富兴商超照明有限公司总经理唐京飘在第二十届全国连锁商业发展战略论坛上,与大家分享了“如何用科技创新推动超市节能”的主题演讲
联商网资讯
0
某程序员吐槽:公司最近招了一批35左右的,这帮人习惯天天卷到八点多,导致现在我们也要八点才下班
架构师大咖
架构师大咖,打造有价值的架构师交流平台。分享架构师干货、教程、课程、资讯。架构师大咖,每日推送。
公众号该公众号已被封禁某位程序员的吐槽引发了广泛的思考和共鸣。他抱怨公司
源码共读
0
乐普心安宝及心电图机,助力安康市搭建“心电一张网”,打通全域“生命线”!
为持续推动胸痛中心建设,助力全民健康,全面提升心血管疾病等急危重症救治能力水平。4月20日,由安康市卫健委主办、安康市中医医院承办的“第七届心血管汉江学术会议暨安康市胸痛中心大会”在高新国际会议中心顺利举行。市人大常委会主任王彪、市政协副主席唐纹、市政府党组成员刘英华等领导亲临现场,受邀参会的中国科
乐普医疗AI
0
江苏省人民医院外科党总支专家团队到盱眙县人民医院开展惠民医疗活动
党建引领聚合力,共建交流惠民生。4月20日,江苏省人民医院外科党总支专家团队走进盱眙县人民医院开展党建主题活动。江苏省人民医院外科党总支书记、大外科副主任杨力,大外科主任吴延虎,盱眙县人民医院院长干文武出席座谈交流会并讲话,盱眙县人民医院党委委员、副院长刘新亮主持了活动。杨力说,江苏省人民医院和盱眙
盱眙老妹
0