Open MrSeaWave opened 3 years ago
源码:https://github.com/qq449245884/frank-test-6/blob/master/lib/dialog/dialog.tsx
import React, {Fragment, ReactElement, ReactNode} from 'react'
import ReactDOM from 'react-dom'
import './dialog.scss';
import {Icon} from '../index'
import {scopedClassMaker} from '../helpers/classes'
interface Props {
visible: boolean,
buttons?: Array<ReactElement>,
onClose: React.MouseEventHandler,
closeOnClickMask?: boolean
}
const scopedClass = scopedClassMaker('fui-dialog')
const sc = scopedClass
const Dialog: React.FunctionComponent<Props> = (props) => {
const onClickClose: React.MouseEventHandler = (e) => {
props.onClose(e)
}
const onClickMask: React.MouseEventHandler = (e) => {
if (props.closeOnClickMask) {
props.onClose(e)
}
}
const result = props.visible ?
<Fragment>
<div className={sc('mask')} onClick={onClickMask}>
</div>
<div className={sc('')}>
<div className={sc('close')} onClick={onClickClose}>
<Icon name='close'/>
</div>
<header className={sc('header')}>提示</header>
<main className={sc('main')}>
{props.children}
</main>
{
props.buttons && props.buttons.length &&
<footer className={sc('footer')}>
{
props.buttons && props.buttons.map((button, index) =>
React.cloneElement(button, {key: index})
)
}
</footer>
}
</div>
</Fragment>
:
null
return (
ReactDOM.createPortal(result, document.body)
)
}
Dialog.defaultProps = {
closeOnClickMask: false
}
const modal = (content: ReactNode, buttons ?:Array<ReactElement>, afterClose?: () => void) => {
const close = () => {
// 因为对话框的 visible 是由外部传入的,且 React 是单向数据流的,在组件内并不能直接修改 visible
// 所以在 onClose 方法我们需要再次渲染一个新的组件,并设置新组件 visible 为 false,覆盖原来的组件:
ReactDOM.render(React.cloneElement(component, {visible: false}), div)
// 从 DOM 中卸载组件
ReactDOM.unmountComponentAtNode(div)
div.remove()
afterClose && afterClose()
}
const component =
<Dialog visible={true}
onClose={() => {
// 直接在页面中点击关闭时,触发
close();
afterClose && afterClose()
}}
buttons={buttons}
>
{content}
</Dialog>
const div = document.createElement('div')
document.body.append(div)
ReactDOM.render(component, div)
// 提供手动关闭的能力,close = modal(content)
return close
}
const alert = (content: string) => {
const button = <button onClick={() => close()}>ok</button>
const close = modal(content, [button])
}
const confirm = (content: string, yes?: () => void, no?: () => void) => {
const onYes = () => {
close()
yes && yes()
}
const onNo = () => {
close()
no && no()
}
const buttons = [
<button onClick={onYes}>yes</button>,
<button onClick={onNo}>no</button>
]
const close = modal(content, buttons, no)
}
export {alert, confirm, modal}
export default Dialog