add notification

pull/165/head
tangjinzhou 2018-02-06 15:21:13 +08:00
parent 92568220f4
commit e6fad3803a
24 changed files with 607 additions and 295 deletions

View File

@ -1,16 +1,15 @@
import cloneDeep from 'lodash.clonedeep'
export function cloneVNode (vnode, deep) {
const componentOptions = vnode.componentOptions
const data = vnode.data
let listeners = {}
if (componentOptions && componentOptions.listeners) {
listeners = cloneDeep(componentOptions.listeners)
listeners = { ...componentOptions.listeners }
}
let on = {}
if (data && data.on) {
on = cloneDeep(data.on)
on = { ...data.on }
}
const cloned = new vnode.constructor(
@ -98,11 +97,23 @@ export function isEmptyElement (ele) {
}
export function getClass (ele) {
return ele.data && (ele.data.class || ele.data.staticClass)
let data = {}
if (ele.data) {
data = ele.data
} else if (ele.$vnode && ele.$vnode.data) {
data = ele.$vnode.data
}
return data.class || data.staticClass
}
export function getStyle (ele) {
return ele.data && (ele.data.style || ele.data.staticStyle)
let data = {}
if (ele.data) {
data = ele.data
} else if (ele.$vnode && ele.$vnode.data) {
data = ele.$vnode.data
}
return data.style || data.staticStyle
}
export function filterEmpty (children = []) {

View File

@ -6,7 +6,7 @@
| -------- | ----------- | ---- | ------- |
| disabled | whether the dropdown menu is disabled | boolean | - |
| getPopupContainer | to set the container of the dropdown menu. The default is to create a `div` element in `body`, you can reset it to the scrolling area and make a relative reposition. [example](https://codepen.io/afc163/pen/zEjNOy?editors=0010) | Function(triggerNode) | `() => document.body` |
| overlay(slot) | the dropdown menu | [Menu](#/components/us/menu) | - |
| overlay(slot) | the dropdown menu | [Menu](#/us/components/menu) | - |
| placement | placement of pop menu: `bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | String | `bottomLeft` |
| trigger | the trigger mode which executes the drop-down action | Array<`click`\|`hover`\|`contextMenu`> | `['hover']` |
| visible(v-model) | whether the dropdown menu is visible | boolean | - |
@ -16,7 +16,7 @@
| --- | --- | --- |
| visibleChange | a callback function takes an argument: `visible`, is executed when the visible state is changed | function(visible) |
You should use [Menu](#/components/us/menu/) as `overlay`. The menu items and dividers are also available by using `Menu.Item` and `Menu.Divider`.
You should use [Menu](#/us/components/menu/) as `overlay`. The menu items and dividers are also available by using `Menu.Item` and `Menu.Divider`.
> Warning: You must set a unique `key` for `Menu.Item`.
>
@ -27,11 +27,11 @@ You should use [Menu](#/components/us/menu/) as `overlay`. The menu items and di
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| disabled | whether the dropdown menu is disabled | boolean | - |
| overlay(slot) | the dropdown menu | [Menu](#/components/us/menu) | - |
| overlay(slot) | the dropdown menu | [Menu](#/us/components/menu) | - |
| placement | placement of pop menu: `bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | String | `bottomLeft` |
| size | size of the button, the same as [Button](#/components/us/button) | string | `default` |
| size | size of the button, the same as [Button](#/us/components/button) | string | `default` |
| trigger | the trigger mode which executes the drop-down action | Array<`click`\|`hover`\|`contextMenu`> | `['hover']` |
| type | type of the button, the same as [Button](#/components/us/button) | string | `default` |
| type | type of the button, the same as [Button](#/us/components/button) | string | `default` |
| visible | whether the dropdown menu is visible | boolean | - |
@ -39,5 +39,5 @@ You should use [Menu](#/components/us/menu/) as `overlay`. The menu items and di
### Dropdown.Button events
| Events Name | Description | Arguments |
| --- | --- | --- |
| click | a callback function, the same as [Button](#/components/us/button), which will be executed when you click the button on the left | Function |
| click | a callback function, the same as [Button](#/us/components/button), which will be executed when you click the button on the left | Function |
| visibleChange | a callback function takes an argument: `visible`, is executed when the visible state is changed | Function |

View File

@ -6,12 +6,12 @@
| --- | --- | --- | --- |
| disabled | 菜单是否禁用 | boolean | - |
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。 | Function(triggerNode) | `() => document.body` |
| overlay(slot) | 菜单 | [Menu](#/components/cn/menu) | - |
| overlay(slot) | 菜单 | [Menu](#/cn/components/menu) | - |
| placement | 菜单弹出位置:`bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | String | `bottomLeft` |
| trigger | 触发下拉的行为 | Array<`click`\|`hover`\|`contextMenu`> | `['hover']` |
| visible(v-model) | 菜单是否显示 | boolean | - |
`overlay` 菜单使用 [Menu](#/components/cn/menu/),还包括菜单项 `Menu.Item`,分割线 `Menu.Divider`
`overlay` 菜单使用 [Menu](#/cn/components/menu/),还包括菜单项 `Menu.Item`,分割线 `Menu.Divider`
> 注意: Menu.Item 必须设置唯一的 key 属性。
>
@ -28,15 +28,15 @@
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| disabled | 菜单是否禁用 | boolean | - |
| overlay(slot) | 菜单 | [Menu](#/components/cn/menu/) | - |
| overlay(slot) | 菜单 | [Menu](#/cn/components/menu/) | - |
| placement | 菜单弹出位置:`bottomLeft` `bottomCenter` `bottomRight` `topLeft` `topCenter` `topRight` | String | `bottomLeft` |
| size | 按钮大小,和 [Button](#/components/cn/button/) 一致 | string | 'default' |
| size | 按钮大小,和 [Button](#/cn/components/button/) 一致 | string | 'default' |
| trigger | 触发下拉的行为 | Array<`click`\|`hover`\|`contextMenu`> | `['hover']` |
| type | 按钮类型,和 [Button](#/components/cn/button/) 一致 | string | 'default' |
| type | 按钮类型,和 [Button](#/cn/components/button/) 一致 | string | 'default' |
| visible(v-model) | 菜单是否显示 | boolean | - |
### Dropdown.Button事件
| 事件名称 | 说明 | 回调参数 |
| --- | --- | --- |
| click | 点击左侧按钮的回调,和 [Button](#/components/cn/button/) 一致 | Function |
| click | 点击左侧按钮的回调,和 [Button](#/cn/components/button/) 一致 | Function |
| visibleChange | 菜单显示状态改变时调用,参数为 visible | function(visible) |

View File

@ -59,3 +59,10 @@ export { default as Divider } from './divider'
import Collapse from './collapse'
const CollapsePanel = Collapse.Panel
export { Collapse, CollapsePanel }
import notification from './notification'
const api = {
notification,
}
export { api }

View File

@ -0,0 +1,29 @@
<cn>
#### 基本
最简单的用法4.5 秒后自动关闭。
</cn>
<us>
#### Basic
The simplest usage that close the notification box after 4.5s.
</us>
```html
<template>
<a-button type="primary" @click="openNotification">Open the notification box</a-button>
</template>
<script>
export default {
methods: {
openNotification () {
this.$notification.open({
message: 'Notification Title',
description: 'This is the content of the notification. This is the content of the notification. This is the content of the notification.',
});
},
}
}
</script>
```

View File

@ -0,0 +1,30 @@
<cn>
#### 自定义图标
图标可以被自定义。
</cn>
<us>
#### Customized Icon
The icon can be customized to any vue node or (h) => vue node.
</us>
```html
<template>
<a-button type="primary" @click="openNotification">Open the notification box</a-button>
</template>
<script>
export default {
methods: {
openNotification () {
this.$notification.open({
message: 'Notification Title',
description: 'This is the content of the notification. This is the content of the notification. This is the content of the notification.',
icon: <a-icon type="smile-circle" style="color: #108ee9" />,
});
},
}
}
</script>
```

View File

@ -0,0 +1,33 @@
<cn>
#### 自定义样式
使用 style 和 className 来定义样式。
</cn>
<us>
#### Customized style
The style and className are available to customize Notification.
</us>
```html
<template>
<a-button type="primary" @click="openNotification">Open the notification box</a-button>
</template>
<script>
export default {
methods: {
openNotification () {
this.$notification.open({
message: 'Notification Title',
description: 'This is the content of the notification. This is the content of the notification. This is the content of the notification.',
style: {
width: '600px',
marginLeft: `${335 - 600}px`,
},
});
},
}
}
</script>
```

View File

@ -0,0 +1,32 @@
<cn>
#### 自动关闭的延时
自定义通知框自动关闭的延时,默认`4.5s`,取消自动关闭只要将该值设为 `0` 即可。
</cn>
<us>
#### Duration after which the notification box is closed
`Duration` can be used to specify how long the notification stays open. After the duration time elapses,
the notification closes automatically. If not specified, default value is 4.5 seconds. If you set the value to 0,
the notification box will never close automatically.
</us>
```html
<template>
<a-button type="primary" @click="openNotification">Open the notification box</a-button>
</template>
<script>
export default {
methods: {
openNotification () {
this.$notification.open({
message: 'Notification Title',
description: 'I will never close automatically. I will be close automatically. I will never close automatically.',
duration: 0,
});
},
}
}
</script>
```

View File

@ -0,0 +1,50 @@
<script>
import Basic from './basic'
import CustomIcon from './custom-icon'
import CustomStyle from './custom-style'
import Duration from './duration'
import Placement from './placement'
import WithBtn from './with-btn'
import WithIcon from './with-icon'
import CN from '../index.zh-CN.md'
import US from '../index.en-US.md'
const md = {
cn: `# 通知提醒框
全局展示通知提醒信息
## 何时使用
在系统四个角显示通知提醒信息经常用于以下情况
- 较为复杂的通知内容
- 带有交互的通知给出用户下一步的行动点
- 系统主动推送
## 代码演示`,
us: `# Notification
Display a notification message globally.
## When To Use
To display a notification message at any of the four corners of the viewport. Typically it can be
used in the following cases:
- A notification with complex content.
- A notification providing a feedback based on the user interaction. Or it may show some details
about upcoming steps the user may have to follow.
- A notification that is pushed by the application.`,
}
export default {
render () {
return (
<div>
<md cn={md.cn} us={md.us}/>
<Basic />
<CustomIcon />
<CustomStyle />
<Duration />
<Placement />
<WithBtn />
<WithIcon />
<api>
<CN slot='cn' />
<US/>
</api>
</div>
)
},
}
</script>

View File

@ -0,0 +1,48 @@
<cn>
#### 位置
可以设置通知从右上角、右下角、左下角、左上角弹出。
</cn>
<us>
#### Placement
A notification box can pop up from `topRight` or `bottomRight` or `bottomLeft` or `topLeft`.
</us>
```html
<template>
<div>
<select v-model="selected">
<option v-for="val in options">{{val}}</option>
</select>
<a-button type="primary" @click="openNotification">Open the notification box</a-button>
</div>
</template>
<script>
const options = ['topLeft', 'topRight', 'bottomLeft', 'bottomRight'];
export default {
data () {
return {
options,
selected: 'topRight',
}
},
watch: {
selected(val) {
this.$notification.config({
placement: val,
});
}
},
methods: {
openNotification () {
this.$notification.open({
message: 'Notification Title',
description: 'This is the content of the notification. This is the content of the notification. This is the content of the notification.',
});
},
}
}
</script>
```

View File

@ -0,0 +1,46 @@
<cn>
#### 基本
最简单的用法4.5 秒后自动关闭。
</cn>
<us>
#### Basic
The simplest usage that close the notification box after 4.5s.
</us>
```html
<template>
<a-button type="primary" @click="openNotification">Open the notification box</a-button>
</template>
<script>
const close = () => {
console.log('Notification was closed. Either the close button was clicked or duration time elapsed.');
};
export default {
methods: {
openNotification () {
const key = `open${Date.now()}`;
this.$notification.open({
message: 'Notification Title',
description: 'A function will be be called after the notification is closed (automatically after the "duration" time of manually).',
btn: (h)=>{
return h('a-button', {
props: {
type: 'primary',
size: 'small',
},
on: {
click: () => this.$notification.close(key)
}
}, 'Confirm')
},
key,
onClose: close,
});
},
}
}
</script>
```

View File

@ -0,0 +1,34 @@
<cn>
#### 带有图标的通知提醒框
通知提醒框左侧有图标。
</cn>
<us>
#### Notification with icon
A notification box with a icon at the left side.
</us>
```html
<template>
<div>
<a-button @click="() => openNotificationWithIcon('success')">Success</a-button>
<a-button @click="() => openNotificationWithIcon('info')">Info</a-button>
<a-button @click="() => openNotificationWithIcon('warning')">Warning</a-button>
<a-button @click="() => openNotificationWithIcon('error')">Error</a-button>
</div>
</template>
<script>
export default {
methods: {
openNotificationWithIcon (type) {
this.$notification[type]({
message: 'Notification Title',
description: 'This is the content of the notification. This is the content of the notification. This is the content of the notification.',
});
},
}
}
</script>
```

View File

@ -1,22 +1,3 @@
---
category: Components
type: Feedback
noinstant: true
title: Notification
---
Display a notification message globally.
## When To Use
To display a notification message at any of the four corners of the viewport. Typically it can be
used in the following cases:
- A notification with complex content.
- A notification providing a feedback based on the user interaction. Or it may show some details
about upcoming steps the user may have to follow.
- A notification that is pushed by the application.
## API
- `notification.success(config)`
@ -31,15 +12,15 @@ The properties of config are as follows:
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| btn | Customized close button | ReactNode | - |
| className | Customized CSS class | string | - |
| description | The content of notification box (required) | string\|ReactNode | - |
| btn | Customized close button | vueNode \|function(h) | - |
| class | Customized CSS class | string | - |
| description | The content of notification box (required) | string\| vueNode \|function(h) | - |
| duration | Time in seconds before Notification is closed. When set to 0 or null, it will never be closed automatically | number | 4.5 |
| icon | Customized icon | ReactNode | - |
| icon | Customized icon | vueNode \|function(h) | - |
| key | The unique identifier of the Notification | string | - |
| message | The title of notification box (required) | string\|ReactNode | - |
| message | The title of notification box (required) | string\|vueNode \|function(h) | - |
| placement | Position of Notification, can be one of `topLeft` `topRight` `bottomLeft` `bottomRight` | string | `topRight` |
| style | Customized inline style | [React.CSSProperties](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/e434515761b36830c3e58a970abf5186f005adac/types/react/index.d.ts#L794) | - |
| style | Customized inline style | Object \| string | - |
| onClose | Specify a function that will be called when the close button is clicked | Function | - |
`notification` also provides a global `config()` method that can be used for specifying the default options. Once this method is used, all the notification boxes will take into account these globally defined options when displaying.
@ -49,15 +30,15 @@ The properties of config are as follows:
```js
notification.config({
placement: 'bottomRight',
bottom: 50,
bottom: '50px',
duration: 3,
});
```
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| bottom | Distance from the bottom of the viewport, when `placement` is `bottomRight` or `bottomLeft` (unit: pixels). | number | 24 |
| bottom | Distance from the bottom of the viewport, when `placement` is `bottomRight` or `bottomLeft` (unit: pixels). | string | `24px` |
| duration | Time in seconds before Notification is closed. When set to 0 or null, it will never be closed automatically | number | 4.5 |
| getContainer | Return the mount node for Notification | () => HTMLNode | () => document.body |
| placement | Position of Notification, can be one of `topLeft` `topRight` `bottomLeft` `bottomRight` | string | `topRight` |
| top | Distance from the top of the viewport, when `placement` is `topRight` or `topLeft` (unit: pixels). | number | 24 |
| top | Distance from the top of the viewport, when `placement` is `topRight` or `topLeft` (unit: pixels). | string | `24px` |

View File

@ -0,0 +1,204 @@
import Notification from './src/notification'
import Icon from '../icon'
// export type NotificationPlacement = 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight';
// export type IconType = 'success' | 'info' | 'error' | 'warning';
const notificationInstance = {}
let defaultDuration = 4.5
let defaultTop = '24px'
let defaultBottom = '24px'
let defaultPlacement = 'topRight'
let defaultGetContainer = () => document.body
// export interface ConfigProps {
// top?: number;
// bottom?: number;
// duration?: number;
// placement?: NotificationPlacement;
// getContainer?: () => HTMLElement;
// }
function setNotificationConfig (options) {
const { duration, placement, bottom, top, getContainer } = options
if (duration !== undefined) {
defaultDuration = duration
}
if (placement !== undefined) {
defaultPlacement = placement
}
if (bottom !== undefined) {
defaultBottom = bottom
}
if (top !== undefined) {
defaultTop = top
}
if (getContainer !== undefined) {
defaultGetContainer = getContainer
}
}
function getPlacementStyle (placement) {
let style
switch (placement) {
case 'topLeft':
style = {
left: 0,
top: defaultTop,
bottom: 'auto',
}
break
case 'topRight':
style = {
right: 0,
top: defaultTop,
bottom: 'auto',
}
break
case 'bottomLeft':
style = {
left: 0,
top: 'auto',
bottom: defaultBottom,
}
break
default:
style = {
right: 0,
top: 'auto',
bottom: defaultBottom,
}
break
}
return style
}
function getNotificationInstance (prefixCls, placement, callback) {
const cacheKey = `${prefixCls}-${placement}`
if (notificationInstance[cacheKey]) {
callback(notificationInstance[cacheKey])
return
}
Notification.newInstance({
prefixCls,
class: `${prefixCls}-${placement}`,
style: getPlacementStyle(placement),
getContainer: defaultGetContainer,
}, (notification) => {
notificationInstance[cacheKey] = notification
callback(notification)
})
}
const typeToIcon = {
success: 'check-circle-o',
info: 'info-circle-o',
error: 'cross-circle-o',
warning: 'exclamation-circle-o',
}
// export interface ArgsProps {
// message: React.ReactNode;
// description: React.ReactNode;
// btn?: React.ReactNode;
// key?: string;
// onClose?: () => void;
// duration?: number | null;
// icon?: React.ReactNode;
// placement?: NotificationPlacement;
// style?: React.CSSProperties;
// prefixCls?: string;
// className?: string;
// readonly type?: IconType;
// }
function notice (args) {
const { icon, type, description, placement, message, btn } = args
const outerPrefixCls = args.prefixCls || 'ant-notification'
const prefixCls = `${outerPrefixCls}-notice`
const duration = args.duration === undefined ? defaultDuration : args.duration
let iconNode = null
if (icon) {
iconNode = (h) => (
<span class={`${prefixCls}-icon`}>
{typeof icon === 'function' ? icon(h) : icon}
</span>
)
} else if (type) {
const iconType = typeToIcon[type]
iconNode = (h) => (
<Icon
class={`${prefixCls}-icon ${prefixCls}-icon-${type}`}
type={iconType}
/>
)
}
const autoMarginTag = (!description && iconNode)
? <span class={`${prefixCls}-message-single-line-auto-margin`} />
: null
getNotificationInstance(outerPrefixCls, placement || defaultPlacement, (notification) => {
notification.notice({
content: (h) => (
<div class={iconNode ? `${prefixCls}-with-icon` : ''}>
{iconNode && iconNode(h)}
<div class={`${prefixCls}-message`}>
{autoMarginTag}
{typeof message === 'function' ? message(h) : message}
</div>
<div class={`${prefixCls}-description`}>
{typeof description === 'function' ? description(h) : description}
</div>
{btn ? <span class={`${prefixCls}-btn`}>
{typeof btn === 'function' ? btn(h) : btn}
</span> : null}
</div>
),
duration,
closable: true,
onClose: args.onClose,
key: args.key,
style: args.style || {},
class: args.class,
})
})
}
const api = {
open: notice,
close (key) {
Object.keys(notificationInstance)
.forEach(cacheKey => notificationInstance[cacheKey].removeNotice(key))
},
config: setNotificationConfig,
destroy () {
Object.keys(notificationInstance).forEach(cacheKey => {
notificationInstance[cacheKey].destroy()
delete notificationInstance[cacheKey]
})
},
};
['success', 'info', 'warning', 'error'].forEach((type) => {
api[type] = (args) => api.open({
...args,
type,
})
})
api.warn = api.warning
// export interface NotificationApi {
// success(args: ArgsProps): void;
// error(args: ArgsProps): void;
// info(args: ArgsProps): void;
// warn(args: ArgsProps): void;
// warning(args: ArgsProps): void;
// open(args: ArgsProps): void;
// close(key: string): void;
// config(options: ConfigProps): void;
// destroy(): void;
// }
export default api

View File

@ -1,201 +0,0 @@
<script>
import Notification from './src/notification';
import Icon from '../icon';
export type NotificationPlacement = 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight';
export type IconType = 'success' | 'info' | 'error' | 'warning';
const notificationInstance: { [key: string]: any } = {};
let defaultDuration = 4.5;
let defaultTop = 24;
let defaultBottom = 24;
let defaultPlacement: NotificationPlacement = 'topRight';
let defaultGetContainer: () => HTMLElement;
export interface ConfigProps {
top?: number;
bottom?: number;
duration?: number;
placement?: NotificationPlacement;
getContainer?: () => HTMLElement;
}
function setNotificationConfig(options: ConfigProps) {
const { duration, placement, bottom, top, getContainer } = options;
if (duration !== undefined) {
defaultDuration = duration;
}
if (placement !== undefined) {
defaultPlacement = placement;
}
if (bottom !== undefined) {
defaultBottom = bottom;
}
if (top !== undefined) {
defaultTop = top;
}
if (getContainer !== undefined) {
defaultGetContainer = getContainer;
}
}
function getPlacementStyle(placement: NotificationPlacement) {
let style;
switch (placement) {
case 'topLeft':
style = {
left: 0,
top: defaultTop,
bottom: 'auto',
};
break;
case 'topRight':
style = {
right: 0,
top: defaultTop,
bottom: 'auto',
};
break;
case 'bottomLeft':
style = {
left: 0,
top: 'auto',
bottom: defaultBottom,
};
break;
default:
style = {
right: 0,
top: 'auto',
bottom: defaultBottom,
};
break;
}
return style;
}
function getNotificationInstance(prefixCls: string, placement: NotificationPlacement, callback: (n: any) => void) {
const cacheKey = `${prefixCls}-${placement}`;
if (notificationInstance[cacheKey]) {
callback(notificationInstance[cacheKey]);
return;
}
(Notification as any).newInstance({
prefixCls,
className: `${prefixCls}-${placement}`,
style: getPlacementStyle(placement),
getContainer: defaultGetContainer,
}, (notification: any) => {
notificationInstance[cacheKey] = notification;
callback(notification);
});
}
const typeToIcon = {
success: 'check-circle-o',
info: 'info-circle-o',
error: 'cross-circle-o',
warning: 'exclamation-circle-o',
};
export interface ArgsProps {
message: React.ReactNode;
description: React.ReactNode;
btn?: React.ReactNode;
key?: string;
onClose?: () => void;
duration?: number | null;
icon?: React.ReactNode;
placement?: NotificationPlacement;
style?: React.CSSProperties;
prefixCls?: string;
className?: string;
readonly type?: IconType;
}
function notice(args: ArgsProps) {
const outerPrefixCls = args.prefixCls || 'ant-notification';
const prefixCls = `${outerPrefixCls}-notice`;
const duration = args.duration === undefined ? defaultDuration : args.duration;
let iconNode: React.ReactNode = null;
if (args.icon) {
iconNode = (
<span className={`${prefixCls}-icon`}>
{args.icon}
</span>
);
} else if (args.type) {
const iconType = typeToIcon[args.type];
iconNode = (
<Icon
className={`${prefixCls}-icon ${prefixCls}-icon-${args.type}`}
type={iconType}
/>
);
}
const autoMarginTag = (!args.description && iconNode)
? <span className={`${prefixCls}-message-single-line-auto-margin`} />
: null;
getNotificationInstance(outerPrefixCls, args.placement || defaultPlacement, (notification: any) => {
notification.notice({
content: (
<div className={iconNode ? `${prefixCls}-with-icon` : ''}>
{iconNode}
<div className={`${prefixCls}-message`}>
{autoMarginTag}
{args.message}
</div>
<div className={`${prefixCls}-description`}>{args.description}</div>
{args.btn ? <span className={`${prefixCls}-btn`}>{args.btn}</span> : null}
</div>
),
duration,
closable: true,
onClose: args.onClose,
key: args.key,
style: args.style || {},
className: args.className,
});
});
}
const api: any = {
open: notice,
close(key: string) {
Object.keys(notificationInstance)
.forEach(cacheKey => notificationInstance[cacheKey].removeNotice(key));
},
config: setNotificationConfig,
destroy() {
Object.keys(notificationInstance).forEach(cacheKey => {
notificationInstance[cacheKey].destroy();
delete notificationInstance[cacheKey];
});
},
};
['success', 'info', 'warning', 'error'].forEach((type) => {
api[type] = (args: ArgsProps) => api.open({
...args,
type,
});
});
api.warn = api.warning;
export interface NotificationApi {
success(args: ArgsProps): void;
error(args: ArgsProps): void;
info(args: ArgsProps): void;
warn(args: ArgsProps): void;
warning(args: ArgsProps): void;
open(args: ArgsProps): void;
close(key: string): void;
config(options: ConfigProps): void;
destroy(): void;
}
export default api as NotificationApi;
</script>

View File

@ -1,13 +1,3 @@
---
category: Components
type: Feedback
noinstant: true
title: Notification
subtitle: 通知提醒框
---
全局展示通知提醒信息。
## 何时使用
在系统四个角显示通知提醒信息。经常用于以下情况:
@ -30,15 +20,15 @@ config 参数如下:
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| btn | 自定义关闭按钮 | ReactNode | - |
| className | 自定义 CSS class | string | - |
| description | 通知提醒内容,必选 | string\|ReactNode | - |
| btn | 自定义关闭按钮 | vueNode \|function(h) | - |
| class | 自定义 CSS class | string | - |
| description | 通知提醒内容,必选 | string \|vueNode \|function(h) | - |
| duration | 默认 4.5 秒后自动关闭,配置为 null 则不自动关闭 | number | 4.5 |
| icon | 自定义图标 | ReactNode | - |
| icon | 自定义图标 | vueNode \|function(h) | - |
| key | 当前通知唯一标志 | string | - |
| message | 通知提醒标题,必选 | string\|ReactNode | - |
| message | 通知提醒标题,必选 | string \|vueNode \|function(h) | - |
| placement | 弹出位置,可选 `topLeft` `topRight` `bottomLeft` `bottomRight` | string | topRight |
| style | 自定义内联样式 | [React.CSSProperties](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/e434515761b36830c3e58a970abf5186f005adac/types/react/index.d.ts#L794) | - |
| style | 自定义内联样式 | Object \| string | - |
| onClose | 点击默认关闭按钮时触发的回调函数 | Function | - |
还提供了一个全局配置方法,在调用前提前配置,全局一次生效。
@ -48,15 +38,15 @@ config 参数如下:
```js
notification.config({
placement: 'bottomRight',
bottom: 50,
bottom: '50px',
duration: 3,
});
```
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| bottom | 消息从底部弹出时,距离底部的位置,单位像素。 | number | 24 |
| bottom | 消息从底部弹出时,距离底部的位置,单位像素。 | string | `24px` |
| duration | 默认自动关闭延时,单位秒 | number | 4.5 |
| getContainer | 配置渲染节点的输出位置 | () => HTMLNode | () => document.body |
| placement | 弹出位置,可选 `topLeft` `topRight` `bottomLeft` `bottomRight` | string | topRight |
| top | 消息从顶部弹出时,距离顶部的位置,单位像素。 | number | 24 |
| top | 消息从顶部弹出时,距离顶部的位置,单位像素。 | string | `24px` |

View File

@ -7,23 +7,27 @@ export default {
mixins: [BaseMixin],
props: {
duration: PropTypes.number.def(1.5),
closable: PropTypes.bool,
prefixCls: PropTypes.string,
},
mounted () {
this.startCloseTimer()
},
beforeDestory () {
beforeDestroy () {
this.clearCloseTimer()
this.willDestroy = true // beforeDestroyonMouseleave
},
methods: {
close () {
this.clearCloseTimer()
this._emit('close')
this.__emit('close')
},
startCloseTimer () {
if (this.duration) {
this.clearCloseTimer()
if (!this.willDestroy && this.duration) {
this.closeTimer = setTimeout(() => {
this.close()
}, this.duration * 1000)

View File

@ -57,26 +57,32 @@ const Notification = {
},
},
render () {
render (h) {
const { prefixCls, notices, remove, getTransitionName } = this
const transitionProps = getTransitionProps(getTransitionName())
const noticeNodes = notices.map((notice) => {
const onClose = createChainedFunction(remove.bind(this, notice.key), notice.on.close)
const { content, duration, closable, onClose, key, style, class: className } = notice
const close = createChainedFunction(remove.bind(this, key), onClose)
const noticeProps = {
...notice,
props: {
prefixCls,
...notice.props,
duration,
closable,
},
on: {
...notice.on,
close: onClose,
close,
},
style,
class: className,
key,
}
return (<Notice
{...noticeProps}
>
{notice.content}
</Notice>)
return (
<Notice
{...noticeProps}
>
{content(h)}
</Notice>
)
})
const className = {
[prefixCls]: 1,
@ -87,14 +93,14 @@ const Notification = {
top: '65px',
left: '50%',
}}>
<transition-group {...getTransitionProps(getTransitionName(), { tag: 'div' })}>{noticeNodes}</transition-group>
<transition-group {...transitionProps}>{noticeNodes}</transition-group>
</div>
)
},
}
Notification.newInstance = function newNotificationInstance (properties, callback) {
const { getContainer, style, class: className, on = {}, ...props } = properties || {}
const { getContainer, style, class: className, ...props } = properties || {}
const div = document.createElement('div')
if (getContainer) {
const root = getContainer()
@ -102,7 +108,7 @@ Notification.newInstance = function newNotificationInstance (properties, callbac
} else {
document.body.appendChild(div)
}
const notificationInstance = new Vue({
new Vue({
el: div,
mounted () {
const self = this
@ -116,9 +122,8 @@ Notification.newInstance = function newNotificationInstance (properties, callbac
},
component: self,
destroy () {
// self.$destroy()
notificationInstance.$destroy()
div.parentNode.removeChild(div)
self.$destroy()
self.$el.parentNode.removeChild(self.$el)
},
})
})
@ -126,7 +131,6 @@ Notification.newInstance = function newNotificationInstance (properties, callbac
render () {
const p = {
props,
on,
ref: 'notification',
style,
class: className,

View File

@ -18,3 +18,4 @@ import './dropdown/style'
import './divider/style'
import './card/style'
import './collapse/style'
import './notification/style'

View File

@ -13,6 +13,8 @@ Popover | done
Menu | done
Dropdown | done
Divider | done
notification | done
message
Carousel
Mention
Input | done |select完成后补全demo
@ -32,9 +34,7 @@ Affix
Alert
BackTop
Layout
message
Modal
notification
Anchor
Tree
TreeSelect
@ -46,7 +46,7 @@ Avatar | done
Badge | done
Breadcrumb | done
Card | done
Collapse
Collapse | done
LocaleProvider
Progress
Slider

View File

@ -15,7 +15,7 @@ export default {
<div class='main-wrapper'>
<a-menu class='nav' selectedKeys={[name]}>
{Object.keys(AllDemo).map(d => <a-menu-item key={d}>
<router-link to={{ path: `/components/${lang}/${d}` }}>{d}</router-link>
<router-link to={{ path: `/${lang}/components/${d}` }}>{d}</router-link>
</a-menu-item>)}
</a-menu>
<div class='content main-container'>

View File

@ -19,4 +19,5 @@ export { default as tooltip } from 'antd/tooltip/demo/index.vue'
export { default as dropdown } from 'antd/dropdown/demo/index.vue'
export { default as divider } from 'antd/divider/demo/index.vue'
export { default as collapse } from 'antd/collapse/demo/index.vue'
export { default as notification } from 'antd/notification/demo/index.vue'

View File

@ -16,8 +16,14 @@ Vue.component(Md.name, Md)
Vue.component(Api.name, Api)
Vue.component('demo-box', demoBox)
Object.keys(Components).forEach(k => {
const name = `a${k.replace(/([A-Z])/g, '-$1').toLowerCase()}`
Vue.component(name, Components[k])
if (k === 'api') {
Object.keys(Components[k]).forEach(api => {
Vue.prototype[`$${api}`] = Components[k][api]
})
} else {
const name = `a${k.replace(/([A-Z])/g, '-$1').toLowerCase()}`
Vue.component(name, Components[k])
}
})
const router = new VueRouter({

View File

@ -1,11 +1,13 @@
import Demo from './components/demo.vue'
const AsyncComp = () => {
const hashs = window.location.hash.split('/')
const d = hashs[hashs.length - 1]
return {
component: import(`../components/collapse/demo/index.vue`),
component: import(`../components/notification/demo/${d}.md`),
}
}
export default [
{ path: '/components/:lang/:name/:demo?', component: Demo },
{ path: '/:lang/components/:name/:demo?', component: Demo },
{ path: '/:lang?/test/:name/:demo?', component: AsyncComp },
{ path: '/*', redirect: '/components/cn/menu' },
{ path: '/*', redirect: '/cn/components/menu' },
]