你能使用 typescript 写好一个最简单的 Button 组件吗?
2020/3/24 4:01:21
本文主要是介绍你能使用 typescript 写好一个最简单的 Button 组件吗?,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
先来一个硬广:我在慕课网上线了新课
面对的用户是:想要提高React 水平,写出符合大厂规范代码,了解开源库的发布验证流程的同学,这门课从设计,到渐进式开发,再到单元测试,发布再到 CI/CD 整个流程全覆盖。同时我还为这门课推出了官方的演示网站:http://vikingship.xyz/ ,有所有组件和文档的演示,可以看看。
这里就讲讲组件库实现的第一个组件 Button,大家一看这个组件,应该是觉得太简单啦,这还用学?闭着眼都能写出来,把需求扔过来吧。结果是怎样呢?让我们来试试吧。
第一步:根据原型图完成需求分析
设计师把热乎乎的需求扔到了我的脸上,这是简化了的原型图,去掉了很多需求。
确实看起来也很简单,不就是来回变换 class嘛 ,让一个普通的 button 显示的不一样嘛,这有何难?当然要注意的就是link button,和 disabled 两种状态,它们是两个特殊的属性。将需求分析一下,得到的代码逻辑无非就是这样。
第二步:开始初步编码
好,开始代码,特别注意我们在上面备注提到的两点,typescript 有字符串字面量这种美好的东西,自然适合一系列定死的常量。
// 把要的依赖整出来 import React, { FC } from ‘react’ // 大小两种 size export type ButtonSize = ‘lg’ | ‘sm’ // 四种不同的 type export type ButtonType = ‘primary’ | ‘default’ | ‘danger’ | ‘link’ //属性很重要 确定好它就很完美了 interface BaseButtonProps { className?: string; /**设置 Button 的禁用 _/ disabled?: boolean; /**设置 Button 的尺寸_ / size?: ButtonSize; /**设置 Button 的类型 _/ btnType?: ButtonType; href?: string; }
接下来就可以写组件的主体啦
export const Button: FC<BaseButtonProps> = (props) => { //取出属性 const { btnType, className, disabled, size, children, href, } = props //根据流程图 来渲染不同的内容 if (btnType = ‘link’ && href ) { return ( <a href={href}> {children} </a> ) } else { return ( <button> {children} </button> ) }}
接下来就是工作的大头 拼接 class 了,这里让找出我们的 添加 class 好帮手 https://github.com/JedWatson/classnames#readme 大家自己研究文档,用法我就不累赘了。
// btn, btn-lg, btn-primary, // 添加根据type 和 size 两类特殊的 class 名称 const classes = classNames(‘btn’, className, { [`btn-${btnType}`]: btnType, [`btn-${size}`]: size, })
别忘了我们说过的特殊 disabled 属性,button 天然支持这个属性,而 a 链接没有这么一个属性,所以我们需要用样式来模拟这个属性,所以我们给 a 链接添加一个特殊的 class,然后把它们填充到 button 和 a 元素上。
const classes = classNames(‘btn’, className, { … // link 用来模拟 disabled 的样式和行为欧! ‘disabled’: (btnType = ‘link’) && disabled }) … <a className={classes} href={href} > {children} </a> … <button className={classes} // 我是原生属性! disabled={disabled} > {children} </button>
第三步:弄点好看的样式
结构到这里没啥问题,接下来就来添加样式,我们使用 scss,样式我不会多写,但是我们要学会两点:1 将一些数值定义成变量,假如我们要做一个组件库,那么用户自定义也是非常重要的,通过这种方法,可以让用户覆盖你的默认样式。2 使用 mixin 来梳理可以重复的逻辑,比如这里的大小和不同的 type 明显就是两个不同的 mixin。
.btn { … 各种样式 font-weight: $btn-font-weight; line-height: $btn-line-height; color: $body-color; box-shadow: none; @include button-size( $btn-padding-y, $btn-padding-x, $btn-font-size, $border-radius); &.disabled, &[disabled] { cursor: not-allowed; opacity: $btn-disabled-opacity; box-shadow: none; > * { pointer-events: none; } } } } .btn-lg { @include button-size($btn-padding-y-lg, $btn-padding-x-lg, $btn-font-size-lg, $btn-border-radius-lg); } .btn-sm { @include button-size($btn-padding-y-sm, $btn-padding-x-sm, $btn-font-size-sm, $btn-border-radius-sm); } .btn-primary { @include button-style($primary, $primary, $white) } .btn-danger { @include button-style($danger, $danger, $white) } .btn-default { @include button-style($white, $gray-400, $body-color, $white, $primary, $primary) } //对于 link ,比较特殊,给它单独拿出来 .btn-link { // … 省略掉各种样式 // 特殊处理 disabled &:disabled, &.disabled { color: $btn-link-disabled-color; pointer-events: none; } }
看看它们长得怎样?
看上去不错,让我们来试试它配合 ts 是否方便,联想是否智能,看看下面这个 gif。
初次感受还不错,那么这个简单的组件是否完美了?大家都知道 button 组件和 a 链接都是标准的 HTML 元素,它们都有很多原生的属性,https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/button,button 有比如 name,type,a链接有 target,rel 等等。现在我们在组件中输入这些属性根本没用!自然就没有 ts 的自动补全,这是一个大问题。
第四步:继续编码 - 进化组件
大家都知道这些原生属性有一大堆,你看了 mdn 的文档就知道,难道我们要一个一个写出来嘛?那样太麻烦了,可以直接放弃了。这时候 React 里面预定义的属性和 ts 的内置类型来帮我们了,我们来看看怎么做把!
// react 内置了 button 和 anchor 的类型,里面有它们的全部属性,你可以按住 cmd点击一下试试 import React, { FC, ButtonHTMLAttributes, AnchorHTMLAttributes } from ‘react’ //下面我们要做的就是扩充已经创建好的 ButtonProps,我们使用 ts 的交叉类型来完成它 type NativeButtonProps = BaseButtonProps & ButtonHTMLAttributes<HTMLElement> type AnchorButtonProps = BaseButtonProps & AnchorHTMLAttributes<HTMLElement> // 最后,让我们把它们合体,重建,然后用ts 内置的 Partial 把这些属性都转换成可选 export type ButtonProps = Partial<NativeButtonProps & AnchorButtonProp>
这样 ButtonProps 就拥有了这些各种各样的原生属性。现在让我们把这些属性取出来并且放置在组件上,
const { btnType, className, disabled, size, children, href, // 使用最好用的 三个点 spread 把剩下的属性都取出来 …restProps } = props //然后再照猫画虎用 spread 赋值在组件上 return ( <a className={classes} href={href} {…restProps} > {children} </a> ) return ( <button className={classes} disabled={disabled} {…restProps} > {children} </button> )
好,最后来试试这些原生属性是否会借 ts 的东风,自动填充出来。
第五步:未完待续
好,那么到目前为止,我们做出了一个看起来还不错的 Button 组件,其实我们能完成的更多,比如说现在测试完全靠肉眼,需要给它单元测试,假如是一款企业级产品,我们需要自动生成文档,还需要打包成合适的模块类型以及发布到 npm 等等工作。现在是不是感觉,这么一个简单的组件也不是那么简单的,如果一个 Button 组件成功的提起了你的兴趣,不妨来看看和我一起完成一个组件库是多么有趣的一个过程把。
这篇关于你能使用 typescript 写好一个最简单的 Button 组件吗?的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-05-15PingCAP 黄东旭参与 CCF 秀湖会议,共探开源教育未来
- 2024-05-13PingCAP 戴涛:构建面向未来的金融核心系统
- 2024-05-09flutter3.x_macos桌面os实战
- 2024-05-09Rust中的并发性:Sync 和 Send Traits
- 2024-05-08使用Ollama和OpenWebUI在CPU上玩转Meta Llama3-8B
- 2024-05-08完工标准(DoD)与验收条件(AC)究竟有什么不同?
- 2024-05-084万 star 的 NocoDB 在 sealos 上一键起,轻松把数据库编程智能表格
- 2024-05-08Mac 版Stable Diffusion WebUI的安装
- 2024-05-08解锁CodeGeeX智能问答中3项独有的隐藏技能
- 2024-05-08RAG算法优化+新增代码仓库支持,CodeGeeX的@repo功能效果提升