Skip to content

Commit 103293a

Browse files
committed
feat: update modal
1 parent a8424d2 commit 103293a

File tree

10 files changed

+149
-19
lines changed

10 files changed

+149
-19
lines changed

components/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ const install = function(Vue) {
203203
Vue.prototype.$error = Modal.error;
204204
Vue.prototype.$warning = Modal.warning;
205205
Vue.prototype.$confirm = Modal.confirm;
206+
Vue.prototype.$destroyAll = Modal.destroyAll;
206207
};
207208

208209
/* istanbul ignore if */

components/modal/ConfirmDialog.jsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import Icon from '../icon';
33
import Dialog from './Modal';
44
import ActionButton from './ActionButton';
55
import { getConfirmLocale } from './locale';
6+
import { hasProp } from '../_util/props-util';
7+
import warning from '../_util/warning';
68

79
export default {
810
functional: true,
@@ -21,21 +23,29 @@ export default {
2123
maskStyle,
2224
okButtonProps,
2325
cancelButtonProps,
26+
iconType = 'question-circle',
2427
} = props;
25-
const iconType = props.iconType || 'question-circle';
28+
warning(
29+
!('iconType' in props),
30+
`The property 'iconType' is deprecated. Use the property 'icon' instead.`,
31+
);
32+
const icon = props.icon ? props.icon : iconType;
2633
const okType = props.okType || 'primary';
2734
const prefixCls = props.prefixCls || 'ant-modal';
2835
const contentPrefixCls = `${prefixCls}-confirm`;
2936
// 默认为 true,保持向下兼容
3037
const okCancel = 'okCancel' in props ? props.okCancel : true;
3138
const width = props.width || 416;
3239
const style = props.style || {};
40+
const mask = props.mask === undefined ? true : props.mask;
3341
// 默认为 false,保持旧版默认行为
3442
const maskClosable = props.maskClosable === undefined ? false : props.maskClosable;
3543
const runtimeLocale = getConfirmLocale();
3644
const okText = props.okText || (okCancel ? runtimeLocale.okText : runtimeLocale.justOkText);
3745
const cancelText = props.cancelText || runtimeLocale.cancelText;
3846
const autoFocusButton = props.autoFocusButton === null ? false : props.autoFocusButton || 'ok';
47+
const transitionName = props.transitionName || 'zoom';
48+
const maskTransitionName = props.maskTransitionName || 'fade';
3949

4050
const classString = classNames(
4151
contentPrefixCls,
@@ -54,6 +64,7 @@ export default {
5464
{cancelText}
5565
</ActionButton>
5666
);
67+
const iconNode = typeof icon === 'string' ? <Icon type={icon} /> : icon;
5768

5869
return (
5970
<Dialog
@@ -63,9 +74,10 @@ export default {
6374
onCancel={e => close({ triggerCancel: true }, e)}
6475
visible={visible}
6576
title=""
66-
transitionName="zoom"
77+
transitionName={transitionName}
6778
footer=""
68-
maskTransitionName="fade"
79+
maskTransitionName={maskTransitionName}
80+
mask={mask}
6981
maskClosable={maskClosable}
7082
maskStyle={maskStyle}
7183
style={style}
@@ -78,7 +90,7 @@ export default {
7890
>
7991
<div class={`${contentPrefixCls}-body-wrapper`}>
8092
<div class={`${contentPrefixCls}-body`}>
81-
<Icon type={iconType} />
93+
{iconNode}
8294
<span class={`${contentPrefixCls}-title`}>{props.title}</span>
8395
<div class={`${contentPrefixCls}-content`}>{props.content}</div>
8496
</div>

components/modal/Modal.jsx

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@ import classNames from 'classnames';
22
import Dialog from '../vc-dialog';
33
import PropTypes from '../_util/vue-types';
44
import addEventListener from '../_util/Dom/addEventListener';
5+
import { getConfirmLocale } from './locale';
6+
import Icon from '../icon';
57
import Button from '../button';
68
import buttonTypes from '../button/buttonTypes';
79
const ButtonType = buttonTypes().type;
810
import LocaleReceiver from '../locale-provider/LocaleReceiver';
9-
import { getConfirmLocale } from './locale';
1011
import {
1112
initDefaultProps,
1213
getComponentFromProp,
1314
getClass,
1415
getStyle,
1516
mergeProps,
1617
} from '../_util/props-util';
17-
import Icon from '../icon';
18+
import { ConfigConsumerProps } from '../config-provider';
1819

1920
let mousePosition = null;
2021
let mousePositionEventBinded = false;
@@ -42,13 +43,16 @@ const modalProps = (defaultProps = {}) => {
4243
/** 底部内容*/
4344
footer: PropTypes.any,
4445
/** 确认按钮文字*/
45-
okText: PropTypes.string,
46+
okText: PropTypes.any,
4647
/** 确认按钮类型*/
4748
okType: ButtonType,
4849
/** 取消按钮文字*/
49-
cancelText: PropTypes.string,
50+
cancelText: PropTypes.any,
51+
icon: PropTypes.any,
5052
/** 点击蒙层是否允许关闭*/
5153
maskClosable: PropTypes.bool,
54+
/** 强制渲染 Modal*/
55+
forceRender: PropTypes.bool,
5256
okButtonProps: PropTypes.object,
5357
cancelButtonProps: PropTypes.object,
5458
destroyOnClose: PropTypes.bool,
@@ -66,14 +70,15 @@ const modalProps = (defaultProps = {}) => {
6670
return initDefaultProps(props, defaultProps);
6771
};
6872

73+
export const destroyFns = [];
74+
6975
export default {
7076
name: 'AModal',
7177
model: {
7278
prop: 'visible',
7379
event: 'change',
7480
},
7581
props: modalProps({
76-
prefixCls: 'ant-modal',
7782
width: 520,
7883
transitionName: 'zoom',
7984
maskTransitionName: 'fade',
@@ -83,6 +88,9 @@ export default {
8388
// okButtonDisabled: false,
8489
// cancelButtonDisabled: false,
8590
}),
91+
inject: {
92+
configProvider: { default: () => ({}) },
93+
},
8694
mounted() {
8795
if (mousePositionEventBinded) {
8896
return;
@@ -145,7 +153,17 @@ export default {
145153
},
146154

147155
render() {
148-
const { visible, wrapClassName, centered, prefixCls, $listeners, $slots } = this;
156+
const {
157+
prefixCls: customizePrefixCls,
158+
visible,
159+
wrapClassName,
160+
centered,
161+
$listeners,
162+
$slots,
163+
} = this;
164+
165+
const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls;
166+
const prefixCls = getPrefixCls('modal', customizePrefixCls);
149167

150168
const defaultFooter = (
151169
<LocaleReceiver

components/modal/confirm.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Vue from 'vue';
22
import ConfirmDialog from './ConfirmDialog';
3+
import { destroyFns } from './Modal';
34

45
export default function confirm(config) {
56
const div = document.createElement('div');
@@ -30,6 +31,13 @@ export default function confirm(config) {
3031
if (config.onCancel && triggerCancel) {
3132
config.onCancel(...args);
3233
}
34+
for (let i = 0; i < destroyFns.length; i++) {
35+
const fn = destroyFns[i];
36+
if (fn === close) {
37+
destroyFns.splice(i, 1);
38+
break;
39+
}
40+
}
3341
}
3442

3543
function render(props) {
@@ -48,7 +56,7 @@ export default function confirm(config) {
4856
}
4957

5058
confirmDialogInstance = render(currentConfig);
51-
59+
destroyFns.push(close);
5260
return {
5361
destroy: close,
5462
update,
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
2+
<cn>
3+
#### 销毁确认对话框
4+
使用 `Modal.destroyAll()` 可以销毁弹出的确认窗。通常用于路由监听当中,处理路由前进、后退不能销毁确认对话框的问题。
5+
</cn>
6+
7+
<us>
8+
#### destroy confirmation modal dialog
9+
`Modal.destroyAll()` could destroy all confirmation modal dialogs. Usually, you can use it in router change event to destroy confirm modal dialog automatically
10+
</us>
11+
12+
```html
13+
<template>
14+
<a-button @click="showConfirm">
15+
Confirm
16+
</a-button>
17+
</template>
18+
<script>
19+
import Button from '../../button'
20+
export default {
21+
methods: {
22+
showConfirm() {
23+
for (let i = 0; i < 3; i += 1) {
24+
setTimeout(() => {
25+
this.$confirm({
26+
content: ( // JSX support
27+
<Button onClick={this.destroyAll}>
28+
Click to destroy all
29+
</Button>
30+
),
31+
onOk() {
32+
return new Promise((resolve, reject) => {
33+
setTimeout(Math.random() > 0.5 ? resolve : reject, 1000);
34+
}).catch(() => console.log('Oops errors!'));
35+
},
36+
onCancel() {},
37+
});
38+
}, i * 500);
39+
}
40+
},
41+
destroyAll() {
42+
this.$destroyAll();
43+
}
44+
}
45+
}
46+
</script>
47+
```
48+

components/modal/demo/index.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Locale from './locale';
99
import Manual from './manual';
1010
import Position from './position';
1111
import ButtonProps from './button-props';
12+
import ConfirmRouter from './confirm-router';
1213
1314
import CN from '../index.zh-CN.md';
1415
import US from '../index.en-US.md';
@@ -17,7 +18,7 @@ const md = {
1718
模态对话框。
1819
## 何时使用
1920
需要用户处理事务,又不希望跳转页面以致打断工作流程时,可以使用 \`Modal\` 在当前页面正中打开一个浮层,承载相应的操作。
20-
另外当需要一个简洁的确认框询问用户时,可以使用精心封装好的 \`antd.Modal.confirm()\` 等方法
21+
另外当需要一个简洁的确认框询问用户时,可以使用 \`Modal.confirm()\` 等语法糖方法
2122
## 代码演示`,
2223
us: `# Modal
2324
Modal dialogs.
@@ -49,6 +50,7 @@ export default {
4950
<Manual/>
5051
<Position/>
5152
<ButtonProps />
53+
<ConfirmRouter />
5254
<api>
5355
<CN slot='cn' />
5456
<US/>

components/modal/index.en-US.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
| confirmLoading | Whether to apply loading visual effect for OK button or not | boolean | false |
1212
| destroyOnClose | Whether to unmount child components on onClose | boolean | false |
1313
| footer | Footer content, set as `:footer="null"` when you don't need default buttons | string\|slot | OK and Cancel buttons |
14+
| forceRender | Force render Modal | boolean | false |
1415
| getContainer | Return the mount node for Modal | (instance): HTMLElement | () => document.body |
1516
| mask | Whether show mask or not. | Boolean | true |
1617
| maskClosable | Whether to close the modal dialog when the mask (area outside the modal) is clicked | boolean | true |
@@ -55,8 +56,10 @@ The properties of the object are follows:
5556
| centered | Centered Modal | Boolean | `false` |
5657
| class | class of container | string | - |
5758
| content | Content | string\|vNode | - |
58-
| iconType | Icon `type` of the Icon component | string | `question-circle` |
59+
| icon | custom icon (`Added in 1.40.0`) | string\|slot | `<Icon type="question-circle">` |
60+
| iconType | Icon `type` of the Icon component (deperated after `1.40.0`) | string | `question-circle` |
5961
| keyboard | Whether support press esc to close | Boolean | true |
62+
| mask | Whether show mask or not. | Boolean | true |
6063
| maskClosable | Whether to close the modal dialog when the mask (area outside the modal) is clicked | Boolean | `false` |
6164
| okText | Text of the OK button | string | `OK` |
6265
| okType | Button `type` of the OK button | string | `primary` |
@@ -80,3 +83,16 @@ modal.update({
8083

8184
modal.destroy();
8285
```
86+
87+
- `Modal.destroyAll`
88+
89+
`Modal.destroyAll()` could destroy all confirmation modal dialogs(Modal.info/Modal.success/Modal.error/Modal.warning/Modal.confirm). Usually, you can use it in router change event to destroy confirm modal dialog automatically without use modal reference to close( it's too complex to use for all modal dialogs)
90+
91+
```jsx
92+
const router = new VueRouter({ ... })
93+
94+
// router change
95+
router.beforeEach((to, from, next) => {
96+
Modal.destroyAll();
97+
})
98+
```

components/modal/index.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Modal from './Modal';
1+
import Modal, { destroyFns } from './Modal';
22
import modalConfirm from './confirm';
33

44
// export { ActionButtonProps } from './ActionButton'
@@ -7,7 +7,7 @@ import modalConfirm from './confirm';
77
const info = function(props) {
88
const config = {
99
type: 'info',
10-
iconType: 'info-circle',
10+
icon: <Icon type="info-circle" />,
1111
okCancel: false,
1212
...props,
1313
};
@@ -17,7 +17,7 @@ const info = function(props) {
1717
const success = function(props) {
1818
const config = {
1919
type: 'success',
20-
iconType: 'check-circle',
20+
icon: <Icon type="check-circle" />,
2121
okCancel: false,
2222
...props,
2323
};
@@ -27,7 +27,7 @@ const success = function(props) {
2727
const error = function(props) {
2828
const config = {
2929
type: 'error',
30-
iconType: 'close-circle',
30+
icon: <Icon type="close-circle" />,
3131
okCancel: false,
3232
...props,
3333
};
@@ -37,7 +37,7 @@ const error = function(props) {
3737
const warning = function(props) {
3838
const config = {
3939
type: 'warning',
40-
iconType: 'exclamation-circle',
40+
icon: <Icon type="exclamation-circle" />,
4141
okCancel: false,
4242
...props,
4343
};
@@ -60,6 +60,15 @@ Modal.warning = warning;
6060
Modal.warn = warn;
6161
Modal.confirm = confirm;
6262

63+
Modal.destroyAll = function() {
64+
while (destroyFns.length) {
65+
const close = destroyFns.pop();
66+
if (close) {
67+
close();
68+
}
69+
}
70+
};
71+
6372
/* istanbul ignore next */
6473
Modal.install = function(Vue) {
6574
Vue.component(Modal.name, Modal);

components/modal/index.zh-CN.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
| confirmLoading | 确定按钮 loading | boolean ||
1111
| destroyOnClose | 关闭时销毁 Modal 里的子元素 | boolean | false |
1212
| footer | 底部内容,当不需要默认底部按钮时,可以设为 `:footer="null"` | string\|slot | 确定取消按钮 |
13+
| forceRender | 强制渲染 Modal | boolean | false |
1314
| getContainer | 指定 Modal 挂载的 HTML 节点 | (instance): HTMLElement | () => document.body |
1415
| keyboard | 是否支持键盘esc关闭 | boolean | true |
1516
| mask | 是否展示遮罩 | Boolean | true |
@@ -54,7 +55,9 @@
5455
| centered | 垂直居中展示 Modal | Boolean | `false` |
5556
| class | 容器类名 | string | - |
5657
| content | 内容 | string\|vNode ||
57-
| iconType | 图标 Icon 类型 | string | question-circle |
58+
| icon | 自定义图标(1.40.0 新增) | string\|slot | `<Icon type="question-circle">` |
59+
| iconType | 图标类型(1.40.0 后废弃,请使用 `icon`| string | `question-circle` |
60+
| mask | 是否展示遮罩 | Boolean | true |
5861
| maskClosable | 点击蒙层是否允许关闭 | Boolean | `false` |
5962
| keyboard | 是否支持键盘esc关闭 | boolean | true |
6063
| okText | 确认按钮文字 | string | 确定 |
@@ -79,3 +82,15 @@ modal.update({
7982

8083
modal.destroy();
8184
```
85+
- `Modal.destroyAll`
86+
87+
使用 `Modal.destroyAll()` 可以销毁弹出的确认窗(即上述的 Modal.info、Modal.success、Modal.error、Modal.warning、Modal.confirm)。通常用于路由监听当中,处理路由前进、后退不能销毁确认对话框的问题,而不用各处去使用实例的返回值进行关闭(modal.destroy() 适用于主动关闭,而不是路由这样被动关闭)
88+
89+
```jsx
90+
const router = new VueRouter({ ... })
91+
92+
// router change
93+
router.beforeEach((to, from, next) => {
94+
Modal.destroyAll();
95+
})
96+
```

0 commit comments

Comments
 (0)