mirror of https://github.com/ElemeFE/element
Notification: add position
parent
7d69d11ead
commit
c340ed13e4
|
@ -49,13 +49,52 @@
|
|||
},
|
||||
|
||||
open7() {
|
||||
this.$notify.success({
|
||||
this.$notify({
|
||||
title: 'Custom Position',
|
||||
message: 'I\'m at the top right corner'
|
||||
});
|
||||
},
|
||||
|
||||
open8() {
|
||||
this.$notify({
|
||||
title: 'Custom Position',
|
||||
message: 'I\'m at the bottom right corner',
|
||||
position: 'bottom-right'
|
||||
});
|
||||
},
|
||||
|
||||
open9() {
|
||||
this.$notify({
|
||||
title: 'Custom Position',
|
||||
message: 'I\'m at the bottom left corner',
|
||||
position: 'bottom-left'
|
||||
});
|
||||
},
|
||||
|
||||
open10() {
|
||||
this.$notify({
|
||||
title: 'Custom Position',
|
||||
message: 'I\'m at the top left corner',
|
||||
position: 'top-left'
|
||||
});
|
||||
},
|
||||
|
||||
open11() {
|
||||
this.$notify({
|
||||
title: 'Success',
|
||||
message: 'This is a success message',
|
||||
offset: 100
|
||||
});
|
||||
},
|
||||
|
||||
open12() {
|
||||
this.$notify({
|
||||
title: 'HTML String',
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: '<strong>This is <i>HTML</i> string</strong>'
|
||||
});
|
||||
},
|
||||
|
||||
onClose() {
|
||||
console.log('Notification is closed');
|
||||
}
|
||||
|
@ -65,7 +104,7 @@
|
|||
|
||||
## Notification
|
||||
|
||||
Displays a global notification message at the upper right corner of the page.
|
||||
Displays a global notification message at a corner of the page.
|
||||
|
||||
### Basic usage
|
||||
|
||||
|
@ -177,17 +216,32 @@ We provide four types: success, warning, info and error.
|
|||
```
|
||||
:::
|
||||
|
||||
### With offset
|
||||
### Custom Position
|
||||
|
||||
Customize Notification's offset from the top edge of the screen
|
||||
Notification can emerge from any corner you like.
|
||||
|
||||
::: demo Set the `offset` attribute to customize Notification's offset from the top edge of the screen. Note that every Notification instance of the same moment should have the same offset.
|
||||
::: demo The `position` attribute defines which corner Notification slides in. It can be `top-right`, `top-left`, `bottom-right` or `bottom-left`. Defaults to `top-right`.
|
||||
```html
|
||||
<template>
|
||||
<el-button
|
||||
plain
|
||||
@click="open7">
|
||||
Notification with offset
|
||||
plain
|
||||
@click="open7">
|
||||
Top Right
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
@click="open8">
|
||||
Bottom Right
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
@click="open9">
|
||||
Bottom Left
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
@click="open10">
|
||||
Top Left
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
|
@ -195,7 +249,60 @@ Customize Notification's offset from the top edge of the screen
|
|||
export default {
|
||||
methods: {
|
||||
open7() {
|
||||
this.$notify.success({
|
||||
this.$notify({
|
||||
title: 'Custom Position',
|
||||
message: 'I\'m at the top right corner'
|
||||
});
|
||||
},
|
||||
|
||||
open8() {
|
||||
this.$notify({
|
||||
title: 'Custom Position',
|
||||
message: 'I\'m at the bottom right corner',
|
||||
position: 'bottom-right'
|
||||
});
|
||||
},
|
||||
|
||||
open9() {
|
||||
this.$notify({
|
||||
title: 'Custom Position',
|
||||
message: 'I\'m at the bottom left corner',
|
||||
position: 'bottom-left'
|
||||
});
|
||||
},
|
||||
|
||||
open10() {
|
||||
this.$notify({
|
||||
title: 'Custom Position',
|
||||
message: 'I\'m at the top left corner',
|
||||
position: 'top-left'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
### With offset
|
||||
|
||||
Customize Notification's offset from the edge of the screen.
|
||||
|
||||
::: demo Set the `offset` attribute to customize Notification's offset from the edge of the screen. Note that every Notification instance of the same moment should have the same offset.
|
||||
```html
|
||||
<template>
|
||||
<el-button
|
||||
plain
|
||||
@click="open11">
|
||||
Notification with offset
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
open11() {
|
||||
this.$notify({
|
||||
title: 'Success',
|
||||
message: 'This is a success message',
|
||||
offset: 100
|
||||
|
@ -207,6 +314,39 @@ Customize Notification's offset from the top edge of the screen
|
|||
```
|
||||
:::
|
||||
|
||||
### Use HTML String
|
||||
`message` supports HTML string.
|
||||
|
||||
::: demo Set `dangerouslyUseHTMLString` to true and `message` will be treated as an HTML string.
|
||||
```html
|
||||
<template>
|
||||
<el-button
|
||||
plain
|
||||
@click="open12">
|
||||
Use HTML String
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
open12() {
|
||||
this.$notify({
|
||||
title: 'HTML String',
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: '<strong>This is <i>HTML</i> string</strong>'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
:::warning
|
||||
Although `message` property supports HTML strings, dynamically rendering arbitrary HTML on your website can be very dangerous because it can easily lead to [XSS attacks](https://en.wikipedia.org/wiki/Cross-site_scripting). So when `dangerouslyUseHTMLString` is on, please make sure the content of `message` is trusted, and **never** assign `message` to user-provided content.
|
||||
:::
|
||||
|
||||
### Global method
|
||||
|
||||
Element has added a global method `$notify` for Vue.prototype. So in a vue instance you can call `Notification` like what we did in this page.
|
||||
|
@ -226,6 +366,7 @@ In this case you should call `Notification(options)`. We have also registered me
|
|||
|---------- |-------------- |---------- |-------------------------------- |-------- |
|
||||
| title | title | string | — | — |
|
||||
| message | description text | string/Vue.VNode | — | — |
|
||||
| dangerouslyUseHTMLString | whether `message` is treated as HTML string | boolean | — | false |
|
||||
| type | notification type | string | success/warning/info/error | — |
|
||||
| iconClass | custom icon's class. It will be overridden by `type` | string | — | — |
|
||||
| customClass | custom class name for Notification | string | — | — |
|
||||
|
|
|
@ -49,13 +49,52 @@
|
|||
},
|
||||
|
||||
open7() {
|
||||
this.$notify.success({
|
||||
title: '成功',
|
||||
message: '这是一条成功的提示消息',
|
||||
this.$notify({
|
||||
title: '自定义位置',
|
||||
message: '右上角弹出的消息'
|
||||
});
|
||||
},
|
||||
|
||||
open8() {
|
||||
this.$notify({
|
||||
title: '自定义位置',
|
||||
message: '右下角弹出的消息',
|
||||
position: 'bottom-right'
|
||||
});
|
||||
},
|
||||
|
||||
open9() {
|
||||
this.$notify({
|
||||
title: '自定义位置',
|
||||
message: '左下角弹出的消息',
|
||||
position: 'bottom-left'
|
||||
});
|
||||
},
|
||||
|
||||
open10() {
|
||||
this.$notify({
|
||||
title: '自定义位置',
|
||||
message: '左上角弹出的消息',
|
||||
position: 'top-left'
|
||||
});
|
||||
},
|
||||
|
||||
open11() {
|
||||
this.$notify({
|
||||
title: '偏移',
|
||||
message: '这是一条带有偏移的提示消息',
|
||||
offset: 100
|
||||
});
|
||||
},
|
||||
|
||||
open12() {
|
||||
this.$notify({
|
||||
title: 'HTML 片段',
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: '<strong>这是 <i>HTML</i> 片段</strong>'
|
||||
});
|
||||
},
|
||||
|
||||
onClose() {
|
||||
console.log('Notification 已关闭');
|
||||
}
|
||||
|
@ -65,7 +104,7 @@
|
|||
|
||||
## Notification 通知
|
||||
|
||||
悬浮出现在页面右上角,显示全局的通知提醒消息。
|
||||
悬浮出现在页面角落,显示全局的通知提醒消息。
|
||||
|
||||
### 基本用法
|
||||
|
||||
|
@ -178,17 +217,32 @@
|
|||
```
|
||||
:::
|
||||
|
||||
### 带有偏移
|
||||
### 自定义弹出位置
|
||||
|
||||
让 Notification 偏移一些位置
|
||||
可以让 Notification 从屏幕四角中的任意一角弹出
|
||||
|
||||
::: demo Notification 提供设置偏移量的功能,通过设置 `offset` 字段,可以使弹出的消息距屏幕顶部偏移一段距离。注意在同一时刻,所有的 Notification 实例应当具有一个相同的偏移量。
|
||||
::: demo 使用`position`属性定义 Notification 的弹出位置,支持四个选项:`top-right`、`top-left`、`bottom-right`、`bottom-left`,默认为`top-right`。
|
||||
```html
|
||||
<template>
|
||||
<el-button
|
||||
plain
|
||||
@click="open7">
|
||||
偏移的消息
|
||||
右上角
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
@click="open8">
|
||||
右下角
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
@click="open9">
|
||||
左下角
|
||||
</el-button>
|
||||
<el-button
|
||||
plain
|
||||
@click="open10">
|
||||
左上角
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
|
@ -196,9 +250,62 @@
|
|||
export default {
|
||||
methods: {
|
||||
open7() {
|
||||
this.$notify.success({
|
||||
title: '成功',
|
||||
message: '这是一条成功的提示消息',
|
||||
this.$notify({
|
||||
title: '自定义位置',
|
||||
message: '右上角弹出的消息'
|
||||
});
|
||||
},
|
||||
|
||||
open8() {
|
||||
this.$notify({
|
||||
title: '自定义位置',
|
||||
message: '右下角弹出的消息',
|
||||
position: 'bottom-right'
|
||||
});
|
||||
},
|
||||
|
||||
open9() {
|
||||
this.$notify({
|
||||
title: '自定义位置',
|
||||
message: '左下角弹出的消息',
|
||||
position: 'bottom-left'
|
||||
});
|
||||
},
|
||||
|
||||
open10() {
|
||||
this.$notify({
|
||||
title: '自定义位置',
|
||||
message: '左上角弹出的消息',
|
||||
position: 'top-left'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
### 带有偏移
|
||||
|
||||
让 Notification 偏移一些位置
|
||||
|
||||
::: demo Notification 提供设置偏移量的功能,通过设置 `offset` 字段,可以使弹出的消息距屏幕边缘偏移一段距离。注意在同一时刻,所有的 Notification 实例应当具有一个相同的偏移量。
|
||||
```html
|
||||
<template>
|
||||
<el-button
|
||||
plain
|
||||
@click="open11">
|
||||
偏移的消息
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
open11() {
|
||||
this.$notify({
|
||||
title: '偏移',
|
||||
message: '这是一条带有偏移的提示消息',
|
||||
offset: 100
|
||||
});
|
||||
}
|
||||
|
@ -208,6 +315,39 @@
|
|||
```
|
||||
:::
|
||||
|
||||
### 使用 HTML 片段
|
||||
`message` 属性支持传入 HTML 片段
|
||||
|
||||
::: demo 将`dangerouslyUseHTMLString`属性设置为 true,`message` 就会被当作 HTML 片段处理。
|
||||
```html
|
||||
<template>
|
||||
<el-button
|
||||
plain
|
||||
@click="open12">
|
||||
使用 HTML 片段
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
open12() {
|
||||
this.$notify({
|
||||
title: 'HTML 片段',
|
||||
dangerouslyUseHTMLString: true,
|
||||
message: '<strong>这是 <i>HTML</i> 片段</strong>'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
:::
|
||||
|
||||
:::warning
|
||||
`message` 属性虽然支持传入 HTML 片段,但是在网站上动态渲染任意 HTML 是非常危险的,因为容易导致 [XSS 攻击](https://en.wikipedia.org/wiki/Cross-site_scripting)。因此在 `dangerouslyUseHTMLString` 打开的情况下,请确保 `message` 的内容是可信的,**永远不要**将用户提交的内容赋值给 `message` 属性。
|
||||
:::
|
||||
|
||||
### 全局方法
|
||||
|
||||
Element 为 `Vue.prototype` 添加了全局方法 `$notify`。因此在 vue instance 中可以采用本页面中的方式调用 Notification。
|
||||
|
@ -227,6 +367,7 @@ import { Notification } from 'element-ui';
|
|||
|---------- |-------------- |---------- |-------------------------------- |-------- |
|
||||
| title | 标题 | string | — | — |
|
||||
| message | 说明文字 | string/Vue.VNode | — | — |
|
||||
| dangerouslyUseHTMLString | 是否将 message 属性作为 HTML 片段处理 | boolean | — | false |
|
||||
| type | 主题样式,如果不在可选值内将被忽略 | string | success/warning/info/error | — |
|
||||
| iconClass | 自定义图标的类名。若设置了 `type`,则 `iconClass` 会被覆盖 | string | — | — |
|
||||
| customClass | 自定义类名 | string | — | — |
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
import Vue from 'vue';
|
||||
import { PopupManager } from 'element-ui/src/utils/popup';
|
||||
import { isVNode } from 'element-ui/src/utils/vdom';
|
||||
let NotificationConstructor = Vue.extend(require('./main.vue'));
|
||||
const NotificationConstructor = Vue.extend(require('./main.vue'));
|
||||
|
||||
let instance;
|
||||
let instances = [];
|
||||
let seed = 1;
|
||||
|
||||
var Notification = function(options) {
|
||||
const Notification = function(options) {
|
||||
if (Vue.prototype.$isServer) return;
|
||||
options = options || {};
|
||||
let userOnClose = options.onClose;
|
||||
let id = 'notification_' + seed++;
|
||||
const userOnClose = options.onClose;
|
||||
const id = 'notification_' + seed++;
|
||||
const position = options.position || 'top-right';
|
||||
|
||||
options.onClose = function() {
|
||||
Notification.close(id, userOnClose);
|
||||
|
@ -32,13 +33,12 @@ var Notification = function(options) {
|
|||
instance.dom = instance.vm.$el;
|
||||
instance.dom.style.zIndex = PopupManager.nextZIndex();
|
||||
|
||||
const offset = options.offset || 0;
|
||||
let topDist = offset;
|
||||
for (let i = 0, len = instances.length; i < len; i++) {
|
||||
topDist += instances[i].$el.offsetHeight + 16;
|
||||
}
|
||||
topDist += 16;
|
||||
instance.top = topDist;
|
||||
let verticalOffset = options.offset || 0;
|
||||
instances.filter(item => item.position === position).forEach(item => {
|
||||
verticalOffset += item.$el.offsetHeight + 16;
|
||||
});
|
||||
verticalOffset += 16;
|
||||
instance.verticalOffset = verticalOffset;
|
||||
instances.push(instance);
|
||||
return instance.vm;
|
||||
};
|
||||
|
@ -56,23 +56,29 @@ var Notification = function(options) {
|
|||
});
|
||||
|
||||
Notification.close = function(id, userOnClose) {
|
||||
let index;
|
||||
let removedHeight;
|
||||
for (var i = 0, len = instances.length; i < len; i++) {
|
||||
if (id === instances[i].id) {
|
||||
if (typeof userOnClose === 'function') {
|
||||
userOnClose(instances[i]);
|
||||
}
|
||||
let index = -1;
|
||||
const len = instances.length;
|
||||
const instance = instances.filter((instance, i) => {
|
||||
if (instance.id === id) {
|
||||
index = i;
|
||||
removedHeight = instances[i].dom.offsetHeight;
|
||||
instances.splice(i, 1);
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
})[0];
|
||||
if (!instance) return;
|
||||
|
||||
if (len > 1) {
|
||||
for (i = index; i < len - 1 ; i++) {
|
||||
instances[i].dom.style.top = parseInt(instances[i].dom.style.top, 10) - removedHeight - 16 + 'px';
|
||||
if (typeof userOnClose === 'function') {
|
||||
userOnClose(instance);
|
||||
}
|
||||
instances.splice(index, 1);
|
||||
|
||||
if (len <= 1) return;
|
||||
const position = instance.position;
|
||||
const removedHeight = instance.dom.offsetHeight;
|
||||
for (let i = index; i < len - 1 ; i++) {
|
||||
if (instances[i].position === position) {
|
||||
instances[i].dom.style[instance.verticalProperty] =
|
||||
parseInt(instances[i].dom.style[instance.verticalProperty], 10) - removedHeight - 16 + 'px';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
<template>
|
||||
<transition name="el-notification-fade">
|
||||
<div
|
||||
class="el-notification"
|
||||
:class="customClass"
|
||||
:class="['el-notification', customClass, horizontalClass]"
|
||||
v-show="visible"
|
||||
:style="{ top: top ? top + 'px' : 'auto' }"
|
||||
:style="positionStyle"
|
||||
@mouseenter="clearTimer()"
|
||||
@mouseleave="startTimer()"
|
||||
@click="click">
|
||||
|
@ -15,7 +14,12 @@
|
|||
</i>
|
||||
<div class="el-notification__group" :class="{ 'is-with-icon': typeClass || iconClass }">
|
||||
<h2 class="el-notification__title" v-text="title"></h2>
|
||||
<div class="el-notification__content"><slot>{{ message }}</slot></div>
|
||||
<div class="el-notification__content">
|
||||
<slot>
|
||||
<p v-if="!dangerouslyUseHTMLString">{{ message }}</p>
|
||||
<p v-else v-html="message"></p>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="el-notification__closeBtn el-icon-close" @click.stop="close"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -43,14 +47,30 @@
|
|||
onClose: null,
|
||||
onClick: null,
|
||||
closed: false,
|
||||
top: null,
|
||||
timer: null
|
||||
verticalOffset: 0,
|
||||
timer: null,
|
||||
dangerouslyUseHTMLString: false,
|
||||
position: 'top-right'
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
typeClass() {
|
||||
return this.type && typeMap[this.type] ? `el-icon-${ typeMap[this.type] }` : '';
|
||||
},
|
||||
|
||||
horizontalClass() {
|
||||
return this.position.indexOf('right') > -1 ? 'right' : 'left';
|
||||
},
|
||||
|
||||
verticalProperty() {
|
||||
return /^top-/.test(this.position) ? 'top' : 'bottom';
|
||||
},
|
||||
|
||||
positionStyle() {
|
||||
return {
|
||||
[this.verticalProperty]: `${ this.verticalOffset }px`
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -9,12 +9,19 @@
|
|||
box-sizing: border-box;
|
||||
border-radius: var(--border-radius-small);
|
||||
position: fixed;
|
||||
right: 16px;
|
||||
background-color: var(--color-white);
|
||||
box-shadow: var(--notification-shadow);
|
||||
transition: opacity 0.3s, transform .3s, right .3s, top 0.4s;
|
||||
transition: opacity .3s, transform .3s, left .3s, right .3s, top 0.4s, bottom .3s;
|
||||
overflow: hidden;
|
||||
|
||||
&.right {
|
||||
right: 16px;
|
||||
}
|
||||
|
||||
&.left {
|
||||
left: 16px;
|
||||
}
|
||||
|
||||
@e group {
|
||||
margin-left: 0;
|
||||
@when with-icon {
|
||||
|
@ -35,6 +42,10 @@
|
|||
margin: 10px 0 0 0;
|
||||
color: var(--notification-color);
|
||||
text-align: justify;
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@e icon {
|
||||
|
@ -74,8 +85,15 @@
|
|||
}
|
||||
|
||||
.el-notification-fade-enter {
|
||||
transform: translateX(100%);
|
||||
right: 0;
|
||||
&.right {
|
||||
right: 0;
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
&.left {
|
||||
left: 0;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
}
|
||||
|
||||
.el-notification-fade-leave-active {
|
||||
|
|
|
@ -47,12 +47,23 @@ describe('Notification', () => {
|
|||
});
|
||||
const group = document.querySelector('.el-notification__group');
|
||||
const title = group.querySelector('.el-notification__title');
|
||||
const message = group.querySelector('.el-notification__content');
|
||||
const message = group.querySelector('.el-notification__content p');
|
||||
expect(document.querySelector('.el-notification')).to.exist;
|
||||
expect(title.textContent).to.equal('狮子');
|
||||
expect(message.textContent).to.equal('狮鹫');
|
||||
});
|
||||
|
||||
it('html string as message', () => {
|
||||
Notification({
|
||||
title: '狮子',
|
||||
message: '<strong>狮鹫</strong>',
|
||||
dangerouslyUseHTMLString: true,
|
||||
duration: 0
|
||||
});
|
||||
const message = document.querySelector('.el-notification__content strong');
|
||||
expect(message.textContent).to.equal('狮鹫');
|
||||
});
|
||||
|
||||
it('create by vnode', () => {
|
||||
const fakeVM = new Vue();
|
||||
const h = fakeVM.$createElement;
|
||||
|
|
Loading…
Reference in New Issue