1. 为什么需要封装uniapp的message功能在uniapp开发中我们经常需要使用消息提示功能比如操作成功提示、错误警告、表单验证提示等。uniapp本身提供了uni.showToast等基础API但在实际项目开发中直接使用原生API会遇到几个典型问题样式不统一不同页面调用的消息提示样式可能不一致代码冗余每次调用都要重复设置duration、icon等参数维护困难当需要修改消息提示的全局样式或行为时需要修改多处代码功能局限原生API无法满足一些高级需求如队列显示、自定义动画等我在最近的一个跨平台电商项目中就遇到了这些问题。项目需要同时在微信小程序、H5和App端运行但各平台的消息提示表现不一致小程序默认有图标而H5没有App端的显示位置也不尽相同。这导致用户体验不一致产品经理提出了统一提示样式的要求。2. 基础消息封装实现2.1 创建message工具类首先在项目的common目录下新建message.js文件// common/message.js const DEFAULT_DURATION 2000 // 默认显示时长 export default { success(msg, duration DEFAULT_DURATION) { uni.showToast({ title: msg, duration, icon: success }) }, error(msg, duration DEFAULT_DURATION) { uni.showToast({ title: msg, duration, image: /static/images/error.png // 自定义错误图标 }) }, warning(msg, duration DEFAULT_DURATION) { uni.showToast({ title: msg, duration, image: /static/images/warning.png }) }, info(msg, duration DEFAULT_DURATION) { uni.showToast({ title: msg, duration, icon: none }) } }2.2 全局挂载在main.js中全局挂载// main.js import message from ./common/message.js Vue.prototype.$message message2.3 基本使用在页面中调用// 成功提示 this.$message.success(订单创建成功) // 错误提示 this.$message.error(网络请求失败) // 普通信息 this.$message.info(请输入有效手机号)3. 高级封装技巧3.1 支持Vue3组合式API对于使用Vue3的项目我们可以提供组合式API的支持// common/message.js import { getCurrentInstance } from vue export function useMessage() { const app getCurrentInstance() return app.appContext.config.globalProperties.$message } // 在组件中使用 import { useMessage } from /common/message.js export default { setup() { const message useMessage() const handleSubmit () { message.success(提交成功) } return { handleSubmit } } }3.2 消息队列处理原生API连续调用时会相互覆盖我们可以实现消息队列let messageQueue [] let isShowing false function showNext() { if (messageQueue.length 0 || isShowing) return isShowing true const { type, msg, duration } messageQueue.shift() uni.showToast({ title: msg, duration, icon: type success ? success : none, complete: () { isShowing false setTimeout(showNext, 300) // 消息间隔 } }) } export default { show(type, msg, duration 2000) { messageQueue.push({ type, msg, duration }) showNext() } }3.3 多平台适配针对不同平台做差异化处理function getPlatformConfig() { // 可根据不同平台返回不同配置 return { position: uni.$platform h5 ? top : center, duration: uni.$platform app ? 2500 : 2000 } } export default { success(msg, duration) { const config getPlatformConfig() uni.showToast({ title: msg, duration: duration || config.duration, position: config.position, icon: success }) } }4. 样式自定义与主题集成4.1 自定义消息样式在App.vue中定义全局样式/* App.vue */ /* 小程序需要写在全局样式文件中 */ .uni-toast { border-radius: 8px !important; padding: 16px 24px !important; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important; } .uni-toast__content { font-size: 15px !important; line-height: 1.5 !important; }4.2 与UI主题集成结合项目主题色系统export default { success(msg, duration) { const theme require(/theme.js).default uni.showToast({ title: msg, duration, icon: none, mask: true, success: () { // 动态修改样式 uni.$emit(toast-show, { type: success, backgroundColor: theme.colors.success }) } }) } }5. 性能优化与异常处理5.1 防止重复点击let lastClickTime 0 export default { success(msg) { const now Date.now() if (now - lastClickTime 1000) return lastClickTime now uni.showToast({ title: msg, icon: success }) } }5.2 异常边界处理export default { show(options) { try { if (!options.title) { console.warn(Message title is required) return } if (options.duration 10000) { options.duration 10000 } uni.showToast(options) } catch (e) { console.error(Message show error:, e) // 降级处理 uni.showModal({ content: options.title, showCancel: false }) } } }6. 单元测试方案为消息组件编写单元测试// tests/unit/message.spec.js import message from /common/message.js describe(Message, () { beforeEach(() { jest.spyOn(uni, showToast).mockImplementation(jest.fn()) }) it(should call showToast with success config, () { message.success(test) expect(uni.showToast).toBeCalledWith({ title: test, duration: 2000, icon: success }) }) it(should use custom duration, () { message.error(error, 3000) expect(uni.showToast).toBeCalledWith({ title: error, duration: 3000, image: expect.stringContaining(error.png) }) }) })7. 实际项目中的应用案例在我负责的跨境电商项目中我们对消息系统做了深度定制多语言支持export default { success(key, duration) { const msg this.$t(messages.${key}) uni.showToast({ title: msg, duration, icon: success }) } } // 使用 this.$message.success(order.create_success)结合业务状态的智能提示export default { showByStatus(status) { const map { 200: { type: success, msg: 操作成功 }, 401: { type: error, msg: 请重新登录 }, 500: { type: error, msg: 服务器错误 } } const config map[status] || { type: info, msg: 未知状态 } this[config.type](config.msg) } }带交互的消息提示export default { confirm(msg) { return new Promise((resolve) { uni.showToast({ title: msg, icon: none, duration: 3000, position: center, mask: true, success: () { setTimeout(() { uni.showModal({ content: msg, success: (res) { resolve(res.confirm) } }) }, 1000) } }) }) } }8. 封装建议与最佳实践根据多个项目的实践经验我总结出以下建议分层设计基础层处理平台差异和基本显示业务层与业务状态码、多语言等结合交互层处理复杂交互场景性能考量避免频繁触发消息导致页面卡顿大文本消息做截断处理在页面onHide时自动清除未显示的消息可扩展性预留自定义插槽接口支持主题色动态切换允许覆盖默认图标和样式调试支持在开发环境输出详细日志提供消息历史记录功能支持消息触发源追踪跨平台一致性统一各平台显示时长处理iOS和Android的显示差异针对H5做移动端和PC端的适配通过这样全面的封装我们的消息系统在多个项目中都表现稳定大大提升了开发效率和用户体验一致性。特别是在复杂的后台管理系统和电商应用中良好的消息反馈机制显著降低了用户操作错误率。
阅读完成 · 觉得有帮助?