携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,点击查看活动详情
大家应该都有见过element-plus的Message组件吧?它可以实现函数式的调用,让我们能够在任何地方都能够通过调用它显示弹框,而不局限于在<template>中使用,那么如果要用原生js实现的话要怎么做呢?
思路分析
思路很简单,首先我们实现一个Message函数,直接调用它的时候弹出的是info类型的消息,然后再给这个函数对象上添加三个方法,分别是success、warn和error,用于弹出对应类型的消息
每次触发,就往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();
})();