Vue3全局提示(Message) Vue2全局提示Message可自定义设置以下属性提示内容content类型string默认 undefined自动关闭的延时duration类型number单位 ms设置 null 时不自动关闭默认 3000消息距离顶部的位置top类型string | number单位 px默认 30调用一次只展示一个提示调用多次则依次展示多个按照调用先后顺序依次自动关闭。效果如下图open()调用info()调用success()调用error()调用warning()调用loading()调用在线预览①创建全局提示组件Message其中引入使用了以下工具函数使用requestAnimationFrame模拟实现setTimeout和setInterval获取依赖注入 useInjectscript setup langts import { ref, computed, watch, onBeforeUnmount } from vue import type { CSSProperties, VNode } from vue import { rafTimeout, cancelRaf, useInject } from components/utils export interface Props { content?: string // 提示内容 duration?: number // 自动关闭的延时单位 ms设置 null 时不自动关闭 top?: string | number // 消息距离顶部的位置单位 px } const props withDefaults(definePropsProps(), { content: undefined, duration: 3000, top: 30 }) export interface Message { content?: string // 提示内容 icon?: VNode // 自定义图标 duration?: number | null // 自动关闭的延时时长单位 ms设置 null 时不自动关闭 top?: string | number // 消息距离顶部的位置单位 px class?: string // 自定义类名 style?: CSSProperties // 自定义样式 onClick?: Function // 点击 message 时的回调函数 onClose?: Function // 关闭时的回调函数 [propName: string]: any // 用于包含带有任意数量的其他属性 } const resetTimer ref() const showMessage refboolean[]([]) const hideTimers refany[]([]) const messageContent refMessage[]([]) const closeDuration refnumber | null(null) // 自动关闭延时 const messageTop refstring() // message 距离顶部的位置 const { colorPalettes } useInject(Message) // 主题色注入 const emits defineEmits([click, close]) // 所有提示是否已经全部变为 false const clear computed(() { return showMessage.value.every((show: boolean) !show) }) watch(clear, (to, from) { // 所有提示都消失后重置 if (!from to) { resetTimer.value rafTimeout(() { messageContent.value [] showMessage.value [] }, 300) } }) onBeforeUnmount(() { hideTimers.value.forEach((rafId: any) { rafId cancelRaf(rafId) }) }) function onEnter(index: number): void { hideTimers.value[index] cancelRaf(hideTimers.value[index]) } function onLeave(index: number): void { hideMessage(index) } function onClick(e: Event, index: number): void { messageContent.value[index].onClick messageContent.value[index].onClick() emits(click, e) } function hideMessage(index: number): void { if (closeDuration.value ! null) { hideTimers.value[index] rafTimeout(() { showMessage.value[index] false hideTimers.value[index] null messageContent.value[index].onClose messageContent.value[index].onClose() emits(close) }, closeDuration.value) } } function show(): void { resetTimer.value cancelRaf(resetTimer.value) const index messageContent.value.length - 1 const last messageContent.value[index] if (last.top ! undefined) { messageTop.value typeof last.top number ? ${last.top}px : last.top } else { messageTop.value typeof props.top number ? ${props.top}px : props.top } showMessage.value[index] true if (last.duration ! null) { closeDuration.value last.duration || props.duration hideMessage(index) } else { closeDuration.value null } } function open(message: string | Message): void { if (typeof message string) { messageContent.value.push({ content: message, mode: open }) } else { messageContent.value.push({ ...message, mode: open }) } show() } function info(message: string | Message): void { if (typeof message string) { messageContent.value.push({ content: message, mode: info }) } else { messageContent.value.push({ ...message, mode: info }) } show() } function success(message: string | Message): void { if (typeof message string) { messageContent.value.push({ content: message, mode: success }) } else { messageContent.value.push({ ...message, mode: success }) } show() } function error(message: string | Message): void { if (typeof message string) { messageContent.value.push({ content: message, mode: error }) } else { messageContent.value.push({ ...message, mode: error }) } show() } function warning(message: string | Message): void { if (typeof message string) { messageContent.value.push({ content: message, mode: warning }) } else { messageContent.value.push({ ...message, mode: warning }) } show() } function loading(message: string | Message): void { if (typeof message string) { messageContent.value.push({ content: message, mode: loading }) } else { messageContent.value.push({ ...message, mode: loading }) } show() } defineExpose({ open, info, success, error, warning, loading }) /script template div classmessage-wrap :style top: ${messageTop}; --message-primary-color: ${colorPalettes[5]}; --message-success-color: #52c41a; --message-warning-color: #faad14; --message-error-color: #ff4d4f; TransitionGroup nameslide-fade div v-showshowMessage[index] classmessage-container :classmessage.class :stylemessage.style v-for(message, index) in messageContent :keyindex div classmessage-content-wrap :classicon-${message.mode} mouseenteronEnter(index) mouseleaveonLeave(index) clickonClick($event, index) component v-ifmessage.icon :ismessage.icon classicon-svg / svg v-else-ifmessage.mode info classicon-svg focusablefalse >script setup langts import Message from ./Message.vue import { ref, h } from vue import { SoundFilled, FireFilled } from ant-design/icons-vue const message ref() const customMessage ref() function onOpen(content: string) { message.value.open(content) // open 调用 } function onInfo(content: string) { message.value.info(content) // info 调用 } function onSuccess(content: string) { message.value.success(content) // success 调用 } function onError(content: string) { message.value.error(content) // error 调用 } function onWarning(content: string) { message.value.warning(content) // warning 调用 } function onLoading(content: string) { message.value.loading(content) // loading 调用 } function onInfoCustom(content: string) { // info 调用, 并自定义图标 message.value.info({ content, icon: h(SoundFilled) }) } function onOpenCustom(content: string) { // open 调用, 并自定义图标 message.value.open({ content, icon: h(FireFilled, { style: color: gold }) }) } function onClassCustom(content: string) { message.value.info({ content, icon: h(SoundFilled), class: custom-class }) } function onStyleCustom(content: string) { customMessage.value.warning({ content, icon: h(FireFilled), top: 30vh, style: { color: #f50 } }) } function onCustomClose() { message.value.info({ content: The message will automatically turn off after 3 seconds., duration: 3000, onClose: () { console.log(custom message closed) } }) } function onNeverAutoClose() { message.value.info({ content: This message will not automatically turn off., duration: null, onClick: () { console.log(custom message clicked) } }) } function onClick(e: Event) { console.log(click, e) } function onClose() { console.log(close) } /script template div h1{{ $route.name }} {{ $route.meta.title }}/h1 h2 classmt30 mb10基本使用/h2 Button typeprimary clickonOpen(This is a noraml message)Open/Button h2 classmt30 mb10不同类型的全局提示/h2 Space Button typeprimary clickonInfo(This is an info message)Info/Button Button typeprimary clickonSuccess(This is a success message)Success/Button Button typeprimary clickonError(This is an error message)Error/Button Button typeprimary clickonWarning(This is a warning message)Warning/Button Button typeprimary clickonLoading(This is a loading message)Loading/Button /Space h2 classmt30 mb10自定义图标/h2 Space Button typeprimary clickonInfoCustom(This is a custom icon message)Custom Info Icon/Button Button typeprimary clickonOpenCustom(This is a custom icon message)Custom Icon/Button /Space h2 classmt30 mb10自定义样式/h2 Space Button typeprimary clickonClassCustom(This is a custom class message)Custom Class/Button Button typeprimary clickonStyleCustom(This is a custom style message)Custom Style/Button /Space h2 classmt30 mb10自定义关闭延时/h2 Space Button typeprimary clickonCustomCloseCustom Close/Button Button typeprimary clickonNeverAutoCloseNever Auto Close/Button /Space Message refmessage clickonClick closeonClose / Message refcustomMessage clickonClick closeonClose / /div /template style langless scoped :deep(.custom-class) { color: #ff6900; } /style

相关新闻

最新新闻

AI资本开支高企下的算力集群工程实践:从GPU到万卡集群的关键问题

AI资本开支高企下的算力集群工程实践:从GPU到万卡集群的关键问题

在行业讨论里,2026年AI资本开支达到7650亿美元、首次超过油气行业资本开支,属于一个经常被引用的预测口径。这个数字来自市场预测机构,不同团队的统计范围和时间定义并不一致,是否完全精准还要看后续实际投入。但其中反映的趋势已…

2026/8/29 13:26:46
C++ sort函数多级排序实战:从德才论到自定义比较函数深度解析

C++ sort函数多级排序实战:从德才论到自定义比较函数深度解析

1. 项目概述:当排序遇上“德才论” 最近在带几个学弟学妹过PTA乙级的题目,发现1015“德才论”这道题,几乎成了所有人在学习C标准库 sort 函数时的一道“分水岭”。题目本身源自一个古老的选才思想,但它的实现却精准地卡在了 so…

2026/8/29 13:26:46
网易数据挖掘实习生笔试考点复盘:从概率统计到SQL与特征工程

网易数据挖掘实习生笔试考点复盘:从概率统计到SQL与特征工程

1. 先说结论:网易数据挖掘实习生笔试到底在考什么 我当年投网易数据挖掘实习生岗位的时候,犯过一个特别蠢的错误:以为笔试会像期末考试一样,按《数据挖掘导论》的章节顺序出题。结果打开试卷半小时就懵了——题不难,但…

2026/8/29 13:26:46
数学建模竞赛获奖名单深度解析:从逆向工程到实战备赛策略

数学建模竞赛获奖名单深度解析:从逆向工程到实战备赛策略

1. 项目概述:从一份获奖名单到竞赛策略的全景解析 看到“2020年东三省数学建模联赛(辽宁赛区)获奖名单”这个标题,很多初次接触数学建模的同学可能会觉得这只是一份简单的公示文件,看一眼就过去了。但作为一名带过好几…

2026/8/29 13:26:46
Keil uVision2 C51实战指南:从工程搭建到调试技巧

Keil uVision2 C51实战指南:从工程搭建到调试技巧

简介:嵌入式开发中,单片机是硬件控制的核心载体,而C语言则是驱动这些芯片的主要工具。无论8051还是ARM内核,开发者都需要依靠编译器将高级语言翻译成机器可执行的指令,这一过程涉及工程管理、内存分配、代码优化等多个…

2026/8/29 13:26:46
微博情感分析实战:SVM模型在小样本高噪声场景下的工程落地

微博情感分析实战:SVM模型在小样本高噪声场景下的工程落地

简介:情感分析是自然语言处理的基础任务,其核心在于从非结构化文本中识别用户主观态度。在中文社交媒体场景下,微博评论具有短文本、高噪声、语义漂移快等特点,导致通用预训练模型(如BERT)在小样本、实时性…

2026/8/29 13:21:45