共计 4287 个字符,预计需要花费 11 分钟才能阅读完成。
什么是 dumi
dumi,中文发音嘟米,是一款为组件开发场景而生的文档工具,与 father 一起为开发者提供一站式的组件开发体验,father 负责构建,而 dumi 负责组件开发及组件文档生成。
个性
- 📦 开箱即用,将注意力集中在组件开发和文档编写上
- 📋 丰盛的 Markdown 扩大,不止于渲染组件 demo
- 🏷 基于 TypeScript 类型定义,主动生成组件 API
- 🎨 主题轻松自定义,还可创立本人的 Markdown 组件
- 📱 反对挪动端组件库研发,内置挪动端高清渲染计划
- 📡 一行命令将组件资产数据化,与上游生产力工具串联
环境筹备
首先得有 node,并确保 node 版本是 10.13 或以上。
$ node -v | |
v10.13.0 |
初始化脚手架
创立空文件夹mkdir dumi-ui-site-template
初始化一个站点模式的组价库开发脚手架
$ yarn create @umijs/dumi-lib --site
运行
执行 npm run dev
或 npx dumi dev
即可开始调试组件或编写文档。
执行成果如下:
开发一个 button 组件
在 src
上面创立文件 Button
文件。
外围代码
index.tsx
import React, {useState} from 'react'; | |
import styled from 'styled-components'; | |
import clsx from 'clsx'; | |
import * as vars from '../styles/vars'; | |
import {isMobile} from '../utils/dom'; | |
import {getThemeColorCss} from '../styles/themeHelper'; | |
type Props = { | |
/** default 线框,primary 实色框 */ | |
type?: 'default' | 'primary'; | |
/** 线框应用主题色 */ | |
active?: boolean; | |
/** 禁用 */ | |
disabled?: boolean; | |
/** 自定义 style */ | |
style?: React.CSSProperties; | |
/** 按钮类型 */ | |
htmlType?: 'submit' | 'reset' | 'button' | undefined; | |
/** 块级按钮 */ | |
block?: boolean; | |
children?: React.ReactNode; | |
/** 自定义 className */ | |
className?: string; | |
/** 圆形按钮 */ | |
circle?: boolean; | |
/** 虚线边 */ | |
dashed?: boolean; | |
/** 设置危险按钮 */ | |
danger?: boolean; | |
/** 设置为展现的标签,比方 div,a,button */ | |
as?: any; | |
/** 设置按钮的图标组件 */ | |
icon?: React.ReactNode; | |
/** 设置按钮加载状态 */ | |
loading?: boolean; | |
/** 是否幽灵按钮 */ | |
ghost?: boolean; | |
/** 点击回调 */ | |
onClick?: (e: React.SyntheticEvent) => void; | |
/** 点击后,下次能点击的工夫距离,避免反复点击, 如果是 true, 距离默认是 1s */ | |
wait?: number | boolean; | |
}; | |
const StyledButton = styled.button` | |
color: inherit; | |
cursor: pointer; | |
margin: 0; | |
display: inline-flex; | |
box-sizing: border-box; | |
outline: 0; | |
position: relative; | |
align-items: center; | |
user-select: none; | |
vertical-align: middle; | |
justify-content: center; | |
text-decoration: none; | |
background-color: transparent; | |
appearance: none; | |
-webkit-tap-highlight-color: transparent; | |
font-weight: 400; | |
white-space: nowrap; | |
background-image: none; | |
transition: all 0.3s ease; | |
user-select: none; | |
touch-action: manipulation; | |
padding: 4px 16px; | |
font-size: 14px; | |
border-radius: 2px; | |
border: 1px solid transparent; | |
height: 32px; | |
&.default { | |
background-color: #fff; | |
border-color: ${vars.border}; | |
${isMobile ? '&:active' : '&:hover'} {opacity: 0.8;} | |
&.pc:hover, | |
&.active {${getThemeColorCss('border-color')} | |
${getThemeColorCss('color')} | |
} | |
&.mobile:active {background-color: ${vars.activeBg}; | |
} | |
&.danger, | |
&.danger:hover, | |
&.danger:active {color: ${vars.danger}; | |
border-color: ${vars.danger}; | |
} | |
} | |
&.primary {${getThemeColorCss('background-color')} | |
${getThemeColorCss('border-color')} | |
color: #fff; | |
${isMobile ? '&:active' : '&:hover'} {opacity: 0.8;} | |
&.danger, | |
&.danger:hover, | |
&.danger:active {background-color: ${vars.danger}; | |
border-color: ${vars.danger}; | |
} | |
} | |
&.disabled, | |
&.disabled:hover, | |
&.disabled:active { | |
cursor: not-allowed; | |
opacity: 0.6; | |
pointer-events: none; | |
} | |
&.block {width: 100%;} | |
&.circle { | |
min-width: 32px; | |
padding: 0; | |
border-radius: 50%; | |
} | |
&.dashed {border-style: dashed;} | |
&.ghost, | |
&.ghost:hover {color: ${vars.border}; | |
background-color: transparent; | |
border-color: ${vars.border}; | |
} | |
&.anchor { | |
margin: unset; | |
padding: unset; | |
background: unset; | |
border: none; | |
${getThemeColorCss('color')} | |
height: unset; | |
} | |
`; | |
const Button = React.forwardRef<HTMLButtonElement, Props>((props, ref) => { | |
const { | |
children, | |
type = 'default', | |
disabled, | |
block, | |
active, | |
danger, | |
circle, | |
dashed, | |
loading, | |
ghost, | |
className, | |
htmlType, | |
onClick, | |
wait, | |
...rest | |
} = props; | |
return ( | |
<StyledButton | |
{...rest} | |
ref={ref} | |
disabled={disabled} | |
type={htmlType} | |
className={clsx( | |
'uc-btn', | |
type, | |
{ | |
disabled: disabled || loading, | |
block: block, | |
danger: danger, | |
circle: circle, | |
dashed: dashed, | |
ghost: ghost, | |
pc: !isMobile, | |
anchor: rest.as === 'a', | |
active, | |
}, | |
className, | |
)} | |
> | |
{children} | |
</StyledButton> | |
); | |
}); | |
Button.displayName = 'UC-Button'; | |
export default Button; |
index.md
--- | |
title: Button 按钮 | |
order: 0 | |
group: | |
title: 根底组件 | |
nav: | |
title: '组件' | |
path: /components | |
--- | |
## Demo | |
<code src="../../demo/Button/index.jsx"></code> | |
<API src="./index.tsx"></API> |
API 间接从 ts 类型定义中主动生成
Demo 代码
在根目录创立 demo
文件夹,而后创立一个 Button
文件夹,创立一个 index.tsx
文件,
import React from 'react'; | |
import {Button} from 'dumi-ui-site-template'; | |
export default function App() { | |
return ( | |
<> | |
<div title="根底按钮"> | |
<Button>Default</Button> | |
<Button active>Outline</Button> | |
<Button danger>Danger</Button> | |
<Button type="primary">Primary</Button> | |
<Button type="primary" danger> | |
Primary | |
</Button> | |
</div> | |
<div title="块级按钮"> | |
<Button block>Block default</Button> | |
<Button block type="primary"> | |
Block primary | |
</Button> | |
<Button block danger dashed> | |
Block danger | |
</Button> | |
</div> | |
</> | |
); | |
} |
这样一个根底的 Button 组件就构建好了,最初在 src/index.ts
文件中裸露进来
export {default as Button} from './Button';
预览成果
构建
- 构建站点文档
npm run docs:build
构建产物输入到docs-dist
- 构建组件开发脚手架
npm run build
构建产物输入到es
系列文章
罕用 UI 组件库情谊举荐
- ant design
- Element
- Naive UI
我是朽木白,一个酷爱分享的程序猿。如果感觉本文还不错,记得 三连 + 关注,说不定哪天就用得上!您的激励是我坚持下去的最大能源❤️。
正文完