「原生练手」✨如何实现Element Plus的Message消息提示弹框?

534 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,点击查看活动详情

大家应该都有见过element-plusMessage组件吧?它可以实现函数式的调用,让我们能够在任何地方都能够通过调用它显示弹框,而不局限于在<template>中使用,那么如果要用原生js实现的话要怎么做呢?

Message消息弹框.gif

思路分析

思路很简单,首先我们实现一个Message函数,直接调用它的时候弹出的是info类型的消息,然后再给这个函数对象上添加三个方法,分别是successwarnerror,用于弹出对应类型的消息

每次触发,就往body元素中添加一个消息元素,设定一个类名,并为其编写样式和过渡动画,函数会在一段时间后将消息元素移除,这样就实现了

开始实践

HTML

首先为了方便看到效果,我们就像element-plus官方文档那样,设置四个按钮

其次,还要有一个容器元素用来存放消息,容器相对于body元素绝对定位到顶部

<div class="btn-group">
  <button class="btn info" id="show-info-msg-btn">info</button>
  <button class="btn success" id="show-success-msg-btn">success</button>
  <button class="btn warn" id="show-warn-msg-btn">warn</button>
  <button class="btn error" id="show-error-msg-btn">error</button>
</div>
<div id="message-container"></div>

CSS

先给容器元素设置样式,让其固定到顶部

#message-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  position: absolute;
  top: 30px;
  max-height: 100vh;
  transition: max-height 3s ease;
}

然后我们再给消息元素也设置样式,由.message控制消息的形状和入场出场动画,而背景色和文字颜色则由.info.success.warn.error去控制

.message {
  width: fit-content;
  padding: 10px 30px;
  text-align: center;
  border-radius: 5px;
  animation: fade-in-out 3s;
}

@keyframes fade-in-out {
  0% {
    opacity: 0;
    transform: translateY(-30%);
  }

  10% {
    opacity: 1;
    transform: translateY(0);
  }

  90% {
    opacity: 1;
    transform: translateY(0);
  }

  100% {
    opacity: 0;
    transform: translateY(-30%);
  }
}

.message.info {
  color: var(--info-text-color);
  background-color: var(--info-bg-color);
}

.message.success {
  color: var(--success-text-color);
  background-color: var(--success-bg-color);
}

.message.warn {
  color: var(--warn-text-color);
  background-color: var(--warn-bg-color);
}

.message.error {
  color: var(--error-text-color);
  background-color: var(--error-bg-color);
}

最后就是核心的js实现了,主要是Message函数的实现,原理不复杂,就和前面分析的一样

function Message(options) {
  if (!options) return;
  // message 是弹窗的消息内容
  // type 是消息的类型
  const message = options.message || "";
  const type = options.type || "info";

  // 创建消息元素
  const messageEl = document.createElement("div");
  messageEl.className = "message";
  messageEl.innerText = message;

  // 根据类型添加对应类名
  messageEl.classList.add(type);

  // 消息添加到容器中
  oMessageContainer.appendChild(messageEl);

  // 2s 后移除
  setTimeout(() => {
    messageEl.remove();
  }, 3000);
}

Message.info = (message) => Message({ message, type: "info" });
Message.success = (message) => Message({ message, type: "success" });
Message.warn = (message) => Message({ message, type: "warn" });
Message.error = (message) => Message({ message, type: "error" });

最后给几个按钮绑定上点击事件就可以实现文章开头的效果啦

(() => {
  const oShowInfoMsgBtn = document.getElementById("show-info-msg-btn");
  const oShowSuccessMsgBtn = document.getElementById("show-success-msg-btn");
  const oShowWarnMsgBtn = document.getElementById("show-warn-msg-btn");
  const oShowErrorMsgBtn = document.getElementById("show-error-msg-btn");
  const oMessageContainer = document.getElementById("message-container");

  const init = () => {
    bindEvent();
  };

  const bindEvent = () => {
    oShowInfoMsgBtn.addEventListener("click", () => {
      Message({ message: "this is a message." });
    });

    oShowSuccessMsgBtn.addEventListener("click", () => {
      Message.success("Congrats, this is a success message.");
    });

    oShowWarnMsgBtn.addEventListener("click", () => {
      Message.warn("Warning, this is a warning message.");
    });

    oShowErrorMsgBtn.addEventListener("click", () => {
      Message.error("Oops, this is a error message.");
    });
  };

  init();
})();