Tsx写一个通用的button组件
一年又要到年底了,vue3.0都已经出来了,我们也不能一直还停留在过去的js中,是时候学习并且在项目中使用一下Ts了。
如果说jsx是基于js的话,那么tsx就是基于typescript的
废话也不多说,让我们开始写一个Tsx形式的button组件,
ts真的不仅仅只有我们常常熟知的数据类型,还包括接口,类,枚举,泛型,等等等,这些都是特别重要的
项目是基于vue-cli 3.0 下开发的,可以自己配置Ts,不会的话那你真的太难了
我们再compenonts中新建一个button文件夹,再建一个unit文件夹,button放button组件的代码,unit,放一些公共使用模块
我们再button文件夹下创建 ,index .tsx放的button源码,index.less放的是样式,css也是不可缺少的
分析一下button需要的一些东西
第一个当然是props,还有一个是点击事件,所以我们第一步就定义一下这两个类型
type ButtonProps = {
tag: string,
size: ButtonSize,
type: ButtonType,
text: String
} type ButtonEvents = {
onClick?(event: Event) :void
}
type ButtonSize = 'large' | 'normal' | 'small' | 'mini'
type ButtonType = 'default' | 'primary' | 'info' | 'warning' | 'danger'
因为button是很简单的组件,内部也没有一些特别的状态需要改变,所以我们用函数式组件的方式去写(之后的render会用到这个方法)
function Button (h: CreateElement, props: ButtonProps, slots: DefaultSlots, ctx: RenderContext<ButtonProps>) {
const { tag, size, type } = props
let text
console.log(slots)
text = slots.default ? slots.default() : props.text
function onClick (event: Event) {
emit(ctx, 'click', event)
}
let classes = [size,type]
return (
<tag
onClick = {onClick}
class = {classes}
>
{text}
</tag>
)
}
h 是一个预留参数,这里并没有用到 ,CreateElement 这个是vue从2.5之后提供的一个类型,也是为了方便在vue项目上使用ts
props 就是button组件的传入的属性,slots插槽,ctx,代表的是当前的组件,可以理解为当前rendercontext执行环境this
DefaultSlots是我们自定义的一个插槽类型
export type ScopedSlot<Props = any> = (props?: Props) => VNode[] | VNode | undefined; export type ScopedSlots = {
[key: string]: ScopedSlot | undefined;
}
插槽的内容我们都是需要从ctx中读取的,默认插槽的key就是defalut,具名插槽就是具体的name
button放发内部还有一个具体的点击事件,还有一个emit方法,从名字我们也可以看的出,他是粗发自定义事件的,我们这里当然不能使用this.emit去促发,
所以我们需要单独这个emit方法,我们知道组件内所以的自定义事件都是保存在listeners里的,我们从ctx中拿取到所以的listeners
function emit (context: RenderContext, eventName: string, ...args: any[]) {
const listeners = context.listeners[eventName]
if (listeners) {
if (Array.isArray(listeners)) {
listeners.forEach(listener => {
listener(...args)
})
} else {
listeners(...args)
}
}
这样我们组件内部的事件触发就完成了
我们的button肯定是有一些默认的属性,所以,我们给button加上默认的属性
Button.props = {
text: String,
tag: {
type: String,
default: 'button'
},
type: {
type: String,
default: 'default'
},
size: {
type: String,
default: 'normal'
}
}
我们定义一个通用的functioncomponent 类型
type FunctionComponent<Props=DefaultProps, PropsDefs = PropsDefinition<Props>> = {
(h: CreateElement, Props:Props, slots: ScopedSlots, context: RenderContext<Props>): VNode |undefined,
props?: PropsDefs
}
PropsDefinition<T> 这个是vue内部提供的,对 props的约束定义
不管怎么样我们最终返回的肯定是一个对象,我们把这个类型也定义一下
ComponentOptions<Vue> 这个也是vue内部提供的
interface DrmsComponentOptions extends ComponentOptions<Vue> {
functional?: boolean;
install?: (Vue: VueConstructor) => void;
}
最终生成一个组件对象
function transformFunctionComponent (fn:FunctionComponent): DrmsComponentOptions {
return {
functional: true, // 函数时组件,这个属性一定要是ture,要不render方法,第二个context永远为underfine
props: fn.props,
model: fn.model,
render: (h, context): any => fn(h, context.props, unifySlots(context), context)
}
}
unifySlots 是读取插槽的内容
// 处理插槽的内容
export function unifySlots (context: RenderContext) {
// use data.scopedSlots in lower Vue version
const scopedSlots = context.scopedSlots || context.data.scopedSlots || {}
const slots = context.slots() Object.keys(slots).forEach(key => {
if (!scopedSlots[key]) {
scopedSlots[key] = () => slots[key]
}
}) return scopedSlots
}
当然身为一个组件,我们肯定是要提供全局注入接口,并且能够按需导入
所以我们给组件加上名称和install方法,install 是 vue.use() 方法使用的,这样我们能全部注册组件
export function CreateComponent (name:string) {
return function <Props = DefaultProps, Events = {}, Slots = {}> (
sfc:DrmsComponentOptions | FunctionComponent) {
if (typeof sfc === 'function') {
sfc = transformFunctionComponent(sfc)
}
sfc.functional = true
sfc.name = 'drms-' + name
sfc.install = install
return sfc
}
}
index.tsx 中的最后一步,导出这个组件
export default CreateComponent('button')<ButtonProps, ButtonEvents>(Button)
还少一个install的具体实现方法,加上install方法,就能全局的按需导入了
function install (this:ComponentOptions<Vue>, Vue:VueConstructor) {
const { name } = this
Vue.component(name as string, this)
}
最终实现的效果图,事件的话也是完全ok的,这个我也是测过的
代码参考的是vant的源码:https://github.com/youzan/vant
该代码已经传到git: https://github.com/czklove/DrpsUI dev分支应该是代码全的,master可能有些并没有合并
Tsx写一个通用的button组件的更多相关文章
- 写一个通用的List集合导出excel的通用方法
前几天要做一个数据导出Excel 我就打算写一个通用的. 这样一来用的时候也方便,数据主要是通过Orm取的List.这样写一个通用的刚好. public static void ListToExcel ...
- 手写一个简单的starter组件
spring-boot中有很多第三方包,都封装成starter组件,在maven中引用后,启动springBoot项目时会自动装配到spring ioc容器中. 思考: 为什么我们springBoot ...
- 《用Java写一个通用的服务器程序》01 综述
最近一两年用C++写了好几个基于TCP通信类型程序,都是写一个小型的服务器,监听请求,解析自定义的协议,处理请求,返回结果.每次写新程序时都把老代码拿来,修改一下协议解析部分和业务处理部分,然后就一个 ...
- 一步一步写一个简单通用的makefile(四)--写一个通用的makefile编译android可执行文件
通常要把我们自己的的代码编译成在android里面编译的可执行文件,我们通常是建一个文件夹 . ├── Android.mk ├── Application.mk ├── convolve.cl ├─ ...
- 《用Java写一个通用的服务器程序》02 监听器
在一个服务器程序中,监听器的作用类似于公司前台,起引导作用,因此监听器花在每个新连接上的时间应该尽可能短,这样才能保证最快响应. 回到编程本身来说: 1. 监听器最好由单独的线程运行 2. 监听器在接 ...
- 如何写一个全局的 Notice 组件?
下面将会实现这样的效果: 组件动态创建脚本: NotificationBanner.js import Vue from "vue"; import Notice from &qu ...
- 《用Java写一个通用的服务器程序》03 处理新socket
在讲监听器时说过处理的新的socket要尽快返回,监听器调用的是ClientFactory的createPhysicalConnection方法,那么就来看这个方法: public boolean c ...
- python安装及写一个简单的验证码组件(配合node)
1.安装Python 到官网下载响应系统的版本(这里以windows为例):https://www.python.org/downloads/windows/ 然后就是不断地"下一步&quo ...
- 如何写一个通用的README规范
背景 我们平常在进行项目开发时,一般都会把代码上传至代码托管平台上方便管理和维护.目前我厂使用的托管平台是SVN,国内外还有一些比较知名的代码托管平台,比如github.Gitlab.BitBucke ...
随机推荐
- [Luogu2593] [ZJOI2006]超级麻将
题目地址 :https://www.luogu.org/problemnew/show/P2593. 无脑DP(虽说是抄的额) #include <iostream> #include & ...
- Centos7.4环境下搭建Python开发环境(虚拟机安装+python安装+pycharm安装)
目录 一.安装 Centos7.4虚拟机 二.安装 python3.6.7 三.安装 pycharm 一般情况下,大家都是在 Windows平台下进行 Python开发,软件安装和环境搭建都非常&qu ...
- Mac系统 安装Photoshop CC 2018破解版
应用场景 本人从事前端行业,但是工作中有时也需要会点PS技能,之前一直使用window系统,突然换了Mac其他软件基本都差不多安装完了,就剩下比较难搞的PS.刚开始按照网上乱七八槽的教程下载过好多次都 ...
- “无处不在” 的系统核心服务 —— ActivityManagerService 启动流程解析
本文基于 Android 9.0 , 代码仓库地址 : android_9.0.0_r45 系列文章目录: Java 世界的盘古和女娲 -- Zygote Zygote 家的大儿子 -- System ...
- 你不知道的DIV+CSS的命名规则
搜索引擎优化(seo)有很多工作要做,其中对代码的优化是一个很关键的步骤.为了更加符合SEO的规范,下面是目前比较好的CSS+DIV的命名规则 1DIV CLASS或者ID 页头:header 登录条 ...
- CocosCreator中_worldMatrix到底是什么(下)
Cocos Creator 中 _worldMatrix 到底是什么(下) 1. 摘要 上篇介绍了矩阵的基本知识以及对应图形变换矩阵推倒.中篇具体介介绍了对应矩阵转换成cocos creator代码的 ...
- 使用FastReport报表工具生成标签打印文档
在我们实际开发报表的时候,我们需要按一定的业务规则组织好报表的模板设计,让报表尽可能的贴近实际的需求,在之前的随笔中<使用FastReport报表工具生成报表PDF文档>介绍了FastRe ...
- Shiro权限管理框架(四):深入分析Shiro中的Session管理
其实关于Shiro的一些学习笔记很早就该写了,因为懒癌和拖延症晚期一直没有落实,直到今天公司的一个项目碰到了在集群环境的单点登录频繁掉线的问题,为了解决这个问题,Shiro相关的文档和教程没少翻.最后 ...
- Python标准库---random模块的使用
更新时间:2019.09.12(更新目录) 目录 1. 谈谈随机数 2. random模块 2.1 random.seed() 2.2 random.random() 2.3 random ...
- JSONP安全防御要点
严格安全地实现CSRF方式调用JSON文件:限制Referer.部署一次性token等. 严格安装JSON格式标准输出Content-Type及编码(Content-Type: application ...