锦书在线
80.52M · 2026-03-21
同学们好,我是 Eugene(尤金),一个拥有多年中后台开发经验的前端工程师~
(Eugene 发音很简单,/juːˈdʒiːn/,大家怎么顺口怎么叫就好)
你是否也有过:明明学过很多技术,一到关键时候却讲不出来、甚至写不出来?
你是否也曾怀疑自己,是不是太笨了,明明感觉会,却总差一口气?
就算想沉下心从头梳理,可工作那么忙,回家还要陪伴家人。
一天只有24小时,时间永远不够用,常常感到力不从心。
技术行业,本就是逆水行舟,不进则退。
如果你也有同样的困扰,别慌。
从现在开始,跟着我一起心态归零,利用碎片时间,来一次彻彻底底的基础扫盲。
这一次,我们一起慢慢来,扎扎实实变强。
不搞花里胡哨的理论堆砌,只分享看得懂、用得上的前端干货,
咱们一起稳步积累,真正摆脱“面向搜索引擎写代码”的尴尬。
很多同学会直接这样写:
// 散落在业务里的各种提示
this.$message.success('保存成功')
ElMessage.error('网络错误')
alert('操作失败') // 甚至还有人用 alert
看起来能用,但会带来这些问题:
Message,有的用 Notification,有的用 alerttry-catch 各自 message所以需要:把通知和消息系统统一封装,集中管理风格和错误处理。
⬆ 返回目录
| 类型 | 特点 | 典型场景 |
|---|---|---|
| Message | 轻量、短暂、通常居中或顶部,自动消失 | 操作结果反馈:保存成功、删除成功 |
| Notification | 带标题、正文,可带操作按钮,位置可配置 | 系统通知、任务完成、重要提示 |
| Toast | 和 Message 概念接近,有些库叫 Toast | 同上,多用于移动端 |
可以简单记:Message 偏轻量,Notification 偏正式、信息更多。封装时建议:
⬆ 返回目录
⬆ 返回目录
┌─────────────────────────────────────┐
│ 业务层:直接调用 msg.success() 等
├─────────────────────────────────────┤
│ 封装层:msg / notify 统一入口
│ - 统一风格
│ - 统一文案模板
│ - 统一埋点/日志
├─────────────────────────────────────┤
│ 底层:Element Plus / Ant Design 等
└─────────────────────────────────────┘
业务层只调用封装好的 API,不直接接触 UI 库。
⬆ 返回目录
⬆ 返回目录
// src/utils/message.config.js
/**
* Message 统一配置
* 所有地方用 Message 时都走这套配置,保证风格一致
*/
export const MESSAGE_CONFIG = {
duration: 2000, // 默认 2 秒消失
showClose: false, // 不显示关闭按钮,靠自动消失
center: true, // 水平居中
offset: 80, // 距离顶部的距离
grouping: true, // 相同内容合并显示,避免刷屏
}
/**
* 不同类型建议的 duration
* 成功可以短一点,错误要留足阅读时间
*/
export const DURATION_BY_TYPE = {
success: 2000,
warning: 3000,
error: 4000,
info: 2500,
}
⬆ 返回目录
⬆ 返回目录
// src/utils/errorCodeMap.js
/**
* 后端错误码 → 前端展示文案
* 避免把后端原始错误直接抛给用户
*/
export const ERROR_CODE_MAP = {
401: '登录已过期,请重新登录',
403: '没有权限执行此操作',
404: '请求的资源不存在',
500: '服务器异常,请稍后重试',
10001: '参数错误',
10002: '数据已存在',
// ... 按你们项目补充
}
/**
* 根据错误码获取友好提示
*/
export function getErrorMessage(code, defaultMsg = '操作失败,请稍后重试') {
return ERROR_CODE_MAP[code] || defaultMsg
}
⬆ 返回目录
// src/api/request.js 示意
import axios from 'axios'
import { ElMessage } from 'element-plus'
import { getErrorMessage } from '@/utils/errorCodeMap'
const request = axios.create({
baseURL: '/api',
timeout: 10000,
})
// 响应拦截器:统一错误处理
request.interceptors.response.use(
(response) => {
const { code, data, message } = response.data
// 假设业务成功是 code === 0
if (code !== 0) {
ElMessage.error(getErrorMessage(code, message))
return Promise.reject(new Error(message))
}
return data
},
(error) => {
if (error.response) {
const { status } = error.response
const msg = getErrorMessage(status)
ElMessage.error(msg)
// 401 可以在这里跳转登录
if (status === 401) {
// router.push('/login')
}
} else {
ElMessage.error('网络异常,请检查网络后重试')
}
return Promise.reject(error)
}
)
export default request
⬆ 返回目录
src/
├── utils/
│ ├── message.config.js # 配置
│ ├── errorCodeMap.js # 错误码映射
│ └── message.js # 封装入口
⬆ 返回目录
// src/utils/message.js
import { ElMessage, ElNotification } from 'element-plus'
import { MESSAGE_CONFIG, DURATION_BY_TYPE } from './message.config'
import { getErrorMessage } from './errorCodeMap'
/**
* 全局 Message 封装
* 统一风格、统一入口,方便以后替换 UI 库或加埋点
*/
function createMessage(type) {
return (content, duration) => {
ElMessage({
...MESSAGE_CONFIG,
type,
message: typeof content === 'string' ? content : content?.message || '操作成功',
duration: duration ?? DURATION_BY_TYPE[type] ?? MESSAGE_CONFIG.duration,
})
}
}
// 对外暴露的 API
export const msg = {
success: createMessage('success'),
warning: createMessage('warning'),
error: createMessage('error'),
info: createMessage('info'),
}
/**
* 全局 Notification 封装
* 适合需要标题、描述、操作按钮的场景
*/
export const notify = {
success(title, message, options = {}) {
ElNotification({
type: 'success',
title: title || '成功',
message: message || '',
duration: 4000,
position: 'top-right',
...options,
})
},
error(title, message, options = {}) {
ElNotification({
type: 'error',
title: title || '错误',
message: message || '',
duration: 5000,
position: 'top-right',
...options,
})
},
// warning、info 同理...
}
/**
* 统一错误提示入口
* 支持:错误码、Error 对象、字符串
*/
export function showError(error) {
let message = '操作失败,请稍后重试'
if (typeof error === 'number') {
message = getErrorMessage(error)
} else if (error?.message) {
message = error.message
} else if (typeof error === 'string') {
message = error
}
msg.error(message)
}
⬆ 返回目录
// 业务组件里
import { msg, notify, showError } from '@/utils/message'
// 简单成功反馈
msg.success('保存成功')
// 接口失败时(如果拦截器没处理,可以手动调)
try {
await saveData()
msg.success('保存成功')
} catch (e) {
showError(e)
}
// 重要通知
notify.success('导出完成', '您的报表已生成,请到下载中心查看')
⬆ 返回目录
// main.js
import { msg, notify, showError } from '@/utils/message'
app.config.globalProperties.$msg = msg
app.config.globalProperties.$notify = notify
app.config.globalProperties.$showError = showError
// 组件内:this.$msg.success('保存成功')
⬆ 返回目录
grouping,或在封装层做「相同文案节流」。⬆ 返回目录
⬆ 返回目录
message 或 Error 文本展示给用户。⬆ 返回目录
ElMessage、ElNotification。msg、notify,底层实现集中在 message.js,换库只改这一层。⬆ 返回目录
import { msg } from '@/utils/message' 直接引入,不依赖 this.$msg。⬆ 返回目录
| 规范 | 说明 |
|---|---|
| 统一入口 | 只用 msg / notify,不直接调用 UI 库 |
| 统一风格 | 通过 message.config.js 统一 duration、位置、样式 |
| 统一错误处理 | 用错误码映射 + axios 拦截器,业务少写 try-catch |
| 类型区分 | 简单反馈用 Message,复杂通知用 Notification |
| 文案友好 | 错误码转成用户能看懂的话,不暴露技术细节 |
| 可扩展 | 封装层预留埋点、日志、国际化等扩展点 |
⬆ 返回目录
封装全局 Message / Notification 的核心是:
msg / notify 走。⬆ 返回目录
学习本就是一场持久战,不需要急着一口吃成胖子。哪怕今天你只记住了一点点,这都是实打实的进步。
后续我还会继续用这种大白话、讲实战方式,带大家扫盲更多前端基础。
关注我,不迷路,咱们把那些曾经模糊的知识点,一个个彻底搞清楚。
如果你觉得这篇内容对你有帮助,不妨点赞+收藏,下次写代码卡壳时,拿出来翻一翻,比搜引擎更靠谱。
我是 Eugene,你的电子学友,我们下一篇干货见~