Element Plus Notification 通知组件完全指南:全局调用、类型体系与源码级原理剖析
【免费下载链接】element-plus🎉 A Vue.js 3 UI Library made by Element team项目地址: https://gitcode.com/GitHub_Trending/el/element-plus
Notification 是 Element Plus 提供的一款全局消息通知组件,用于在页面四角弹出轻量级的提示卡片,适合承载操作结果、系统消息等非阻塞性反馈。本文以 notification.md 官方文档为主线,结合 notification 组件源码 与官方示例,系统讲解其调用方式、全部配置项、版本演进能力(如 VNode 消息、倒计时进度条、hover 暂停等),并深入到实例队列管理、定时器与 zIndex 分配的底层实现,帮助你从"会调用"进阶到"知其所以然"。
基础用法:第一个 Notification
Element Plus 已将$notify方法注册到app.config.globalProperties,因此在任意 Vue 组件内部可以直接通过this.$notify调用;在<script setup>组合式 API 中,更推荐按需导入ElNotification后直接调用函数式 API。
最简单的场景只需提供title(标题)和message(正文)两个字段:
import { ElNotification } from 'element-plus' ElNotification({ title: 'Title', message: 'This is a reminder', })参考官方示例 notification/basic.vue,其默认行为是在 4500ms 后自动关闭,你可以在创建时传入h('i', ...)渲染的 VNode 作为消息体:
import { h } from 'vue' import { ElNotification } from 'element-plus' const open1 = () => { ElNotification({ title: 'Title', message: h('i', { style: 'color: teal' }, 'This is a reminder'), }) }若希望通知永不自动关闭,将duration设置为0即可:
const open2 = () => { ElNotification({ title: 'Prompt', message: 'This is a message that does not automatically close', duration: 0, }) }注意:
duration接收的是毫秒单位的 Number。
在源码层面,notification.ts 中duration的默认值即为4500,而 notification.vue 的startTimer()会先判断props.duration <= 0并直接返回——这正是duration: 0不自动关闭的实现依据。
五种通知类型:primary / success / warning / info / error
Notification 通过type字段指定语义类型,组件会据此渲染对应的图标与状态色。官方文档明确列出四种基础类型,而primary类型在 ^(2.9.11) 版本中新增,因此当前共有五种:
| type | 语义 | 说明 |
|---|---|---|
primary | 主色 | ^(2.9.11) 新增,无状态色 |
success | 成功 | 绿色、对勾图标 |
warning | 警告 | 橙色、感叹号图标 |
info | 信息 | 蓝色、信息图标 |
error | 错误 | 红色、叉号图标 |
除了在ElNotification({ type: 'success' })中显式传参,Element Plus 还为每种类型注册了独立方法,可以直接调用而无需传入type:
ElNotification.success({ title: 'Success', message: 'This is a success message' }) ElNotification.warning({ title: 'Warning', message: 'This is a warning message' }) ElNotification.info({ title: 'Info', message: 'This is an info message' }) ElNotification.error({ title: 'Error', message: 'This is an error message' }) ElNotification.primary({ title: 'Primary', message: 'This is a primary message' })完整示例见 notification/different-types.vue。
源码佐证:在 notification.ts 中,类型数组被定义为['primary', 'success', 'info', 'warning', 'error'];而 notify.ts 遍历该数组,为notify函数动态挂载了notify[type]方法,内部实现等价于notify({ ...options, type })。同时,notification.vue 中的iconComponent计算属性遵循"有type用类型图标,否则回退到自定义icon"的优先级规则,印证了文档中"icon会被type覆盖"的说明。
自定义弹出位置:四个角落任选
Notification 可以从页面四个角落中的任意一个滑入,通过position字段控制,可选值为top-right、top-left、bottom-right、bottom-left,默认值为top-right。
ElNotification({ title: 'Custom Position', message: "I'm at the bottom right corner", position: 'bottom-right', })参考官方示例 notification/positioning.vue,其中依次演示了右上(默认)、右下、左下、左上四种定位。
从源码看,位置不仅决定视觉坐标,还决定了实例队列的归属。notify.ts 内部维护了一个以四个位置为键的队列对象:
const notifications: Record<NotificationPosition, NotificationQueue> = { 'top-left': [], 'top-right': [], 'bottom-left': [], 'bottom-right': [], }同位置的多个实例会按顺序纵向堆叠,彼此之间保持固定的 16px 间距(GAP_SIZE,见 notify.ts)。
调整屏幕边缘偏移:offset
通过offset属性可以控制 Notification 距屏幕边缘的偏移量。文档特别强调:同一时刻的每一个 Notification 实例应使用相同的 offset,否则会出现视觉错乱。
ElNotification.success({ title: 'Success', message: 'This is a success message', offset: 100, })示例见 notification/offsetting.vue。
这里有必要解释offset的真实语义:notify.ts 在创建实例时,并非直接使用用户传入的offset,而是把它作为基础偏移,再叠加同位置队列中所有已存在实例的高度与间距,从而得到每个实例实际的纵向位置:
let verticalOffset = options.offset || 0 notifications[position].forEach(({ vm }) => { verticalOffset += (vm.el?.offsetHeight || 0) + GAP_SIZE }) verticalOffset += GAP_SIZE因此offset更像"第一个实例距屏幕边缘的距离",后续实例会自动向下(或向上)排开,无需手动计算。
使用 HTML 字符串与 XSS 安全警告
message默认按纯文本渲染,若需渲染富文本,可将dangerouslyUseHTMLString设为true:
ElNotification({ title: 'HTML String', dangerouslyUseHTMLString: true, message: '<strong>This is <i>HTML</i> string</strong>', })示例见 notification/raw-html.vue。
必须重视的安全警告:动态渲染任意 HTML 极易导致 XSS(跨站脚本)攻击。因此开启dangerouslyUseHTMLString后,请务必确保message内容可信,绝不要将用户输入直接作为message赋值。
该行为的实现位于 notification.vue:组件通过v-if="!dangerouslyUseHTMLString"走插值渲染,否则走v-html="message",源码注释中也明确标注了"never use user's input as message"。
消息即函数:VNode 与动态渲染 ^(2.9.0)
从 ^(2.9.0) 版本起,message除了支持字符串和 VNode 之外,还支持返回 VNode 的函数。函数形式的最大价值在于:当 VNode 中包含响应式动态属性时,只有函数形式才能保证内容跟随状态更新。
普通 VNode 写法:
import { h } from 'vue' ElNotification({ title: 'Use Vnode', message: h('p', null, [ h('span', null, 'Message can be '), h('i', { style: 'color: teal' }, 'VNode'), ]), })包含动态 props(如开关组件)时必须使用函数形式:
import { h, ref } from 'vue' import { ElNotification, ElSwitch } from 'element-plus' const open1 = () => { const checked = ref<boolean | string | number>(false) ElNotification({ title: 'Use Vnode', // Should pass a function if VNode contains dynamic props message: () => h(ElSwitch, { modelValue: checked.value, 'onUpdate:modelValue': (val: boolean | string | number) => { checked.value = val }, }), }) }完整示例见 notification/use-vnode.vue。其底层逻辑在 notify.ts:createVNode时会判断message是函数则直接作为插槽函数、是 VNode 则包一层箭头函数,从而把任意形式的message统一为可渲染的插槽内容。这也解释了为什么函数形式能保留动态响应能力——它本质上是作为作用域插槽被渲染的。
倒计时进度条与悬停暂停 ^(2.14.4)
从 ^(2.14.4) 起,Notification 支持显示一条与自动关闭计时同步的进度条,直观展示剩余展示时间。
- 传入
progress: true显示默认进度条,其颜色跟随type的状态色; - 传入对象可深度定制进度条,支持 Progress 组件 的全部选项(如
color),但percentage、type、duration、indeterminate、width五个字段被排除——因为该进度条永远由倒计时驱动,percentage会自动计算; - 当
pauseOnHover为true(默认值)时,鼠标悬停在通知上会同时暂停计时器与进度条。
ElNotification({ title: 'Default progress', message: 'Hover to pause the timer and progress bar', duration: 6000, progress: true, }) ElNotification({ title: 'Custom color', message: 'Custom progress bar color overrides the default', duration: 6000, progress: { color: [ { color: '#f56c6c', percentage: 20 }, { color: '#e6a23c', percentage: 40 }, { color: '#5cb87a', percentage: 60 }, { color: '#1989fa', percentage: 80 }, { color: '#6f7ad3', percentage: 100 }, ], }, }) // 悬停不暂停 ElNotification({ title: 'No pause on hover', message: 'Timer and progress bar keep running even when hovering', duration: 6000, progress: true, pauseOnHover: false, })示例见 notification/progress-bar.vue。
源码层面的实现非常精巧,值得展开:
- notification.ts 中
NotificationProgress类型通过Omit<Partial<ProgressProps>, 'percentage' | 'type' | 'duration' | 'indeterminate' | 'width'>显式排除上述字段,与文档说明完全一致; - notification.vue 使用
useIntervalFn以 100ms 为间隔更新percentage,计算公式为100 - ((elapsed + Date.now() - startedAt) / duration) * 100,即从 100 线性递减到 0; - 悬停暂停通过
onMouseEnter/onMouseLeave配合clearTimer()/startTimer()实现(见 notification.vue),且clearTimer()会累计已流逝时间elapsed,恢复时用remaining = duration - elapsed重新计时并让进度条从当前位置继续,而不是粗暴归零; - 键盘交互同样周到:按下
Esc关闭当前通知,按下Delete/Backspace则仅暂停计时(见 notification.vue)。
隐藏关闭按钮:showClose
默认情况下 Notification 右上角有关闭按钮,将其设为false后用户将无法手动关闭(只能等待自动关闭或通过代码调用close):
ElNotification({ title: 'Title', message: 'This is a message', showClose: false, })对应示例见 notification/no-close.vue。组件模板中关闭按钮通过v-if="showClose"条件渲染(notification.vue),并使用了.stop修饰符阻止点击事件冒泡到通知卡片本身。
全局方法与局部引入
全局方法 $notify
Element Plus 将$notify注册到了app.config.globalProperties,因此任何 Vue 实例内部都可以直接调用:
this.$notify({ title: 'Title', message: 'This is a message', })局部引入
在按需引入的场景下,推荐从element-plus显式导入ElNotification:
import { ElNotification } from 'element-plus' import { CloseBold } from '@element-plus/icons-vue' ElNotification({ title: 'Title', message: 'This is a message', closeIcon: CloseBold, })同样支持类型化方法ElNotification.success(options)(以及primary、warning、info、error)。此外还提供两个批量控制方法:
ElNotification.closeAll():手动关闭当前所有通知实例。源码实现见 notify.ts,它遍历四个方向的队列并逐一调用实例暴露的close();ElNotification.updateOffsets(position)(^(2.10.5) 新增):手动更新指定方向下所有实例的偏移量。源码见 notify.ts,它会以队列中首个实例的偏移为基准,重新按"高度 + 16px 间距"依次排布后续实例。
App 上下文继承
Notification 的构造函数接受第二个参数context,用于注入当前应用的上下文(app context),从而使通知内的组件可以继承当前应用的全部属性(如全局组件、provide/inject 数据等)。
import { getCurrentInstance } from 'vue' import { ElNotification } from 'element-plus' // in your setup method const { appContext } = getCurrentInstance()! ElNotification({}, appContext)两点补充说明:
- 若你通过
app.use(ElementPlus)全局注册了ElNotification,它会自动继承应用上下文,无需手动传参; - 源码中 notify.ts 通过
vm.appContext = isUndefined(context) ? notify._context : context完成注入,而notify._context正是全局注册时被赋值的应用上下文(notify.ts)。
API 参考:Options 完整配置表
下表为ElNotification(options)支持的全部配置项,字段、类型与默认值均与官方文档一致,并结合源码补充了版本与取值说明。
| 名称 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| title | 标题 | string | '' |
| message | 正文内容 | string/VNode/() => VNode(函数形式 ^(2.9.0)) | '' |
| dangerouslyUseHTMLString | 是否将message作为 HTML 字符串渲染(开启需防范 XSS) | boolean | false |
| type | 通知类型:'primary'(^(2.9.11))|'success'|'warning'|'info'|'error'|'' | enum | '' |
| icon | 自定义图标组件(会被type覆盖) | string/Component | — |
| customClass | 自定义类名 | string | '' |
| duration | 自动关闭前的时长(毫秒);设为0则不自动关闭 | number | 4500 |
| position | 弹出位置:'top-right'|'top-left'|'bottom-right'|'bottom-left' | enum | top-right |
| showClose | 是否显示关闭按钮 | boolean | true |
| onClose | 关闭时的回调 | () => void | — |
| onClick | 点击通知时的回调 | () => void | — |
| offset | 距屏幕边缘的偏移(同刻所有实例应保持一致) | number | 0 |
| appendTo | 通知挂载的根元素,默认document.body | CSSSelector/HTMLElement | — |
| zIndex | 初始 zIndex | number | 0 |
| closeIcon ^(2.9.8) | 自定义关闭图标 | string/Component | Close |
| progress ^(2.14.4) | 自动关闭倒计时进度条:true显示默认条;传对象可定制(percentage、type、duration、indeterminate、width被排除) | boolean/object(Progress 选项) | false |
| pauseOnHover ^(2.14.4) | 悬停时是否暂停计时 | boolean | true |
源码佐证:notification.ts 中的notificationProps完整定义了上述字段,其中position与type通过values做了枚举约束,closeIcon默认值为Close图标(源自@element-plus/icons-vue),progress使用definePropType([Boolean, Object])同时接受布尔与对象两种形态。
API 参考:实例方法
ElNotification(...)与this.$notify(...)都会返回当前 Notification 的实例句柄,可在任意时刻手动关闭:
| 名称 | 说明 | 类型 |
|---|---|---|
| close | 关闭该条 Notification | () => void |
const notification = ElNotification({ title: 'Title', message: '...' }) // 手动关闭 notification.close()该方法的内部实现值得留意:返回句柄的close并非直接隐藏 DOM,而是调用组件实例exposed中暴露的close()(见 notify.ts)。组件内部的close()会先置visible = false触发离场过渡,再执行clearTimer()停止进度条与关闭计时器(notification.vue),确保完整的生命周期不会被跳过。
深入原理:实例队列、内存清理与 zIndex
实例队列与自动排布
如前所述,notify.ts 用四个方向的数组维护所有存活实例。关闭某条通知时,close()(notify.ts)会做三件事:
- 调用用户传入的
onClose回调; - 在
transition的before-leave阶段读取被移除实例的offsetHeight(此时 DOM 尚未卸载,可正常取高); - 将该实例从队列中
splice移除,并把其后方所有实例的偏移统一减去"被移除高度 + 16px 间距",实现后续通知平滑上移补位。
内存释放
每个通知创建时会生成一个独立的div容器,并通过render(vm, container)渲染(notify.ts)。组件在离场动画结束后触发destroy事件,对应onDestroy钩子执行render(null, container)卸载虚拟节点,防止内存泄漏。
层级管理
通知的zIndex默认并非固定的0:组件通过useGlobalComponentSettings获取全局 zIndex 管理器,在onMounted时调用nextZIndex()自增获取当前最高层级(notification.vue),确保新通知始终覆盖在旧通知之上;若显式传入zIndex则优先生效。
小结
Element Plus Notification 以"函数式调用 + 可配置化选项"为核心设计,从基础的标题/正文、四种语义类型,到定位偏移、VNode 消息、倒计时进度条、悬停暂停等进阶能力一应俱全。配合源码中精心设计的实例队列、过渡生命周期、zIndex 分配与内存清理机制,它在易用性与工程稳健性之间取得了很好的平衡。掌握本文所述的选项语义与底层行为,你便能在项目中正确、安全、优雅地使用通知能力。
如需继续了解与 Notification 同族的轻提示组件,可查阅 Message 组件文档 与 MessageBox 组件文档 进行对比选型。
【免费下载链接】element-plus🎉 A Vue.js 3 UI Library made by Element team项目地址: https://gitcode.com/GitHub_Trending/el/element-plus
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考