实现优雅的浏览器通知功能这些坑你一定要知道

司马艳敏 组件 阅读 2,413
赞 21 收藏
二维码
手机扫码查看
反馈

我的写法,亲测靠谱

Notification通知这个功能,我用得挺多的,尤其是在后台管理系统里。这种弹出式的提示框,既能提醒用户操作结果,又不会打断用户的操作流。我自己总结了一套写法,用起来感觉还蛮顺手。

实现优雅的浏览器通知功能这些坑你一定要知道

先上代码吧:

// notification.js
let idCounter = 0;

export function notify({ type = 'info', message, duration = 3000 }) {
    const id = notification-${idCounter++};
    const container = document.querySelector('#notification-container') || createContainer();

    const el = document.createElement('div');
    el.id = id;
    el.className = notification ${type};
    el.innerHTML = <span>${message}</span><button class="close">x</button>;

    container.appendChild(el);

    setTimeout(() => {
        removeNotification(id);
    }, duration);

    el.querySelector('.close').addEventListener('click', () => {
        removeNotification(id);
    });
}

function createContainer() {
    const container = document.createElement('div');
    container.id = 'notification-container';
    container.style.position = 'fixed';
    container.style.top = '20px';
    container.style.right = '20px';
    container.style.zIndex = '1000';
    document.body.appendChild(container);
    return container;
}

function removeNotification(id) {
    const el = document.getElementById(id);
    if (el) {
        el.remove();
    }
}

这个实现有几个亮点。首先,我用了个全局的计数器来生成唯一ID,这样每个通知都能独立管理。其次,我把容器的创建逻辑单独抽出来,避免每次都重复查询DOM。还有就是关闭按钮和自动消失都支持,用户体验会好一些。

样式这块我也简单写了点:

/* notification.css */
#notification-container {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
}

.notification {
    padding: 10px 20px;
    margin-bottom: 10px;
    border-radius: 4px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
    color: #fff;
}

.info { background: #2f86eb; }
.success { background: #5cb85c; }
.warning { background: #f0ad4e; }
.error { background: #d9534f; }

.close {
    margin-left: 15px;
    background: none;
    border: none;
    color: #fff;
    cursor: pointer;
}

为什么这样写?因为这种结构很灵活,以后想改样式或者加动画都很方便。我之前试过把所有样式直接写在JS里,后来发现维护起来太痛苦了。

这几种错误写法,别再踩坑了

说实话,我在Notification组件上踩过的坑可不少。最常见的就是滥用setTimeout导致内存泄漏。比如这种写法:

// 错误示范
export function badNotify(message) {
    const el = document.createElement('div');
    document.body.appendChild(el);
    
    // 这里有问题!
    setTimeout(() => {
        el.remove();
    }, 3000);
}

看起来没问题对吧?但实际上如果用户快速连续触发多次通知,就会导致一堆定时器堆积,而且这些元素可能还没正确移除。我之前就这样搞崩过一个系统,差点被老板骂死。

还有人喜欢直接操作innerHTML,像这样:

// 另一种错误示范
const container = document.getElementById('container');
container.innerHTML += <div class="notification">${message}</div>;

这种方式问题更大。首先性能差,每次都要重新解析整个HTML;其次容易引发XSS攻击;最后如果你的通知里有特殊字符,比如<啊>什么的,直接就挂了。

最后一个常见错误是不处理重复创建容器的问题。有些人每次调用都创建一个新的容器,结果页面上堆满了空的

,看着都难受。

实际项目中的坑

说几个实战中遇到的真实问题吧。第一个就是z-index的坑。记得有次我在一个复杂的后台系统里用Notification,结果发现通知总是被其他弹窗遮住。折腾了半天才发现是z-index设置不够高,最后改成动态获取最大值才解决:

function getMaxZIndex() {
    return Math.max(
        ...Array.from(document.querySelectorAll('body *'))
            .map(el => parseFloat(window.getComputedStyle(el).zIndex))
            .filter(zIndex => !isNaN(zIndex)),
        0
    ) + 1;
}

第二个问题是多语言适配。有些文案特别长,比如德语那种超级长的单词,直接撑破布局。后来我给文字加了个max-width,超出就显示省略号:

span {
    max-width: 200px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

第三个要注意的是屏幕缩放。有些用户喜欢放大网页,结果通知就跑偏了。我的解决方案是用window.resize事件动态调整位置,不过要注意防抖:

let resizeTimer;
window.addEventListener('resize', () => {
    clearTimeout(resizeTimer);
    resizeTimer = setTimeout(() => {
        const container = document.getElementById('notification-container');
        if (container) {
            container.style.right = '20px';
            container.style.top = '20px';
        }
    }, 200);
});

结尾唠叨几句

以上是我个人对Notification组件的一些实践经验分享。说实话,这个组件看着简单,但要做好还挺费劲的。我现在这套方案也不是完美无缺,比如动画效果还可以更炫酷,响应式处理还能更智能。

如果你有更好的实现方式,或者发现了我说的方案里有什么问题,欢迎在评论区交流。前端开发就是这样,永远都有优化的空间,大家一起进步嘛。

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

暂无评论