Skip to content

原生 js - showMessage 显示一个消息提示。


loading

参数

  • textOrOptions: string | Object - 提示的文本内容或配置选项

  • options: Object - 配置选项

  • text: string - 提示的文本内容(当第一个参数为对象时使用)

  • type: string - 提示类型,可选值:'success'|'info'|'warning'|'error',默认'info'

  • duration: number - 显示时间,单位毫秒,默认 3000,设为 0 则不自动关闭

  • showIcon: boolean - 是否显示图标,默认 true

  • onClose: Function - 关闭时的回调函数

使用示例

javascript
// 基础用法

showMessage('操作成功')

// 快捷方式调用

showMessage.success('保存成功')

showMessage.error('操作失败')

// 使用配置项

showMessage({
  text: '这是一条消息提示',

  type: 'info',

  duration: 5000,

  onClose: () => {
    console.log('消息已关闭')
  }
})

源码

源码
js
/**
 * 显示一个消息提示
 * @author chuxiao
 * @param {string|Object} textOrOptions - 提示的文本内容或配置选项
 * @param {Object} [options={}] - 配置选项
 * @param {string} [options.text] - 提示的文本内容(当第一个参数为对象时使用)
 * @param {string} [options.type='info'] - 提示类型,可选值:'success'|'info'|'warning'|'error'
 * @param {number} [options.duration=3000] - 显示时间,单位毫秒,设为0则不自动关闭
 * @param {boolean} [options.showIcon=true] - 是否显示图标
 * @param {Function} [options.onClose] - 关闭时的回调函数
 *
 * @example
 * // 基础用法-直接传文本
 * showMessage('操作成功');
 *
 * // 快捷方式调用
 * showMessage.success('保存成功');
 * showMessage.error('操作失败');
 *
 * // 使用配置项
 * showMessage({
 *   text: '这是一条消息提示',
 *   type: 'info',
 *   duration: 5000,
 *   onClose: () => {
 *     console.log('消息已关闭');
 *   }
 * });
 */
function showMessage(textOrOptions, options = {}) {
  let text, finalOptions

  if (typeof textOrOptions === 'string') {
    text = textOrOptions
    finalOptions = options
  } else {
    text = textOrOptions.text || ''
    finalOptions = textOrOptions
  }

  const { type = 'info', duration = 3000, showIcon = true, onClose = () => {} } = finalOptions

  const iconColorMap = {
    success: '#52c41a',
    info: '#1677ff',
    warning: '#faad14',
    error: '#ff4d4f'
  }

  const backgroundColorMap = {
    success: '#f6ffed',
    info: '#e6f4ff',
    warning: '#fffbe6',
    error: '#fff2f0'
  }

  const borderColorMap = {
    success: '#b7eb8f',
    info: '#91caff',
    warning: '#ffe58f',
    error: '#ffccc7'
  }

  const textColorMap = {
    success: '#52c41a',
    info: '#1677ff',
    warning: '#faad14',
    error: '#ff4d4f'
  }

  const svgIcons = {
    success: `<svg viewBox="0 0 1024 1024" width="16" height="16"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 0 1-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z" fill="${iconColorMap[type]}"/></svg>`,
    info: `<svg viewBox="0 0 1024 1024" width="16" height="16"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm32 664c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V456c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272zm-32-344c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48z" fill="${iconColorMap[type]}"/></svg>`,
    warning: `<svg viewBox="0 0 1024 1024" width="16" height="16"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48z" fill="${iconColorMap[type]}"/></svg>`,
    error: `<svg viewBox="0 0 1024 1024" width="16" height="16"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359c-1.2-1.5-1.9-3.3-1.9-5.2 0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z" fill="${iconColorMap[type]}"/></svg>`
  }

  // 创建消息容器
  let messageContainer = document.querySelector('.message-container')
  if (!messageContainer) {
    messageContainer = document.createElement('div')
    messageContainer.className = 'message-container'
    messageContainer.style.cssText = `
      position: fixed;
      top: 20px;
      left: 50%;
      transform: translateX(-50%);
      z-index: 1000;
      pointer-events: none;
      display: flex;
      flex-direction: column;
      align-items: center;
    `
    document.body.appendChild(messageContainer)
  }

  // 创建消息元素
  const message = document.createElement('div')
  message.style.cssText = `
    background: ${backgroundColorMap[type]};
    padding: 10px 16px;
    border-radius: 4px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    margin-bottom: 10px;
    display: flex;
    align-items: center;
    gap: 8px;
    pointer-events: all;
    animation: messageSlideIn 0.3s ease;
    transition: all 0.3s ease;
    opacity: 1;
    transform: translateY(0);
    border: 1px solid ${borderColorMap[type]};
    max-width: 80vw;
  `

  // 添加图标
  if (showIcon && svgIcons[type]) {
    const iconContainer = document.createElement('div')
    iconContainer.innerHTML = svgIcons[type]
    iconContainer.style.cssText = `
      flex-shrink: 0;
      display: flex;
      align-items: center;
    `
    message.appendChild(iconContainer)
  }

  // 添加文本
  const content = document.createElement('span')
  content.textContent = text
  content.style.cssText = `
    font-size: 14px;
    color: ${textColorMap[type]};
    line-height: 1.5;
    word-wrap: break-word;
    word-break: break-all;
  `
  message.appendChild(content)

  // 添加样式
  const style = document.createElement('style')
  style.textContent = `
    @keyframes messageSlideIn {
      from {
        opacity: 0;
        transform: translateY(-20px);
      }
      to {
        opacity: 1;
        transform: translateY(0);
      }
    }
    @keyframes messageSlideOut {
      from {
        opacity: 1;
        transform: translateY(0);
      }
      to {
        opacity: 0;
        transform: translateY(-20px);
      }
    }
  `
  document.head.appendChild(style)

  // 添加到容器
  messageContainer.appendChild(message)

  // 关闭消息的函数
  const close = () => {
    message.style.animation = 'messageSlideOut 0.3s ease forwards'
    setTimeout(() => {
      messageContainer.removeChild(message)
      if (messageContainer.children.length === 0) {
        document.body.removeChild(messageContainer)
        document.head.removeChild(style)
      }
      onClose()
    }, 300)
  }

  // 添加关闭按钮
  if (duration === 0) {
    const closeBtn = document.createElement('div')
    closeBtn.innerHTML = '×'
    closeBtn.style.cssText = `
      margin-left: 8px;
      cursor: pointer;
      color: #00000073;
      font-size: 12px;
      flex-shrink: 0;
      line-height: 1;
      padding: 0 4px;
      border-radius: 2px;
      transition: all 0.3s;
    `

    closeBtn.onmouseover = () => {
      closeBtn.style.backgroundColor = 'rgba(0, 0, 0, 0.06)'
    }

    closeBtn.onmouseout = () => {
      closeBtn.style.backgroundColor = 'transparent'
    }

    closeBtn.onclick = close
    message.appendChild(closeBtn)
  }

  // 自动关闭
  if (duration > 0) {
    setTimeout(close, duration)
  }
}

// 添加快捷方式
;['success', 'info', 'warning', 'error'].forEach(type => {
  showMessage[type] = (text, options = {}) => {
    return showMessage(text, { ...options, type })
  }
})

Released under the MIT License.