搞轮子:不依赖外部DIY Toast 需要考虑什么
mask(遮罩)
import React, { FC, memo } from "react";
import classnames from "classnames";
import { MaskProps } from "./PropType";
const prefixCls = "jing-mask";
const Mask: FC<MaskProps> = (props) => {
const { className, type, visible, style, onClick } = props;
const classes = classnames(className, prefixCls, {
[`${prefixCls}--${type}`]: !!type,
});
return visible ? (
<div className={classes} style={style} onClick={onClick} />
) : null;
};
Mask.defaultProps = {
type: "normal",
visible: false,
};
export default memo(Mask);
缺点在于它
前提
animation(transition) 组件
mask(遮罩)组件(搞定)
portal 组件
最简单版本的
import React, { FC, useState, useEffect, memo } from "react";
import { createPortal } from "react-dom";
import { PortalProps } from "./PropType";
const Portal: FC<PortalProps> = (props) => {
const { children, container, className } = props;
const [containerEl] = useState(() => {
const el = document.createElement("div");
el.className += `jing-portal__container ${className}`;
return el;
});
useEffect(() => {
document.body.appendChild(container || containerEl);
return () => {
document.body.removeChild(containerEl);
};
}, []);
return createPortal(children, containerEl);
};
export default memo(Portal);
定位 popup,弹出层
popup 组件
使用方式
当作静态函数使用
Toast(…)
Toast.loading()
组件本身要考虑什么功能
遮罩(mask)、内容(message)、是否禁止背景点击(forbidClick),支持自定义图标(icon)、自定义出现的位置(position)、是否在点击遮罩层后关闭(closeOnClickOverlay)
展示时长(duration)、关闭时的回调函数(onClose)
提供 Toast.success 表示成功,
Toast.fail 表示失败
Toast.loading 表示加载
单例模式
allowMultiple
梳理一下
Toast的基础是 Popup,Popup的基础是 Mask 和 Portal
Popup要做的就是弹出层,属于基础组件
Modal 要做之前 popup.alert 之类的事情(Vant 是 Dialog)
Toast 要实例化
无论是 Toast 还是 Modal 都需要使用静态方法调用
Modal 可以大写
popup 和 portal 放一起
不可见的时候看不到元素,
可见的时候渲染元素
动画
react-transition-group 和 portal 的结合
因为 portal 是return 出的组件,所以不会有动画
需要做 animation
有人说给他加 animationDuration
https://codesandbox.io/s/stupefied-bouman-ehszt?file=/src/components/Portal/index.js:517-526
一定会有 div
节点从有到无
animatedVisible 成为 true,显示Portal 组件,先渲染父组件,再渲染子组件
先执行
破除魔咒,取消
useEffect(() => {
mountContainer?.appendChild(containerEl);
return () => {
mountContainer?.removeChild(containerEl);
};
}, []);
react-transition-group 的用法
http://reactcommunity.org/react-transition-group/transition#Transition-prop-onExited
Toast 不是一个组件,而是一个 ”方法“, Toast("提示内容")
怎么把一个 <Toast>提示文字<Toast>
写法的组件改造成 Toast("提示内容")
查看了别人做的 Toast,
先做个 React 版本的 Toast,即组件时写法,然后再将它作为基础组件使用,怎么使用,
生成一个 div(document.createElement(‘div’))
插入 dom 中(bodyContainer.appendChild(container))
ReactDOM.render() 渲染它
我们先完成 Toast 组件
Toast.loading()
需要完成 loading 组件
loading 之后
要 useloading
show
hide
目的是把它当作一个静态函数使用
Loading.
const loading = Loading.useLoading();
<Button
size="xs"
onClick={() => {
loading.show();
setTimeout(() => {
loading.hide();
}, 3000);
}}
>
开启
</Button>
这里有个思考角度,loading 需不需要被 popup 包裹,我的想法是按照实际需求来做组件,我们可以做成像弹出层那样,但是 loading 的用法,一般是作为 Toast 的子组件来使用,所以这里,useLoading 对我们不适用
当然,做这个是为了铺垫 useToast,它也需要具备 Toast.show() 的用法
show 的时候 ReactDOM.render 过程