玩转Notification通知实现与优化的那些事儿

博主梓艺 组件 阅读 1,170
赞 19 收藏
二维码
手机扫码查看
反馈

项目背景和选型

最近做了一个电商后台管理系统,需求里要求有个全局的通知功能。说白了就是用户操作后给个反馈,比如“删除成功”“添加成功”这种提示。

玩转Notification通知实现与优化的那些事儿

本来想用Element Plus自带的Notification组件,但发现样式定制性太差,而且在多标签页场景下会有问题。最后决定自己封装一个轻量的通知组件,基于Vue 3和TypeScript实现。

踩坑:样式冲突和动画问题

开始写的时候挺顺利,用了个简单的绝对定位把通知框放在右上角。结果一上线就发现问题了:

  • 多个通知同时出现时会重叠
  • 动画效果生硬,关闭时直接消失了
  • 在不同分辨率下位置会偏移

折腾了半天才发现是CSS优先级和transform的问题。下面是调整后的核心代码:

// notification.ts
import { createApp, ref } from 'vue'
import NotificationComponent from './Notification.vue'

const notifications = ref([])

export function useNotification() {
  const add = (message: string, type: 'success' | 'error' = 'success') => {
    const id = Date.now()
    notifications.value.push({ id, message, type })

    // 自动移除
    setTimeout(() => {
      remove(id)
    }, 3000)
  }

  const remove = (id: number) => {
    const index = notifications.value.findIndex(n => n.id === id)
    if (index > -1) notifications.value.splice(index, 1)
  }

  return { notifications, add, remove }
}

export function createNotification() {
  const mountPoint = document.createElement('div')
  document.body.appendChild(mountPoint)

  const app = createApp(NotificationComponent, {
    notifications: useNotification().notifications
  })
  app.mount(mountPoint)
}

最大的挑战:多实例管理

当系统同时触发多个通知时,事情变得复杂了。最开始我简单地用一个数组存通知,结果发现:

  • 快速连续触发会导致通知闪烁
  • 关闭动画还没完成就被移除了
  • 有些通知会被错误地覆盖

后来改用队列的方式来处理,每个通知都有独立的生命周期控制。这是优化后的样式部分:

/* notification.css */
.notification-container {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 9999;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 10px;
}

.notification-item {
  background: #fff;
  border: 1px solid #ddd;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  padding: 10px 20px;
  border-radius: 4px;
  opacity: 0;
  transform: translateX(100%);
  transition: all 0.3s ease;
}

.notification-item.show {
  opacity: 1;
  transform: translateX(0);
}

.notification-item.hide {
  opacity: 0;
  transform: translateX(100%);
}

意外收获:API封装

写着写着发现,与其让用户手动调用add方法,不如封装成更简单的API。于是加了个工厂函数:

// api.ts
import { createNotification, useNotification } from './notification'

let instance: any = null

export function notify(message: string, type: 'success' | 'error' = 'success') {
  if (!instance) {
    instance = createNotification()
  }
  useNotification().add(message, type)
}

// 使用方式
notify('操作成功', 'success')
notify('出错了', 'error')

这个改动虽然小,但大大提升了使用体验。现在其他开发者只需要引入一个简单的notify函数就能用了。

遗留问题和性能考虑

虽然基本功能都实现了,但还是有几个小问题没完全解决:

  • 在某些老旧浏览器上动画性能不够流畅
  • 当通知数量超过5个时,堆积效果不太理想
  • 没有做国际化支持

性能方面,目前每次新增或移除通知都会触发视图更新。考虑过用虚拟DOM优化,但觉得现阶段影响不大就没继续深挖了。

回顾与反思

总的来说,这个通知组件比我预想的要复杂。从最初以为几个小时能搞定,到最后花了三天才勉强满意。但也正因为这些坑,让我对Vue的响应式原理理解更深了。

如果让我重新来一遍,我可能会:

  • 提前规划好动画方案
  • 一开始就考虑多实例的情况
  • 做好单元测试覆盖

以上是我个人对这个Notification组件的完整讲解,有更优的实现方式欢迎评论区交流。这个组件后续还会继续迭代,等有了新进展再跟大家分享。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论