确定API
- 要确保你的API和同行的API没有太大不同,否则用户学习成本变高,不利于我们的UI使用;所以我们就可以去copy下同行的API;
- 提供两种风格:一是标签风格,二是API风格
- 创建dialog目录;
搭建Dialog 基本架子
-
<Fragment></Fragment>
用于把多个div包起来,但是在页面中却不会渲染出来(有点像<template>),所以经常使用<Fragment></Fragment>
来代替<div></div>
; - 我们需要在每个className上都写一遍
dui-dialog-
,岂不是很麻烦?!所以我们写个函数来统一它吧~ - 返回函数的函数叫做高阶函数;
添加CSS
- 这里一个小问题,index.scss要引入到example.tsx中样式才有效!!!!只引入到index.tsx中在预览例子的时候样式不起作用!!!!(应该跟生产开发环境文件设置的入口有关)
- 想要svg受外面字体颜色的控制,加上
fill: currentColor;
- 跟字体相关可以用px、em,跟布局宽度相关可以用min-width结合em;
- 属性选择器,
[class^=xx]
代表所有以xx开头的类;
添加事件
1、可以自定义按钮
- 给dialog一个buttons Props,它是个数组;
- 所以这时又有个小警告了,因为是个数组,需要给每一项设置key,就用到了
React.cloneElement
; - 为什么用
React.cloneElement
,而不是直接button['key'] = index
这样添加属性呢,因为报错啊!!!说不能给只读属性key赋值啊!!!
2、给组件的props设置默认值
Dialog.defaultProps = {
closeonClickMask: false
}
- 一般设置过默认值后,这个props就是可选的,
interface
属性那里加上?
;
3、ReactDOM.createPortal
- ReactDOM.createPortal,这是由于层级问题引起的,给dialog的层级越小越好,这样也方便用户自己去改;
- 一般网站架构师会设定好层级
-
可以在文档中告诉开发者,你如何写可以覆盖我的层级;
注意:为了禁止遮罩层来回滑动,在对话框出现的时候
document.body.style.overflow='hidden'
和document.body.style.paddingRight = '17px'
,关闭的时候恢复document.body.style.overflow='auto'
和document.body.style.paddingRight = '0'
给Dialog提供便利的API——alert
- 动态创建组件,即用
ReactDOM.render()
把组件渲染进div; - 关闭组件呢,即还是用
ReactDOM.render()
渲染组件,只不过是把组件的visible属性变成false; -
ReactDOM.unmountComponentAtNode()
,文档
//创建组件和节点
const div = document.createElement("div");
document.body.appendChild(div);
document.body.style.overflow = 'hidden'
ReactDOM.render(component, div);
//消除组件和节点
//第一句:把这个组件的visible改成false
ReactDOM.render(React.cloneElement(component, {visible: false}), div)
//第二句:把这个组件从div上卸载下来
ReactDOM.unmountComponentAtNode(div)
document.body.style.overflow = 'auto'
//第三句:清除这个div
div.remove()
comfirm
modal
- ReactElement和ReactNode区别:ReactElement只能是标签元素,ReactNode还可以是字符串;
- modal return一个函数出来,有点类似于闭包的形式;
- 下面代码中button调用函数的形式,要写一个箭头函数去调用close(这个close函数是modal()return出来的函数),直接
onClick={close}
的话是不可以的,因为解析器是从右往左执行的,这样直接写,它找不到你声明的close在哪里,放在箭头函数中就可以的原因是,函数是延迟执行的,只有点击按钮时才调用函数; 所以在声明函数的时候不要直接去调用它本身!!!
const openModal = () => {
const close = modal(
<div>
<h1>你好</h1>
<button style={{ color: "purple" }} onClick={() => close()}>
close
</button>
</div>
);
};
三者之前的区别
1、是否有按钮
- alert只有一个【确认】按钮,按钮没有回调函数;
- comfirm有【取消】、【确认】按钮,且按钮有各自的回调函数;
- modal没有按钮;
2、传的内容
- alert和comfirm传的内容仅仅是字符串;
- modal不仅可以传字符串,还可以传元素,但要保证只有一个根元素;
重构
- 写完代码请立即重构,消除重复的代码;
- 看上图,抽出每个API中的part,可以看出它们的组成很相近,所以可以把它们写成一个公共的函数;
总结
- scopedClass 高阶函数;
- React.Fragment
- 使用
&&
或者三元表达式来做条件判断,一般不用if...else...来写条件判断,有点麻烦; -
ReactDOM.createPortal
传送门,可以使元素脱离当前位置到达你指定的节点位置; - 如何动态去生成一个组件;
- 闭包传API;