2020-08-04 19:03:20 +08:00
|
|
|
<template>
|
2021-09-04 19:29:28 +08:00
|
|
|
<transition
|
|
|
|
name="el-notification-fade"
|
|
|
|
@before-leave="onClose"
|
|
|
|
@after-leave="$emit('destroy')"
|
|
|
|
>
|
2020-08-04 19:03:20 +08:00
|
|
|
<div
|
2020-08-06 17:53:58 +08:00
|
|
|
v-show="visible"
|
2020-08-04 19:03:20 +08:00
|
|
|
:id="id"
|
|
|
|
:class="['el-notification', customClass, horizontalClass]"
|
|
|
|
:style="positionStyle"
|
|
|
|
role="alert"
|
2021-01-31 18:43:33 +08:00
|
|
|
@mouseenter="clearTimer"
|
|
|
|
@mouseleave="startTimer"
|
|
|
|
@click="onClick"
|
2020-08-04 19:03:20 +08:00
|
|
|
>
|
2021-10-27 23:17:13 +08:00
|
|
|
<el-icon
|
|
|
|
v-if="iconComponent"
|
2020-08-06 17:53:58 +08:00
|
|
|
class="el-notification__icon"
|
2021-10-27 23:17:13 +08:00
|
|
|
:class="typeClass"
|
2020-08-06 17:53:58 +08:00
|
|
|
>
|
2021-10-27 23:17:13 +08:00
|
|
|
<component :is="iconComponent" />
|
|
|
|
</el-icon>
|
|
|
|
<div class="el-notification__group">
|
2020-08-04 19:03:20 +08:00
|
|
|
<h2 class="el-notification__title" v-text="title"></h2>
|
2021-09-04 19:29:28 +08:00
|
|
|
<div
|
|
|
|
v-show="message"
|
|
|
|
class="el-notification__content"
|
2021-09-22 01:19:35 +08:00
|
|
|
:style="!!title ? undefined : { margin: 0 }"
|
2021-09-04 19:29:28 +08:00
|
|
|
>
|
2020-08-04 19:03:20 +08:00
|
|
|
<slot>
|
|
|
|
<p v-if="!dangerouslyUseHTMLString">{{ message }}</p>
|
|
|
|
<!-- Caution here, message could've been compromized, nerver use user's input as message -->
|
|
|
|
<!-- eslint-disable-next-line -->
|
|
|
|
<p v-else v-html="message"></p>
|
|
|
|
</slot>
|
|
|
|
</div>
|
2021-10-27 23:17:13 +08:00
|
|
|
<el-icon
|
2020-08-06 17:53:58 +08:00
|
|
|
v-if="showClose"
|
2021-10-27 23:17:13 +08:00
|
|
|
class="el-notification__closeBtn"
|
2020-08-06 17:53:58 +08:00
|
|
|
@click.stop="close"
|
2021-10-27 23:17:13 +08:00
|
|
|
>
|
|
|
|
<close />
|
|
|
|
</el-icon>
|
2020-08-04 19:03:20 +08:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</transition>
|
|
|
|
</template>
|
|
|
|
<script lang="ts">
|
2021-09-22 01:19:35 +08:00
|
|
|
import { defineComponent, computed, ref, onMounted } from 'vue'
|
|
|
|
import { useEventListener, useTimeoutFn } from '@vueuse/core'
|
2021-01-31 18:43:33 +08:00
|
|
|
import { EVENT_CODE } from '@element-plus/utils/aria'
|
2021-10-27 23:17:13 +08:00
|
|
|
import { ElIcon } from '@element-plus/components/icon'
|
|
|
|
import { TypeComponents, TypeComponentsMap } from '@element-plus/utils/icon'
|
2021-09-22 01:19:35 +08:00
|
|
|
import { notificationProps, notificationEmits } from './notification'
|
2021-01-31 18:43:33 +08:00
|
|
|
|
2021-09-22 01:19:35 +08:00
|
|
|
import type { CSSProperties } from 'vue'
|
2020-08-04 19:03:20 +08:00
|
|
|
|
|
|
|
export default defineComponent({
|
|
|
|
name: 'ElNotification',
|
2021-09-22 01:19:35 +08:00
|
|
|
|
2021-10-27 23:17:13 +08:00
|
|
|
components: {
|
|
|
|
ElIcon,
|
|
|
|
...TypeComponents,
|
|
|
|
},
|
|
|
|
|
2021-09-22 01:19:35 +08:00
|
|
|
props: notificationProps,
|
|
|
|
emits: notificationEmits,
|
2021-01-31 18:43:33 +08:00
|
|
|
|
2020-08-04 19:03:20 +08:00
|
|
|
setup(props) {
|
2021-01-31 18:43:33 +08:00
|
|
|
const visible = ref(false)
|
2021-09-22 01:19:35 +08:00
|
|
|
let timer: (() => void) | undefined = undefined
|
2020-08-04 19:03:20 +08:00
|
|
|
|
2021-10-27 23:17:13 +08:00
|
|
|
const typeClass = computed(() => {
|
|
|
|
const type = props.type
|
|
|
|
return type && TypeComponentsMap[props.type]
|
|
|
|
? `el-notification--${type}`
|
|
|
|
: ''
|
|
|
|
})
|
|
|
|
|
|
|
|
const iconComponent = computed(() => {
|
|
|
|
return TypeComponentsMap[props.type] || props.icon || ''
|
|
|
|
})
|
2020-08-04 19:03:20 +08:00
|
|
|
|
2021-09-22 01:19:35 +08:00
|
|
|
const horizontalClass = computed(() =>
|
|
|
|
props.position.endsWith('right') ? 'right' : 'left'
|
|
|
|
)
|
2020-08-04 19:03:20 +08:00
|
|
|
|
2021-09-22 01:19:35 +08:00
|
|
|
const verticalProperty = computed(() =>
|
|
|
|
props.position.startsWith('top') ? 'top' : 'bottom'
|
|
|
|
)
|
2020-08-04 19:03:20 +08:00
|
|
|
|
2021-09-22 01:19:35 +08:00
|
|
|
const positionStyle = computed<CSSProperties>(() => {
|
2020-08-06 00:09:09 +08:00
|
|
|
return {
|
|
|
|
[verticalProperty.value]: `${props.offset}px`,
|
2021-09-22 01:19:35 +08:00
|
|
|
zIndex: props.zIndex,
|
|
|
|
}
|
2020-08-04 19:03:20 +08:00
|
|
|
})
|
|
|
|
|
2021-01-31 18:43:33 +08:00
|
|
|
function startTimer() {
|
|
|
|
if (props.duration > 0) {
|
2021-09-22 01:19:35 +08:00
|
|
|
;({ stop: timer } = useTimeoutFn(() => {
|
|
|
|
if (visible.value) close()
|
|
|
|
}, props.duration))
|
2021-01-31 18:43:33 +08:00
|
|
|
}
|
|
|
|
}
|
2020-08-04 19:03:20 +08:00
|
|
|
|
2021-01-31 18:43:33 +08:00
|
|
|
function clearTimer() {
|
2021-09-22 01:19:35 +08:00
|
|
|
timer?.()
|
2020-08-06 00:09:09 +08:00
|
|
|
}
|
2021-01-31 18:43:33 +08:00
|
|
|
|
|
|
|
function close() {
|
|
|
|
visible.value = false
|
2020-08-04 19:03:20 +08:00
|
|
|
}
|
2021-01-31 18:43:33 +08:00
|
|
|
|
|
|
|
function onKeydown({ code }: KeyboardEvent) {
|
2020-09-22 21:01:10 +08:00
|
|
|
if (code === EVENT_CODE.delete || code === EVENT_CODE.backspace) {
|
2021-01-31 18:43:33 +08:00
|
|
|
clearTimer() // press delete/backspace clear timer
|
2020-09-22 21:01:10 +08:00
|
|
|
} else if (code === EVENT_CODE.esc) {
|
2020-08-04 19:03:20 +08:00
|
|
|
// press esc to close the notification
|
2021-01-31 18:43:33 +08:00
|
|
|
if (visible.value) {
|
|
|
|
close()
|
2020-08-04 19:03:20 +08:00
|
|
|
}
|
|
|
|
} else {
|
2021-01-31 18:43:33 +08:00
|
|
|
startTimer() // resume timer
|
2020-08-04 19:03:20 +08:00
|
|
|
}
|
2021-01-31 18:43:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// lifecycle
|
|
|
|
onMounted(() => {
|
|
|
|
startTimer()
|
|
|
|
visible.value = true
|
|
|
|
})
|
|
|
|
|
2021-09-22 01:19:35 +08:00
|
|
|
useEventListener(document, 'keydown', onKeydown)
|
2021-01-31 18:43:33 +08:00
|
|
|
|
|
|
|
return {
|
|
|
|
horizontalClass,
|
|
|
|
typeClass,
|
2021-10-27 23:17:13 +08:00
|
|
|
iconComponent,
|
2021-01-31 18:43:33 +08:00
|
|
|
positionStyle,
|
|
|
|
visible,
|
|
|
|
|
|
|
|
close,
|
|
|
|
clearTimer,
|
|
|
|
startTimer,
|
|
|
|
}
|
2020-08-04 19:03:20 +08:00
|
|
|
},
|
|
|
|
})
|
|
|
|
</script>
|