Modal对话框

模态对话框。

何时使用

需要用户处理事务,又不希望跳转页面以致打断工作流程时,可以使用 Modal 在当前页面正中打开一个浮层,承载相应的操作。

另外当需要一个简洁的确认框询问用户时,可以使用 Modal.confirm() 等语法糖方法。

代码演示

Modal对话框 - 图1

基本

第一个对话框。

  1. import { Modal, Button } from 'antd';
  2. class App extends React.Component {
  3. state = { visible: false };
  4. showModal = () => {
  5. this.setState({
  6. visible: true,
  7. });
  8. };
  9. handleOk = e => {
  10. console.log(e);
  11. this.setState({
  12. visible: false,
  13. });
  14. };
  15. handleCancel = e => {
  16. console.log(e);
  17. this.setState({
  18. visible: false,
  19. });
  20. };
  21. render() {
  22. return (
  23. <div>
  24. <Button type="primary" onClick={this.showModal}>
  25. Open Modal
  26. </Button>
  27. <Modal
  28. title="Basic Modal"
  29. visible={this.state.visible}
  30. onOk={this.handleOk}
  31. onCancel={this.handleCancel}
  32. >
  33. <p>Some contents...</p>
  34. <p>Some contents...</p>
  35. <p>Some contents...</p>
  36. </Modal>
  37. </div>
  38. );
  39. }
  40. }
  41. ReactDOM.render(<App />, mountNode);

Modal对话框 - 图2

自定义页脚

更复杂的例子,自定义了页脚的按钮,点击提交后进入 loading 状态,完成后关闭。

不需要默认确定取消按钮时,你可以把 footer 设为 null

  1. import { Modal, Button } from 'antd';
  2. class App extends React.Component {
  3. state = {
  4. loading: false,
  5. visible: false,
  6. };
  7. showModal = () => {
  8. this.setState({
  9. visible: true,
  10. });
  11. };
  12. handleOk = () => {
  13. this.setState({ loading: true });
  14. setTimeout(() => {
  15. this.setState({ loading: false, visible: false });
  16. }, 3000);
  17. };
  18. handleCancel = () => {
  19. this.setState({ visible: false });
  20. };
  21. render() {
  22. const { visible, loading } = this.state;
  23. return (
  24. <div>
  25. <Button type="primary" onClick={this.showModal}>
  26. Open Modal with customized footer
  27. </Button>
  28. <Modal
  29. visible={visible}
  30. title="Title"
  31. onOk={this.handleOk}
  32. onCancel={this.handleCancel}
  33. footer={[
  34. <Button key="back" onClick={this.handleCancel}>
  35. Return
  36. </Button>,
  37. <Button key="submit" type="primary" loading={loading} onClick={this.handleOk}>
  38. Submit
  39. </Button>,
  40. ]}
  41. >
  42. <p>Some contents...</p>
  43. <p>Some contents...</p>
  44. <p>Some contents...</p>
  45. <p>Some contents...</p>
  46. <p>Some contents...</p>
  47. </Modal>
  48. </div>
  49. );
  50. }
  51. }
  52. ReactDOM.render(<App />, mountNode);

Modal对话框 - 图3

信息提示

各种类型的信息提示,只提供一个按钮用于关闭。

  1. import { Modal, Button, Space } from 'antd';
  2. function info() {
  3. Modal.info({
  4. title: 'This is a notification message',
  5. content: (
  6. <div>
  7. <p>some messages...some messages...</p>
  8. <p>some messages...some messages...</p>
  9. </div>
  10. ),
  11. onOk() {},
  12. });
  13. }
  14. function success() {
  15. Modal.success({
  16. content: 'some messages...some messages...',
  17. });
  18. }
  19. function error() {
  20. Modal.error({
  21. title: 'This is an error message',
  22. content: 'some messages...some messages...',
  23. });
  24. }
  25. function warning() {
  26. Modal.warning({
  27. title: 'This is a warning message',
  28. content: 'some messages...some messages...',
  29. });
  30. }
  31. ReactDOM.render(
  32. <Space>
  33. <Button onClick={info}>Info</Button>
  34. <Button onClick={success}>Success</Button>
  35. <Button onClick={error}>Error</Button>
  36. <Button onClick={warning}>Warning</Button>
  37. </Space>,
  38. mountNode,
  39. );

Modal对话框 - 图4

手动更新和移除

手动更新和关闭 Modal.method 方式创建的对话框。

  1. import { Modal, Button } from 'antd';
  2. function countDown() {
  3. let secondsToGo = 5;
  4. const modal = Modal.success({
  5. title: 'This is a notification message',
  6. content: `This modal will be destroyed after ${secondsToGo} second.`,
  7. });
  8. const timer = setInterval(() => {
  9. secondsToGo -= 1;
  10. modal.update({
  11. content: `This modal will be destroyed after ${secondsToGo} second.`,
  12. });
  13. }, 1000);
  14. setTimeout(() => {
  15. clearInterval(timer);
  16. modal.destroy();
  17. }, secondsToGo * 1000);
  18. }
  19. ReactDOM.render(<Button onClick={countDown}>Open modal to close in 5s</Button>, mountNode);

Modal对话框 - 图5

销毁确认对话框

使用 Modal.destroyAll() 可以销毁弹出的确认窗。通常用于路由监听当中,处理路由前进、后退不能销毁确认对话框的问题。

  1. import { Modal, Button } from 'antd';
  2. import { ExclamationCircleOutlined } from '@ant-design/icons';
  3. function destroyAll() {
  4. Modal.destroyAll();
  5. }
  6. const { confirm } = Modal;
  7. function showConfirm() {
  8. for (let i = 0; i < 3; i += 1) {
  9. setTimeout(() => {
  10. confirm({
  11. icon: <ExclamationCircleOutlined />,
  12. content: <Button onClick={destroyAll}>Click to destroy all</Button>,
  13. onOk() {
  14. console.log('OK');
  15. },
  16. onCancel() {
  17. console.log('Cancel');
  18. },
  19. });
  20. }, i * 500);
  21. }
  22. }
  23. ReactDOM.render(
  24. <div>
  25. <Button onClick={showConfirm}>Confirm</Button>
  26. </div>,
  27. mountNode,
  28. );

Modal对话框 - 图6

使用 hooks 获得上下文

通过 Modal.useModal 创建支持读取 context 的 contextHolder

  1. import { Modal, Button, Space } from 'antd';
  2. const ReachableContext = React.createContext();
  3. const UnreachableContext = React.createContext();
  4. const config = {
  5. title: 'Use Hook!',
  6. content: (
  7. <div>
  8. <ReachableContext.Consumer>{name => `Reachable: ${name}!`}</ReachableContext.Consumer>
  9. <br />
  10. <UnreachableContext.Consumer>{name => `Unreachable: ${name}!`}</UnreachableContext.Consumer>
  11. </div>
  12. ),
  13. };
  14. const App = () => {
  15. const [modal, contextHolder] = Modal.useModal();
  16. return (
  17. <ReachableContext.Provider value="Light">
  18. <Space>
  19. <Button
  20. onClick={() => {
  21. modal.confirm(config);
  22. }}
  23. >
  24. Confirm
  25. </Button>
  26. <Button
  27. onClick={() => {
  28. modal.warning(config);
  29. }}
  30. >
  31. Warning
  32. </Button>
  33. <Button
  34. onClick={() => {
  35. modal.info(config);
  36. }}
  37. >
  38. Info
  39. </Button>
  40. <Button
  41. onClick={() => {
  42. modal.error(config);
  43. }}
  44. >
  45. Error
  46. </Button>
  47. </Space>
  48. {/* `contextHolder` should always under the context you want to access */}
  49. {contextHolder}
  50. {/* Can not access this context since `contextHolder` is not in it */}
  51. <UnreachableContext.Provider value="Bamboo" />
  52. </ReachableContext.Provider>
  53. );
  54. };
  55. ReactDOM.render(<App />, mountNode);

Modal对话框 - 图7

异步关闭

点击确定后异步关闭对话框,例如提交表单。

  1. import { Modal, Button } from 'antd';
  2. class App extends React.Component {
  3. state = {
  4. ModalText: 'Content of the modal',
  5. visible: false,
  6. confirmLoading: false,
  7. };
  8. showModal = () => {
  9. this.setState({
  10. visible: true,
  11. });
  12. };
  13. handleOk = () => {
  14. this.setState({
  15. ModalText: 'The modal will be closed after two seconds',
  16. confirmLoading: true,
  17. });
  18. setTimeout(() => {
  19. this.setState({
  20. visible: false,
  21. confirmLoading: false,
  22. });
  23. }, 2000);
  24. };
  25. handleCancel = () => {
  26. console.log('Clicked cancel button');
  27. this.setState({
  28. visible: false,
  29. });
  30. };
  31. render() {
  32. const { visible, confirmLoading, ModalText } = this.state;
  33. return (
  34. <div>
  35. <Button type="primary" onClick={this.showModal}>
  36. Open Modal with async logic
  37. </Button>
  38. <Modal
  39. title="Title"
  40. visible={visible}
  41. onOk={this.handleOk}
  42. confirmLoading={confirmLoading}
  43. onCancel={this.handleCancel}
  44. >
  45. <p>{ModalText}</p>
  46. </Modal>
  47. </div>
  48. );
  49. }
  50. }
  51. ReactDOM.render(<App />, mountNode);

Modal对话框 - 图8

确认对话框

使用 confirm() 可以快捷地弹出确认框。onCancel/onOk 返回 promise 可以延迟关闭。

  1. import { Modal, Button, Space } from 'antd';
  2. import { ExclamationCircleOutlined } from '@ant-design/icons';
  3. const { confirm } = Modal;
  4. function showConfirm() {
  5. confirm({
  6. title: 'Do you Want to delete these items?',
  7. icon: <ExclamationCircleOutlined />,
  8. content: 'Some descriptions',
  9. onOk() {
  10. console.log('OK');
  11. },
  12. onCancel() {
  13. console.log('Cancel');
  14. },
  15. });
  16. }
  17. function showPromiseConfirm() {
  18. confirm({
  19. title: 'Do you want to delete these items?',
  20. icon: <ExclamationCircleOutlined />,
  21. content: 'When clicked the OK button, this dialog will be closed after 1 second',
  22. onOk() {
  23. return new Promise((resolve, reject) => {
  24. setTimeout(Math.random() > 0.5 ? resolve : reject, 1000);
  25. }).catch(() => console.log('Oops errors!'));
  26. },
  27. onCancel() {},
  28. });
  29. }
  30. function showDeleteConfirm() {
  31. confirm({
  32. title: 'Are you sure delete this task?',
  33. icon: <ExclamationCircleOutlined />,
  34. content: 'Some descriptions',
  35. okText: 'Yes',
  36. okType: 'danger',
  37. cancelText: 'No',
  38. onOk() {
  39. console.log('OK');
  40. },
  41. onCancel() {
  42. console.log('Cancel');
  43. },
  44. });
  45. }
  46. function showPropsConfirm() {
  47. confirm({
  48. title: 'Are you sure delete this task?',
  49. icon: <ExclamationCircleOutlined />,
  50. content: 'Some descriptions',
  51. okText: 'Yes',
  52. okType: 'danger',
  53. okButtonProps: {
  54. disabled: true,
  55. },
  56. cancelText: 'No',
  57. onOk() {
  58. console.log('OK');
  59. },
  60. onCancel() {
  61. console.log('Cancel');
  62. },
  63. });
  64. }
  65. ReactDOM.render(
  66. <Space>
  67. <Button onClick={showConfirm}>Confirm</Button>
  68. <Button onClick={showPromiseConfirm}>With promise</Button>
  69. <Button onClick={showDeleteConfirm} type="dashed">
  70. Delete
  71. </Button>
  72. <Button onClick={showPropsConfirm} type="dashed">
  73. With extra props
  74. </Button>
  75. </Space>,
  76. mountNode,
  77. );

Modal对话框 - 图9

国际化

设置 okTextcancelText 以自定义按钮文字。

  1. import { Modal, Button } from 'antd';
  2. import { ExclamationCircleOutlined } from '@ant-design/icons';
  3. class LocalizedModal extends React.Component {
  4. state = { visible: false };
  5. showModal = () => {
  6. this.setState({
  7. visible: true,
  8. });
  9. };
  10. hideModal = () => {
  11. this.setState({
  12. visible: false,
  13. });
  14. };
  15. render() {
  16. return (
  17. <div>
  18. <Button type="primary" onClick={this.showModal}>
  19. Modal
  20. </Button>
  21. <Modal
  22. title="Modal"
  23. visible={this.state.visible}
  24. onOk={this.hideModal}
  25. onCancel={this.hideModal}
  26. okText="确认"
  27. cancelText="取消"
  28. >
  29. <p>Bla bla ...</p>
  30. <p>Bla bla ...</p>
  31. <p>Bla bla ...</p>
  32. </Modal>
  33. </div>
  34. );
  35. }
  36. }
  37. function confirm() {
  38. Modal.confirm({
  39. title: 'Confirm',
  40. icon: <ExclamationCircleOutlined />,
  41. content: 'Bla bla ...',
  42. okText: '确认',
  43. cancelText: '取消',
  44. });
  45. }
  46. ReactDOM.render(
  47. <div>
  48. <LocalizedModal />
  49. <br />
  50. <Button onClick={confirm}>Confirm</Button>
  51. </div>,
  52. mountNode,
  53. );

Modal对话框 - 图10

自定义位置

使用 centered 或类似 style.top 的样式来设置对话框位置。

  1. import { Modal, Button } from 'antd';
  2. class App extends React.Component {
  3. state = {
  4. modal1Visible: false,
  5. modal2Visible: false,
  6. };
  7. setModal1Visible(modal1Visible) {
  8. this.setState({ modal1Visible });
  9. }
  10. setModal2Visible(modal2Visible) {
  11. this.setState({ modal2Visible });
  12. }
  13. render() {
  14. return (
  15. <div>
  16. <Button type="primary" onClick={() => this.setModal1Visible(true)}>
  17. Display a modal dialog at 20px to Top
  18. </Button>
  19. <Modal
  20. title="20px to Top"
  21. style={{ top: 20 }}
  22. visible={this.state.modal1Visible}
  23. onOk={() => this.setModal1Visible(false)}
  24. onCancel={() => this.setModal1Visible(false)}
  25. >
  26. <p>some contents...</p>
  27. <p>some contents...</p>
  28. <p>some contents...</p>
  29. </Modal>
  30. <br />
  31. <br />
  32. <Button type="primary" onClick={() => this.setModal2Visible(true)}>
  33. Vertically centered modal dialog
  34. </Button>
  35. <Modal
  36. title="Vertically centered modal dialog"
  37. centered
  38. visible={this.state.modal2Visible}
  39. onOk={() => this.setModal2Visible(false)}
  40. onCancel={() => this.setModal2Visible(false)}
  41. >
  42. <p>some contents...</p>
  43. <p>some contents...</p>
  44. <p>some contents...</p>
  45. </Modal>
  46. </div>
  47. );
  48. }
  49. }
  50. ReactDOM.render(<App />, mountNode);

Modal对话框 - 图11

自定义页脚按钮属性

传入 okButtonPropscancelButtonProps 可分别自定义确定按钮和取消按钮的 props。

  1. import { Modal, Button } from 'antd';
  2. class App extends React.Component {
  3. state = { visible: false };
  4. showModal = () => {
  5. this.setState({
  6. visible: true,
  7. });
  8. };
  9. handleOk = e => {
  10. console.log(e);
  11. this.setState({
  12. visible: false,
  13. });
  14. };
  15. handleCancel = e => {
  16. console.log(e);
  17. this.setState({
  18. visible: false,
  19. });
  20. };
  21. render() {
  22. return (
  23. <div>
  24. <Button type="primary" onClick={this.showModal}>
  25. Open Modal with customized button props
  26. </Button>
  27. <Modal
  28. title="Basic Modal"
  29. visible={this.state.visible}
  30. onOk={this.handleOk}
  31. onCancel={this.handleCancel}
  32. okButtonProps={{ disabled: true }}
  33. cancelButtonProps={{ disabled: true }}
  34. >
  35. <p>Some contents...</p>
  36. <p>Some contents...</p>
  37. <p>Some contents...</p>
  38. </Modal>
  39. </div>
  40. );
  41. }
  42. }
  43. ReactDOM.render(<App />, mountNode);

API

参数说明类型默认值
afterCloseModal 完全关闭后的回调function-
bodyStyleModal body 样式object{}
cancelText取消按钮文字string|ReactNode取消
centered垂直居中展示 ModalBooleanfalse
closable是否显示右上角的关闭按钮booleantrue
closeIcon自定义关闭图标ReactNode-
confirmLoading确定按钮 loadingbooleanfalse
destroyOnClose关闭时销毁 Modal 里的子元素booleanfalse
footer底部内容,当不需要默认底部按钮时,可以设为 footer={null}string|ReactNode确定取消按钮
forceRender强制渲染 Modalbooleanfalse
getContainer指定 Modal 挂载的 HTML 节点, false 为挂载在当前 domHTMLElement | () => HTMLElement | Selectors | falsedocument.body
keyboard是否支持键盘 esc 关闭booleantrue
mask是否展示遮罩Booleantrue
maskClosable点击蒙层是否允许关闭booleantrue
maskStyle遮罩样式object{}
okText确认按钮文字string|ReactNode确定
okType确认按钮类型stringprimary
okButtonPropsok 按钮 propsButtonProps-
cancelButtonPropscancel 按钮 propsButtonProps-
style可用于设置浮层的样式,调整浮层位置等CSSProperties-
title标题string|ReactNode-
visible对话框是否可见boolean-
width宽度string|number520
wrapClassName对话框外层容器的类名string-
zIndex设置 Modal 的 z-indexNumber1000
onCancel点击遮罩层或右上角叉或取消按钮的回调function(e)-
onOk点击确定回调function(e)-

注意

<Modal /> 默认关闭后状态不会自动清空, 如果希望每次打开都是新内容,请设置 destroyOnClose

Modal.method()

包括:

  • Modal.info

  • Modal.success

  • Modal.error

  • Modal.warning

  • Modal.confirm

以上均为一个函数,参数为 object,具体属性如下:

参数说明类型默认值版本
autoFocusButton指定自动获得焦点的按钮null| ok | cancelok
cancelText设置 Modal.confirm 取消按钮文字string取消
centered垂直居中展示 ModalBooleanfalse
className容器类名string-
content内容string|ReactNode-
icon自定义图标ReactNode<QuestionCircle /3.12.0
maskClosable点击蒙层是否允许关闭Booleanfalse
okText确认按钮文字string确定
okType确认按钮类型stringprimary
okButtonPropsok 按钮 propsButtonProps-
cancelButtonPropscancel 按钮 propsButtonProps-
title标题string|ReactNode-
width宽度string|number416
zIndex设置 Modal 的 z-indexNumber1000
onCancel取消回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭function(close)-
onOk点击确定回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭function(close)-

以上函数调用后,会返回一个引用,可以通过该引用更新和关闭弹窗。

  1. const modal = Modal.info();
  2. modal.update({
  3. title: '修改的标题',
  4. content: '修改的内容',
  5. });
  6. modal.destroy();
  • Modal.destroyAll

使用 Modal.destroyAll() 可以销毁弹出的确认窗(即上述的 Modal.info、Modal.success、Modal.error、Modal.warning、Modal.confirm)。通常用于路由监听当中,处理路由前进、后退不能销毁确认对话框的问题,而不用各处去使用实例的返回值进行关闭(modal.destroy() 适用于主动关闭,而不是路由这样被动关闭)

  1. import { browserHistory } from 'react-router';
  2. // router change
  3. browserHistory.listen(() => {
  4. Modal.destroyAll();
  5. });

Modal.useModal()

当你需要使用 Context 时,可以通过 Modal.useModal 创建一个 contextHolder 插入子节点中。通过 hooks 创建的临时 Modal 将会得到 contextHolder 所在位置的所有上下文。创建的 modal 对象拥有与 Modal.method) 相同的创建通知方法。

  1. const [modal, contextHolder] = Modal.useModal();
  2. React.useEffect(() => {
  3. modal.confirm({
  4. // ...
  5. });
  6. }, []);
  7. return <div>{contextHolder}</div>;

FAQ

为什么 Modal 方法不能获取 context、redux 的内容?

直接调用 Modal 方法,antd 会通过 ReactDOM.render 动态创建新的 React 实体。其 context 与当前代码所在 context 并不相同,因而无法获取 context 信息。

当你需要 context 信息(例如 ConfigProvider 配置的内容)时,可以通过 Modal.useModal 方法会返回 modal 实体以及 contextHolder 节点。将其插入到你需要获取 context 位置即可:

  1. const [modal, contextHolder] = Modal.useModal();
  2. return (
  3. <Context1.Provider value="Ant">
  4. {/* contextHolder 在 Context1 内,它可以获得 Context1 的 context */}
  5. {contextHolder}
  6. <Context2.Provider value="Design">
  7. {/* contextHolder 在 Context2 外,因而不会获得 Context2 的 context */}
  8. </Context2.Provider>
  9. </Context1.Provider>
  10. );

异同:通过 hooks 创建的 contextHolder 必须插入到子元素节点中才会生效,当你不需要上下文信息时请直接调用。