以下是完整的Vue2全局通知组件实现方案,包含自动挂载和全局调用方法:
第一步:创建通知组件
<!-- src/components/Notification/index.vue -->
<template>
<div class="notification-container">
<transition-group name="notification-slide">
<div
v-for="(msg, index) in activeNotifications"
:key="msg.id"
class="notification"
:class="[`type-${msg.type}`]"
>
<div class="notification-header">
<span class="title">{{ msg.title }}</span>
<button class="close-btn" @click="close(msg.id)">×</button>
</div>
<div class="content">{{ msg.content }}</div>
</div>
</transition-group>
</div>
</template>
<script>
export default {
name: 'GlobalNotification',
data() {
return {
notifications: [],
nextId: 1
}
},
computed: {
activeNotifications() {
return this.notifications.slice(-3)
}
},
methods: {
add(config) {
const newMsg = {
id: this.nextId++,
type: 'info',
duration: 5000,
...config,
timer: null
}
newMsg.timer = setTimeout(() => {
this.close(newMsg.id)
}, newMsg.duration)
this.notifications.push(newMsg)
},
close(id) {
const index = this.notifications.findIndex(msg => msg.id === id)
if (index > -1) {
clearTimeout(this.notifications[index].timer)
this.notifications.splice(index, 1)
}
}
}
}
</script>
<!-- 保持之前提供的样式不变 -->
<style scoped>
.notification-container {
position: fixed;
bottom: 20px;
right: 20px;
z-index: 9999;
max-width: 350px;
display: flex;
flex-direction: column-reverse;
gap: 15px;
}
.notification {
background: #fff;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
padding: 15px;
border-left: 4px solid #409eff;
transition: all 0.3s ease;
}
.notification.type-success {
border-color: #67c23a;
}
.notification.type-warning {
border-color: #e6a23c;
}
.notification.type-error {
border-color: #f56c6c;
}
.notification-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.title {
font-weight: 600;
font-size: 14px;
color: #303133;
}
.close-btn {
border: none;
background: transparent;
font-size: 18px;
cursor: pointer;
color: #909399;
padding: 0 5px;
}
.content {
font-size: 13px;
color: #606266;
line-height: 1.5;
}
.notification-slide-enter-active,
.notification-slide-leave-active {
transition: all 0.3s ease;
}
.notification-slide-enter,
.notification-slide-leave-to {
opacity: 0;
transform: translateX(100%);
}
</style>
第二步:创建插件文件
// src/components/Notification/index.js
import Vue from 'vue'
import Notification from './index.vue'
const NotificationConstructor = Vue.extend(Notification)
let notificationInstance = null
const initInstance = () => {
notificationInstance = new NotificationConstructor({
el: document.createElement('div')
})
document.body.appendChild(notificationInstance.$el)
}
const NotificationPlugin = {
install(vue) {
vue.prototype.$notify = (config) => {
if (!notificationInstance) {
initInstance()
}
notificationInstance.add(config)
}
}
}
export default NotificationPlugin
第三步:全局注册(main.js)
// src/main.js
import Vue from 'vue'
import App from './App.vue'
import NotificationPlugin from '@/components/Notification/index'
Vue.use(NotificationPlugin)
new Vue({
render: h => h(App)
}).$mount('#app')
第四步:全局使用示例
在任何Vue组件中直接调用:
// 显示基础通知
this.$notify({
title: '系统消息',
content: '您有新的站内信',
type: 'success',
duration: 3000
})
// 显示警告通知
this.$notify({
title: '操作警告',
content: '删除操作不可恢复',
type: 'warning'
})
// 显示错误通知
this.$notify({
title: '发生错误',
content: '网络连接超时',
type: 'error',
duration: 8000
})
功能增强说明:
- 自动挂载:首次调用时自动创建DOM节点,无需手动放置组件
- 内存管理:使用单例模式保证全局只有一个通知实例
- 类型校验(可选增强):
// 在NotificationPlugin中添加
import { validateType } from './validators'
Vue.prototype.$notify = (config) => {
if (!validateType(config.type)) {
console.error('Invalid notification type')
return
}
// ...原有逻辑
}
- 全局配置(可选):
// 初始化配置
Vue.use(NotificationPlugin, {
maxDisplay: 5, // 最大显示数量
defaultDuration: 5000, // 默认持续时间
position: { // 显示位置
bottom: '20px',
right: '20px'
}
})
注意事项:
- 样式文件需要全局引入或在组件内使用
scoped
以外的样式声明 - 建议在组件销毁时自动清理定时器(已在原组件实现)
- 可以通过扩展
config
参数添加更多功能(如点击回调、自定义模板等)
这种实现方式具有以下优势:
- 真正的全局单例模式
- 完全解耦的调用方式
- 支持Vue2的完整生命周期管理
- 可扩展性强,方便后续功能升级
第五步:header组件判断新消息
mounted() {
this.startTimer(); // 组件挂载时启动定时器
},
beforeDestroy() {
this.stopTimer(); // 组件销毁时清除定时器
},
methods: {
// 启动定时器
startTimer() {
if (!this.timer) {
this.timer = setInterval(this.checkForNewMessages, 10000); // 每 10 秒执行一次
}
},
// 清除定时器
stopTimer() {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
},
// 检查是否有新消息
checkForNewMessages() {
this.$http.post('/message/list',{'pageSize':3,"userId":this.userId}).then(res => {
console.log('定时器判断是否有新消息 : ',res);
if (res.code === '0000'&&res.data.rows.length>0) {
res.data.rows.forEach(item => {
// 显示基础通知
this.$notify({
title: '新消息提醒',
content: item.content,
type: 'success',
duration: 3000
})
})
}
})
.catch(error => {
console.error('检查新消息失败:', error);
});
},