# MDialog 弹层

- 来源：[E10 UI 组件库](https://www.e-cology.com.cn/ui/mobile/dialog/freepass)
- 平台：移动端
- 维护者：蒋贝贝
- Issue：http://gitlab.ecology10.cn/FRONTEND/weapp-ui/-/issues?state=all&search=[MDialog]

## 代码演示

### 基础用法

最简单的对话框，简单的根据路由控制显隐的对话框。

```jsx
import { Component } from 'react';
import { withRouter } from 'react-router-dom';
import { MDialog, MButton, constants, utils } from '@weapp/ui';

const { uiPcClsPrefix } = constants;
const { formatParentPath } = utils;
interface MDialogDemoProps {
  history?: any;
}

interface MDialogDemoState {
  visible?: boolean;
  visibleBottom?: boolean,
  customVisible?: boolean;
}
const prefixCls = `${uiPcClsPrefix}-demo-mDialog`;
// @ts-ignore
@withRouter //需要用到路由时，才需要加
class MDialogDemo extends Component<MDialogDemoProps, MDialogDemoState> {
  constructor(props: MDialogDemoProps) {
    super(props);
    this.state = {
      visible: false,
      visibleBottom: false,
      customVisible: false,
    }
  }
  // 基础弹框方法
  onClose = () => {
    this.setState({ visible: false });
  }
  showMDialog = () => {
    this.setState({ visible: true });
  }

  // 路由弹窗方法
  showMDialogByRoute = () => {
    let parentPath = formatParentPath(this.props as any)
    this.props.history.push(`${parentPath}/route`);
  }
  onCloseRoute = () => {
    console.log('onCloseRoute')
    this.props.history.go(-1);
  }

  // 底部按钮弹出框方法
  closeDialogBottom = () => this.setState({ visibleBottom: false })
  showDialogBottom = () => this.setState({ visibleBottom: true })

  // 基础弹框方法
  onCloseCustomMDialog = () => {
    this.setState({ customVisible: false });
  }
  showCustomMDialog = () => {
    this.setState({ customVisible: true });
  }

  render() {
    const { visible, visibleBottom,customVisible } = this.state;
    let parentPath = formatParentPath(this.props as any)
    return (
      <div className={prefixCls}>
        <div>
          <h3>基础使用</h3>
          <div>
            <MButton onClick={this.showMDialog}>打开基础弹框</MButton>
            <MDialog
              className={`dialog-demo`}
              visible={visible}
              onClose={this.onClose}
              onOk={this.onClose}
              title="基本用法"
              destroyOnClose
              mask
              maskClosable
              message="辅助信息类文字"
              description="说明性文字"
              icon="Icon-computer"
              okText='确定'
              cancelText='取消'
            >
              <div>MDialog支持children</div>
            </MDialog>
          </div>
          <div>
            <MButton onClick={this.showMDialogByRoute}>打开路由弹框</MButton>
            <MDialog
              className={`dialog-demo`}
              onClose={this.onCloseRoute}
              title="通过路由打开"
              destroyOnClose
              mask
              maskClosable
              path={`${parentPath}/route`}
              onOk={this.onCloseRoute}
            >
              当path属性存在时，可以根据路由去控制对话框的显示与隐藏。
            </MDialog>
          </div>
        </div>

        <div>
          <h3>底部弹出框</h3>
          <MButton onClick={this.showDialogBottom}>底部弹出框</MButton>
          <MDialog
            visible={visibleBottom}
            mask
            maskClosable
            onClose={this.closeDialogBottom}
            placement="bottom"
            footer={[
              {
                key: 'sub1',
                text: '选项一',
                type: 'warning',
                // onPress: this.closeDialogBottom,
              },
              {
                key: 'sub2',
                text: '选项二',
                type: 'primary',
                // onPress: this.closeDialogBottom,
              },
              {
                key: 'sub3',
                text: '选项三',
                type: 'default',
                // onPress: this.closeDialogBottom,
              },
            ]}
          >
            children
          </MDialog>
        </div>

        <div>
          <h3>自定义底部按钮</h3>
          <MButton onClick={this.showCustomMDialog}>打开自定义底部按钮弹框</MButton>
          <MDialog
            className={`dialog-demo`}
            visible={customVisible}
            onClose={this.onCloseCustomMDialog}
            onOk={this.onCloseCustomMDialog}
            title="基本用法"
            destroyOnClose
            mask
            maskClosable
            icon="Icon-computer"
            // footerType='grid'
            footerDefaultNum={3}
            footer={[
              {
                key: 'sub1',
                text: '选项一',
                type: 'warning',
                // onPress: this.closeDialogBottom,
              },
              {
                key: 'sub2',
                text: '选项二',
                type: 'primary',
                // onPress: this.closeDialogBottom,
              },
              {
                key: 'sub3',
                text: '选项三',
                type: 'default',
                // onPress: this.closeDialogBottom,
              },
            ]}
          >
            <div>MDialog footer 设置，可控制底部按钮一行显示个数</div>
          </MDialog>
        </div>
      </div>
    );
  }
}

export default MDialogDemo
```

### 通过路由打开

通过路由打开，当path属性存在时，根据路由去控制对话框的显示与隐藏。

```jsx
import { Component } from 'react';
import { withRouter } from 'react-router-dom';
import { MDialog, MButton, constants, utils } from '@weapp/ui';

const { formatParentPath } = utils;
const { uiPcClsPrefix } = constants;
interface MDialogDemoProps {
  history?: any;
}

const prefixCls = `${uiPcClsPrefix}-demo-mDialog`;
// @ts-ignore
@withRouter
class MDialogDemo extends Component<MDialogDemoProps> {
  showMDialogByRoute = () => {
    let parentPath = formatParentPath(this.props as any)
    this.props.history.push(`${parentPath}/route`);
  }
  onCloseRoute = () => {
    console.log('onCloseRoute')
    this.props.history.go(-1);
  }
  render() {
    let parentPath = formatParentPath(this.props as any)
    return (
      <div className={prefixCls}>
        <MButton onClick={this.showMDialogByRoute}>打开路由弹框</MButton>
        <MDialog
          className={`dialog-demo`}
          onClose={this.onCloseRoute}
          title="通过路由打开"
          height={500}
          destroyOnClose
          mask
          maskClosable
          path={`${parentPath}/route`}
          onOk={this.onCloseRoute}
        >
          MDialogBody
        </MDialog>
      </div>
    );
  }
}

export default MDialogDemo
```

### 底部弹出框

在屏幕底部，弹出对话框,

```jsx
import { Component } from 'react';
import { MDialog, MButton, constants } from '@weapp/ui';
const { uiPcClsPrefix } = constants;
interface MDialogDemoProps {
  history?: any;
}

interface MDialogDemoState {
  visibleBottom?: boolean,
}
const prefixCls = `${uiPcClsPrefix}-demo-mDialog`;
class MDialogDemo extends Component<MDialogDemoProps, MDialogDemoState> {
  constructor(props: MDialogDemoProps) {
    super(props);
    this.state = {
      visibleBottom: false,
    }
  }
  closeDialogBottom = () => this.setState({ visibleBottom: false })
  showDialogBottom = () => this.setState({ visibleBottom: true })
  render() {
    const { visibleBottom } = this.state;
    return (
      <div className={prefixCls}>
        <MButton onClick={this.showDialogBottom}>底部弹出框</MButton>
        <MDialog
          visible={visibleBottom}
          mask
          maskClosable
          onClose={this.closeDialogBottom}
          placement="bottom"
          footer={[
            {
              key: 'sub1',
              text: '选项一',
              type: 'warning',
              // onPress: this.closeDialogBottom,
            },
            {
              key: 'sub2',
              text: '选项二',
              type: 'primary',
              // onPress: this.closeDialogBottom,
            },
            {
              key: 'sub3',
              text: '选项三',
              type: 'default',
              // onPress: this.closeDialogBottom,
            },
          ]}
        >
          children
        </MDialog>
      </div>
    );
  }
}

export default MDialogDemo
```

### Modal弹窗

用于重要信息的告知或操作的反馈，并附带少量的选项供用户进行操作。

```jsx
import { Component } from 'react';
import { MDialog, MButton, constants } from '@weapp/ui';
const { uiPcClsPrefix } = constants;
const { prompt } = MDialog;
interface MDialogDemoProps {
  history?: any;
}
const prefixCls = `${uiPcClsPrefix}-demo-mDialog`;
class MDialogDemo extends Component<MDialogDemoProps> {
  instance: any;
  
  showPrompt = () => {
    prompt({
      title: "基本用法",
      mask: true,
      maskClosable: true,
      message: "辅助信息类文字",
      description: "说明性文字",
      onClose: () => { },
      onOk: (value?: string) => { console.log(value) },
      promptProps: {
        value: 'sss'
      },
      okText: '确定',
      cancelText: '取消'
    })
  }

  getInstance = (el: any) => {
    this.instance = el;
  }

  onClose = () => {
    this.instance && this.instance.onClose()
  }

  showPromptSub = () => {
    prompt({
      title: "基本用法",
      mask: true,
      maskClosable: true,
      message: "辅助信息类文字",
      description: "说明性文字",
      onClose: () => { },
      onOk: (value?: string) => { console.log(value) },
      prompt: false,
      getInstance: this.getInstance,
      footer: [
        {
          key: 'cancel',
          text: '关闭',
          onPress: this.onClose,
        }
      ]
    })
  }
  
  render() {
    return (
      <div className={prefixCls}>
        <MButton onClick={this.showPrompt}>基础Modal对话框</MButton>
        <MButton onClick={this.showPromptSub}>自定义页脚Modal对话框</MButton>
      </div>
    );
  }
}

export default MDialogDemo
```

### 路由层

嵌套路由弹窗，可根据路由控制多个弹窗的显示与隐藏。

```jsx
import { Component } from 'react';
import { RouteComponentProps, withRouter } from 'react-router-dom';
import { MDialog, MButton, constants, utils, MDialogButtonType } from '@weapp/ui';

const { formatParentPath } = utils;
const { uiPcClsPrefix } = constants;
const { ButtonGroup } = MDialog;
interface MDialogDemoProps extends RouteComponentProps {
}

// MDialog.dialogConfig = { // 全局配置参数
//   style:{
//     top:'auto',
//     height:"60%",
//   },
//   placement: 'middle',
// }
const prefixCls = `${uiPcClsPrefix}-demo-mDialog`;
class MDialogDemo extends Component<MDialogDemoProps> {
  showMDialogByRoute = () => {
    let parentPath = formatParentPath(this.props as any)
    this.props.history.push(`${parentPath}/route`);
  }
  showMDialogByRouteSec = () => {
    let parentPath = formatParentPath(this.props as any)
    this.props.history.push(`${parentPath}/route/second`);
  }
  onCloseRoute = () => {
    this.props.history.go(-1);
  }
  render() {
    let parentPath = formatParentPath(this.props as any)
    const primaryType: MDialogButtonType = 'primary';
    const btns = [
      { id: 'route', content: '一级路由', onClick: this.showMDialogByRoute, type: primaryType }
    ]
    const btnsSub = [
      { id: 'route', content: '二级路由', onClick: this.showMDialogByRouteSec, type: primaryType },
      { id: 'back', content: '返回返回返回返回返回返回返回返回返回返回', onClick: this.onCloseRoute },
    ]
    const btnsSec = [
      { id: 'back', content: '返回', onClick: this.onCloseRoute },
      { id: 'disabled', content: '禁用', onClick: this.onCloseRoute, disabled: true },
    ]
    return (
      <div className={prefixCls}>
        <ButtonGroup datas={btns}/>
        <MDialog
          destroyOnClose
          path={`${parentPath}/route`}
          isRouteLayout={true}
          title={"一级路由"}
        >
          MDialogBody
          <ButtonGroup datas={btnsSub}/>
          <MDialog
            destroyOnClose
            path={`${parentPath}/route/second`}
            isRouteLayout={true}
            title={"二级路由"}
          >
            MDialogBody2
            <ButtonGroup datas={btnsSec}/>
          </MDialog>
        </MDialog>

      </div>
    );
  }
}

export default withRouter(MDialogDemo)
```

### 自定义footer 设置

footer 设置，设置弹框底部按钮，以及每行显示按钮格数。

```jsx
import { Component } from 'react';
import { MDialog, MButton, constants } from '@weapp/ui';
const { uiPcClsPrefix } = constants;
interface MDialogDemoProps {
  history?: any;
}

interface MDialogDemoState {
  visible?: boolean;
  visibleBottom?: boolean,
}
const prefixCls = `${uiPcClsPrefix}-demo-mDialog`;

class MDialogDemo extends Component<MDialogDemoProps, MDialogDemoState> {
  constructor(props: MDialogDemoProps) {
    super(props);
    this.state = {
      visible: false,
    }
  }
  onClose = () => {
    this.setState({ visible: false });
  }
  showMDialog = () => {
    this.setState({ visible: true });
  }
  render() {
    const { visible } = this.state;
    return (
      <div className={prefixCls}>
        <MButton onClick={this.showMDialog}>打开自定义底部按钮弹框</MButton>
        <MDialog
          className={`dialog-demo`}
          visible={visible}
          onClose={this.onClose}
          onOk={this.onClose}
          title="基本用法"
          destroyOnClose
          mask
          maskClosable
          icon="Icon-computer"
          // footerType='grid'
          footerDefaultNum={3}
          footer={[
            {
              key: 'sub1',
              text: '选项一',
              type: 'warning',
              // onPress: this.closeDialogBottom,
            },
            {
              key: 'sub2',
              text: '选项二',
              type: 'primary',
              // onPress: this.closeDialogBottom,
            },
            {
              key: 'sub3',
              text: '选项三',
              type: 'default',
              // onPress: this.closeDialogBottom,
            },
          ]}
        >
          <div>MDialog footer 设置，可控制底部按钮一行显示个数</div>
        </MDialog>
      </div>
    );
  }
}

export default MDialogDemo
```

### Toast 轻提示

对操作结果的轻量级反馈，无需用户操作即可自行消失。

```jsx
import { Component } from 'react';
import { MDialog, MButton, constants, Icon } from '@weapp/ui';

const { uiPcClsPrefix } = constants;
const { toast } = MDialog;

interface DialogDemoProps {
  history?: any;
}

const prefixCls = `${uiPcClsPrefix}-demo-btn`;

class DialogDemo extends Component<DialogDemoProps> {
  intance: any;

  default = () => {
    toast({
      content: '这是一条提示信息, 3s 后主动消失',
      onClose: () => { console.log('onClose') },
    });
  }
  info = () => {
    toast({
      type: 'info', // type: 'info', 'fail', 'success'
      content: '这是一条提示信息, 3s 后主动消失',
      onClose: () => { console.log('onClose') }
    });
  }
  success = () => {
    toast({
      type: 'success', // type: 'info', 'fail', 'success'
      content: '这是一条提示信息, 3s 后主动消失',
      mask: true
    });
  }
  warn = () => {
    toast({
      type: 'warn', // type: 'info', 'fail', 'success'
      content: '这是一条提示信息, 3s 后主动消失',
      mask: true
    });
  }
  fail = () => {
    toast({
      type: 'fail', // type: 'info', 'fail', 'success'
      content: '这是一条提示信息, 3s 后主动消失'
    });
  }
  loading = () => {
    toast({
      type: 'loading', // type: 'info', 'fail', 'success'
      content: '这是一条提示信息, 3s 后主动消失',
    });
  }
  custom = () => {
    toast({
      type: 'info', // type: 'info', 'error', 'success'
      content: <div>
        <Icon name={'Icon--Import-and-export'} size='lg' />
        <div>自定义内容</div>
      </div>,
    });
  }
  delay0 = () => {
    this.intance = toast({
      content: '这是一条提示信息, 不会主动消失',
      onClose: () => { console.log('onClose') },
      mask: false,
      delay: 0,
      isHorizontal: true
    });
  }
  destroy = () => {
    this.intance && this.intance.destroy()
  }
  horizontal = () => {
    toast({
      content: '横屏展示',
      onClose: () => { console.log('onClose') },
      isHorizontal: true
    });
  }
  horizontal2 = () => {
    toast({
      content: '横屏展示（颠倒）',
      onClose: () => { console.log('onClose') },
      isHorizontal: true,
      horizontalDirection: 'clockwise'
    });
  }
  render() {
    return (
      <div className={prefixCls}>
        <h3>基础使用</h3>
        <MButton onClick={this.default}>信息提示 - default</MButton>
        <MButton onClick={this.info}>信息提示 - info</MButton>
        <MButton onClick={this.success}>信息提示 - success</MButton>
        <MButton onClick={this.warn}>信息提示 - warn</MButton>
        <MButton onClick={this.fail}>信息提示 - fail</MButton>
        <MButton onClick={this.loading}>信息提示 - loading</MButton>
        <h3>自定义内容</h3>
        <MButton onClick={this.custom}>信息提示 - custom</MButton>
        <h3>destroy</h3>
        <MButton onClick={this.delay0}>信息提示 - delay0</MButton>
        <MButton onClick={this.destroy} >destroy</MButton>
        <h3>横屏提示</h3>
        <MButton onClick={this.horizontal}>横屏展示</MButton>
        <MButton onClick={this.horizontal2} >横屏展示（颠倒）</MButton>
      </div >
    );
  }
}

export default DialogDemo
```

## API

### 参数说明如下：

| 参数 | 说明 | 类型 | 是否必填 | 默认值 |
| --- | --- | --- | --- | --- |
| placement | middle \| top \| right \| bottom \| left | string | 否 | middle |
| path | 通过路由打开 | string | 否 |  |
| visible | 显示受控 | boolean | 否 |  |
| onClose | 击遮罩层或右上角叉或取消按钮的回调 | () => void | 否 |  |
| onAfterClose | Dialog 关闭后回调(带动画效果) | () => void | 否 |  |
| onOk | 点击确定按钮的回调 | (...arg: any[]) => void | 否 |  |
| mask | 是否展示遮罩 | boolean | 否 |  |
| maskClosable | 点击蒙层是否允许关闭 | boolean | 否 |  |
| maskStyle | Dialog 遮罩层部分样式 | CSSProperties | 否 |  |
| destroyOnClose | 关闭时销毁 Drawer 里的子元素 | boolean | 否 |  |
| forceRender | 预渲染弹框内部内容 | boolean | 否 |  |
| top | 距离顶部高度 | number | 否 |  |
| title | 标题内容 | string | 否 |  |
| getTitle | 自定义标题内容 | () => ReactNode | 否 |  |
| message | 辅助信息类文字 | string | 否 |  |
| description | 说明性文字 | string | 否 |  |
| titleStyle | 自定义标题样式 | CSSProperties | 否 |  |
| footer | 按钮组(底部) | ReactNode | 否 |  |
| footerStyle | 自定义底部按钮样式 | CSSProperties | 否 |  |
| zIndex |  | number | 否 |  |
| height | left/right 模式不可改 | number | 否 |  |
| width |  | number | 否 |  |
| getContainer | 弹层容器定位 | (element?: HTMLElement) => HTMLElement | 否 |  |
| icon | 图标 | IconNames | 否 |  |
| iconProps | 图标属性 | IconProps | 否 |  |
| wrapClassName | 外层容器 class | string | 否 |  |
| wrapStyle | 外层容器自定义样式 | CSSProperties | 否 |  |
| bottomWrapStyle | 底部弹出框外层容器自定义样式 | CSSProperties | 否 |  |
| isRouteLayout | 路由层模式(配置 path，默认路由层模式打开) | boolean | 否 | false |
| okText | 自定义确定按钮名称 | string | 否 |  |
| cancelText | 自定义取消按钮名称 | string | 否 |  |
| footerType | dialog footer 类型 | `row` \| `grid` | 否 |  |
| footerGridColNum | 一行最多按钮个数（仅 footerType === 'grid'）时生效 |  | 否 |  |
| footerDefaultNum | footer 默认最大 grid 显示格式个数，超过该数值通过 row 类型显示 | number | 否 | 2 |
| closeAnimation | 关闭动画 | boolean | 否 | false |
| ref | 组件实例 | any | 否 |  |
| isStopPropagation | 禁止阻止冒泡 | boolean | 否 | true |
| enableRouterLayout | 强制启用RouteLayout模式（非路由场景） | boolean | 否 | false |
默认 footer 显示 `` 和 `` 按钮，并默认绑定 onClose 和 onOk 事件。

传递 footer = [] 可以关闭 footer 的显示。

自定义 footer 需要自行绑定事件。

默认 footer 数量为 2 时，一行显示，超过 2 时，每个 btn 显示为一行，可以通过 `` 修改数量。

可以通过 footerType 修改显示方法：`` 表示不管数量为多少，每个 btn 都显示为一行；`` 不管数量为多少，一行都显示多个 btn（可以通过 footerGridColNum 设置一行最多显示个数，超过个数换行处理）

## prompt 参数

| 参数 | 说明 | 类型 | 是否必填 | 默认值 |
| --- | --- | --- | --- | --- |
| promptProps | InputProps | prompt 中的 input 参数 | 否 |  |
| prompt | boolean | 是否需要输入框 | 否 | true |
| getInstance | 获取弹框实例 | (instance: any) => void |  |  |
> 其他参数同 MDialog

## RouteLayout 参数

##### 使用MDialog.RouteLayout或使用MDialog，设置isRouteLayout(路由层模式)

| 参数 | 说明 | 类型 | 是否必填 | 默认值 |
| --- | --- | --- | --- | --- |
| queueAnimProps | 动画参数设置(详情请参考QueueAnim插件官方文档) |  |  |  |
| closeQueueAnim | 关闭动画 | boolean | false |  |
## toast 参数

| 参数 | 说明 | 类型 | 是否必填 | 默认值 |
| --- | --- | --- | --- | --- |
| content | 提示内容 | React.Element or String | 否 |  |
| type | 提示类型 | `info` \| `fail` \| `success` \| `loading` | 否 | info |
| delay | 自动关闭的延时，单位 ms | number | 否 | 3000 |
| mask | 是否显示透明蒙层，防止触摸穿透 | boolean | 否 | true |
| onClose | 击遮罩层或右上角叉或取消按钮的回调 | () => void | 否 |  |
| destroy | 击遮罩层或右上角叉或取消按钮的回调 | () => void | 否 |  |
| isHorizontal | 击遮罩层或右上角叉或取消按钮的回调 | boolean | 否 | false |
| horizontalDirection | 击遮罩层或右上角叉或取消按钮的回调 | 'clockwise' \| 'anticlockwise' | 否 | 'anticlockwise' |
> 注： delay = 0 时，onClose 无效，toast 不会消失；隐藏 toast 需要手动调用 destroy

```tsx
// 销毁方法:
let intance = toast({
  content: "这是一条提示信息, 不会主动消失",
  onClose: () => {
    console.log("onClose");
  },
  mask: false,
});

setTimeout(() => {
  intance.destroy();
}, 3000);
```

## createDialog 参数

```
1.示例：
MDialog.createDialog({
  title: 'Create Dialog'
})

2.ts说明
createDialog: (e: DialogProps) => { destroy: () => void };
```

## MDialog.dialogConfig 说明

**1. 一般用于移动端全局Dialog参数配置 **

**2. 仅在isRouteLayout(路由层模式)下生效 **

| 参数 | 说明 | 类型 | 是否必填 | 默认值 |
| --- | --- | --- | --- | --- |
| style | 移动端最外层容器样式 | CSSProperties | 否 |  |
