LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

使用 HTML + JavaScript 实现消息提示组件(附完整代码)

admin
2025年12月21日 11:14 本文热度 979
消息提示作为现代 Web 应用中一种重要的反馈机制,能够有效地向用户传达操作结果、系统状态等信息。本文将介绍如何使用原生 HTML、CSS 和 JavaScript 实现一套功能完善的消息提示组件。

效果演示

该消息提示组件提供了四种基本类型的消息提示:信息、成功、警告和错误。每种类型都有独特的图标和颜色标识,帮助用户快速识别消息性质。此外,还支持常驻型通知,即不自动关闭、需用户手动关闭的特殊提示。用户可以通过点击页面中的按钮触发各类通知,在右上角区域以动画形式弹出,并在设定的时间后自动消失。每个通知都包含标题、内容、时间和进度条,同时配有关闭按钮方便用户随时取消显示。

页面结构

消息容器

整个通知系统的根节点是一个固定定位的容器 #notification-container,这个容器由 JavaScript 创建,并通过 CSS 设置为 position: fixed,确保始终处于视窗右上角,不影响主内容流。

单个通知组件

每个通知都是一个独立的 .notice 元素,包含图标、标题、内容、时间、关闭按钮和进度条轨道等元素。渲染后的基本结构如下:
<div class="notice notice-info" id="notice-1">  <div class="notice-container">    <div class="notice-icon"></div>    <div class="notice-content-wrapper">      <div class="notice-title">消息提示</div>      <div class="notice-content">我是消息提示消息提示消息提示消息提示</div>      <div class="notice-time">2025-12-21 08:40:10</div>    </div>  </div>  <div class="notice-close-button" data-id="1"></div>  <div class="notice-progress">    <div class="notice-progress-bar" id="progress-1" style="width: 100%;"></div>  </div></div>

核心功能实现

为了统一管理和复用通知逻辑,项目采用了模块模式封装了一个名为 NoticeManager 的单例对象。它负责创建、更新及销毁通知实例,并维护全局状态。

初始化容器

该对象首先创建并挂载通知容器到文档中,然后定义私有变量存储所有活跃通知。
const container = document.createElement('div');container.id = 'notification-container';document.body.appendChild(container);
const notices = new Map();

创建通知流程

当调用任意一种类型的方法时(如 NoticeManager.info()),实际执行的是通用的 createNotice(options) 函数。该函数分配唯一 ID 并构建 DOM 结构,插入至通知容器,绑定关闭事件处理器,若启用了自动关闭,则启动倒计时和进度条动画,最后返回分配的 ID 供后续操作引用。
function createNotice(options) {  const id = ++noticeId;  const type = options.type || 'info';  const title = options.title || '';  const message = options.message || '';  const timeout = options.timeout || 3000;  const autoClose = options.autoClose !== false;  // 创建通知元素  const noticeEl = document.createElement('div');  noticeEl.className = `notice notice-${type}`;  noticeEl.id = `notice-${id}`;  noticeEl.innerHTML = `<div class="notice-container">                    <div class="notice-icon"></div>                    <div class="notice-content-wrapper">                        ${title ? `<div class="notice-title">${title}</div>` : ''}                        <div class="notice-content">${message}</div>                        <div class="notice-time">${getCurrentTime()}</div>                    </div>                </div>                <div class="notice-close-button" data-id="${id}"></div>                ${autoClose ? `<div class="notice-progress">                    <div class="notice-progress-bar" id="progress-${id}"></div>                </div>` : ''}`;  container.appendChild(noticeEl);  const closeBtn = noticeEl.querySelector('.notice-close-button');  closeBtn.addEventListener('click'() => destroyNotice(id));  // 创建通知实例对象  const noticeInstance = {    id: id,    element: noticeEl,    startTimeDate.now(),    timeout: timeout,    autoClose: autoClose,    timernull,    destroyedfalse  };  notices.set(id, noticeInstance);  // 如果启用自动关闭,初始化进度条并设置定时器  if (autoClose) {    const progressBar = document.getElementById(`progress-${id}`);    if (progressBar) {      progressBar.style.width = '100%';    }    updateProgressBar(id);    noticeInstance.timer = setTimeout(() => destroyNotice(id), timeout);  }  return id;}

自动关闭机制

对于设置了 autoClose: true 的通知,会在创建完成后立即开始倒计时,并同步驱动进度条从 100% 缓慢减少至 0%,最终触发销毁动作。
function updateProgressBar(id) {  const notice = notices.get(id);  if (!notice || notice.destroyed || !notice.autoClosereturn;
  const elapsed = Date.now() - notice.startTime;  const progress = Math.max(0100 - (elapsed / notice.timeout) * 100);  const progressBar = document.getElementById(`progress-${id}`);  if (progressBar) {    progressBar.style.width = `${progress}%`;  }  if (progress > 0) {    requestAnimationFrame(() => updateProgressBar(id));  }}

销毁通知处理

无论是超时还是用户主动点击关闭按钮,都会进入 destroyNotice(id) 流程进行清理工作。
function destroyNotice(id) {  const notice = notices.get(id);  if (!notice || notice.destroyedreturn;  if (notice.timer) {    clearTimeout(notice.timer);  }  notice.destroyed = true;  notices.delete(id);  const noticeEl = document.getElementById(`notice-${id}`);  if (noticeEl) {    noticeEl.classList.add('slideOutRight');    setTimeout(() => {      if (noticeEl.parentNode) {        noticeEl.parentNode.removeChild(noticeEl);      }    }, 300);  }}

扩展建议

  • 声音提醒选项:允许用户开启伴随音效的通知提醒

  • 自定义主题风格:开放更多外观定制接口满足个性化需求

  • 多层级优先级排序:引入重要程度分级策略,使高优先级通知始终保持可见

  • 批量操作支持:增加清除全部等功能按钮

完整代码

git地址:https://gitee.com/ironpro/hjdemo/blob/master/notice/index.html
<!DOCTYPE html><html lang="zh-CN"><head>  <meta charset="utf-8">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <title>消息提示</title>  <style>      * {          margin0;          padding0;          box-sizing: border-box;      }      body {          background-color#f5f5f5;          min-height100vh;          padding20px;      }      .container {          max-width600px;          margin0 auto;          background: white;          border-radius15px;          box-shadow0 20px 40px rgba(0,0,0,0.1);          overflow: hidden;      }      .header {          background#2c3e50;          color: white;          padding20px;          text-align: center;      }      .header h1 {          font-size24px;          font-weight500;      }      .main {          padding20px;          text-align: center;          height300px;      }      .buttons {          margin-top60px;      }      .notice-button {          padding10px 20px;          border: none;          border-radius4px;          cursor: pointer;          font-size14px;          font-weight500;          transition: all 0.2s;          color: white;          margin-right10px;          margin-bottom10px;          backgroundvar(--color-info);      }      .notice-button.success { backgroundvar(--color-success); }      .notice-button.error { backgroundvar(--color-error); }      .notice-button.warning { backgroundvar(--color-warning); }      .notice-button.info { backgroundvar(--color-info); }
      /* 通知样式部分 */      :root {          --color-info#1890ff;          --color-success#52c41a;          --color-warning#faad14;          --color-error#ff4d4f;      }      #notification-container {          position: fixed;          top20px;          right20px;          z-index9999;      }      .notice {          position: relative;          margin-bottom10px;          padding16px;          box-shadow0 1px 6px rgba(0,0,0,0.2);          background#fff;          width320px;          animation: fadeInRight 0.3s;          transition: transform 0.3s, opacity 0.3s;          overflow: hidden;      }      @keyframes fadeInRight {          from {              opacity0;              transformtranslate3d(100%00);          }          to {              opacity1;              transformtranslate3d(000);          }      }      .slideOutRight {          animation: slideOutRight 0.3s forwards;      }      @keyframes slideOutRight {          from {              opacity1;              transformtranslate3d(000);          }          to {              opacity0;              transformtranslate3d(100%00);          }      }      .notice-close-button {          position: absolute;          top10px;          right10px;          width16px;          height16px;          border-radius50%;          cursor: pointer;          display: flex;          align-items: center;          justify-content: center;      }      .notice-close-button:hover {          background-color#e81123;      }      .notice-close-button::before {          content"×";          color#999;          font-weight: bold;          font-size16px;      }      .notice-close-button:hover::before {          color#fff;      }      .notice-container {          display: flex;          align-items: flex-start;      }      .notice-icon {          width26px;          text-align: center;          margin-right16px;          flex-shrink0;      }      .notice-icon::before {          font-size26px;          display: block;      }      .notice-info .notice-icon::before {          content"ℹ";          color:  var(--color-info);;      }      .notice-success .notice-icon::before {          content"✓";          color:  var(--color-success);;      }      .notice-warning .notice-icon::before {          content"⚠";          color:  var(--color-warning);;      }      .notice-error .notice-icon::before {          content"✖";          color:  var(--color-error);;      }      .notice-content-wrapper {          flex1;          min-width0;      }      .notice-title {          font-weight700;          margin-bottom8px;          font-size14px;          line-height17px;          color#17233d;          white-space: nowrap;          overflow: hidden;          text-overflow: ellipsis;      }      .notice-content {          font-size13px;          color#515a6e;          line-height1.5;          margin-bottom8px;      }      .notice-time {          font-size10px;          color#999;          text-align: right;      }      .notice-progress {          position: absolute;          left0;          bottom0;          height3px;          width100%;          background-color#f0f0f0;      }      .notice-progress-bar {          height100%;          width0%;          transition: width 0.1s linear;      }      .notice-info .notice-progress-bar {          background-colorvar(--color-info);      }      .notice-success .notice-progress-bar {          background-colorvar(--color-success);      }      .notice-warning .notice-progress-bar {          background-colorvar(--color-warning);      }      .notice-error .notice-progress-bar {          background-colorvar(--color-error);      }  </style></head><body><div class="container">  <div class="header">    <h1>消息提示</h1>  </div>  <div class="main">    <div class="buttons">      <button class="notice-button info" id="notice1">信息</button>      <button class="notice-button success" id="notice2">成功</button>      <button class="notice-button warning" id="notice3">警告</button>      <button class="notice-button error" id="notice4">错误</button>      <button class="notice-button info" id="notice5">不自动关闭</button>    </div>  </div></div><script>  // 通知管理器  const NoticeManager = (function() {    const container = document.createElement('div');    container.id = 'notification-container';    document.body.appendChild(container);
    let noticeId = 0;    const notices = new Map();    // 创建通知    function createNotice(options) {      const id = ++noticeId;      const type = options.type || 'info';      const title = options.title || '';      const message = options.message || '';      const timeout = options.timeout || 3000;      const autoClose = options.autoClose !== false;      // 创建通知元素      const noticeEl = document.createElement('div');      noticeEl.className = `notice notice-${type}`;      noticeEl.id = `notice-${id}`;      noticeEl.innerHTML = `<div class="notice-container">                        <div class="notice-icon"></div>                        <div class="notice-content-wrapper">                            ${title ? `<div class="notice-title">${title}</div>` : ''}                            <div class="notice-content">${message}</div>                            <div class="notice-time">${getCurrentTime()}</div>                        </div>                    </div>                    <div class="notice-close-button" data-id="${id}"></div>                    ${autoClose ? `<div class="notice-progress">                        <div class="notice-progress-bar" id="progress-${id}"></div>                    </div>` : ''}`;      container.appendChild(noticeEl);      const closeBtn = noticeEl.querySelector('.notice-close-button');      closeBtn.addEventListener('click'() => destroyNotice(id));      // 创建通知实例对象      const noticeInstance = {        id: id,        element: noticeEl,        startTimeDate.now(),        timeout: timeout,        autoClose: autoClose,        timernull,        destroyedfalse      };      notices.set(id, noticeInstance);      // 如果启用自动关闭,初始化进度条并设置定时器      if (autoClose) {        const progressBar = document.getElementById(`progress-${id}`);        if (progressBar) {          progressBar.style.width = '100%';        }        updateProgressBar(id);        noticeInstance.timer = setTimeout(() => destroyNotice(id), timeout);      }      return id;    }    // 更新进度条    function updateProgressBar(id) {      const notice = notices.get(id);      if (!notice || notice.destroyed || !notice.autoClosereturn;
      const elapsed = Date.now() - notice.startTime;      const progress = Math.max(0100 - (elapsed / notice.timeout) * 100);      const progressBar = document.getElementById(`progress-${id}`);      if (progressBar) {        progressBar.style.width = `${progress}%`;      }      if (progress > 0) {        requestAnimationFrame(() => updateProgressBar(id));      }    }    // 销毁通知    function destroyNotice(id) {      const notice = notices.get(id);      if (!notice || notice.destroyedreturn;      if (notice.timer) {        clearTimeout(notice.timer);      }      notice.destroyed = true;      notices.delete(id);      const noticeEl = document.getElementById(`notice-${id}`);      if (noticeEl) {        noticeEl.classList.add('slideOutRight');        setTimeout(() => {          if (noticeEl.parentNode) {            noticeEl.parentNode.removeChild(noticeEl);          }        }, 300);      }    }    // 获取当前时间    function getCurrentTime() {      const now = new Date();      const year = now.getFullYear();      const month = String(now.getMonth() + 1).padStart(2'0');      const day = String(now.getDate()).padStart(2'0');      const hours = String(now.getHours()).padStart(2'0');      const minutes = String(now.getMinutes()).padStart(2'0');      const seconds = String(now.getSeconds()).padStart(2'0');      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;    }    // 公开接口    return {      info(options) => createNotice({...options, type'info'}),      success(options) => createNotice({...options, type'success'}),      warning(options) => createNotice({...options, type'warning'}),      error(options) => createNotice({...options, type'error'})    };  })();
  // 绑定按钮事件  document.getElementById('notice1').addEventListener('click'() => {    NoticeManager.info({      title'消息提示',      message'我是消息提示消息提示消息提示消息提示'    });  });
  document.getElementById('notice2').addEventListener('click'() => {    NoticeManager.success({      title'成功提示',      message'我是消息提示消息提示消息提示消息提示'    });  });
  document.getElementById('notice3').addEventListener('click'() => {    NoticeManager.warning({      title'警告提示',      message'我是消息提示消息提示消息提示消息提示'    });  });
  document.getElementById('notice4').addEventListener('click'() => {    NoticeManager.error({      title'错误提示',      message'我是消息提示消息提示消息提示消息提示'    });  });
  document.getElementById('notice5').addEventListener('click'() => {    NoticeManager.info({      title'常驻通知',      message'这条通知不会自动关闭,需要手动点击关闭按钮',      autoClosefalse    });  });</script></body></html>


阅读原文:原文链接


该文章在 2025/12/22 18:04:05 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved