原生JavaScript实现自定义弹窗组件
本文详细介绍如何使用原生JavaScript、HTML和CSS从零构建一个自定义弹窗组件。通过封装构造函数、处理DOM节点及事件监听,实现可配置的提示框功能,并提供完整代码示例与兼容性说明,帮助开发者摆脱对第三方库的依赖,提升前端交互体验。
自定义弹窗背景与实现思路
浏览器自带的原生弹窗往往界面简陋且功能有限,在实际开发中,我们通常需要根据设计规范定制弹窗,或者引入如layer等第三方库。此前在慕课网学习了相关实现思路,笔者尝试编写了一套完整的自定义弹窗代码,并添加了详细注释,现分享如下。请注意,示例代码使用了ES6语法,若需兼容旧版浏览器,请将其转换为ES5写法,后续可能会补充兼容性更好的ES5版本。
HTML结构搭建
HTML结构部分较为简单,主要包含一个触发按钮,用于调用JavaScript中定义的实例方法,具体实现可参考后续代码。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>自定义弹窗</title>
<link rel="stylesheet" href="alert.css" rel="external nofollow" >
</head>
<body>
<button>Click me</button>
<script src="index.js"></script>
<script>
document.querySelector("button").addEventListener("click",()=>{
new $Msg({
content:"我的自定义弹窗好了",
type:"success",
cancle:function(){
let cancle = new $Msg({
content:"我是取消后的回调"
})
},
confirm:function(){
new $Msg({content:"我是确定后的回调"})
}
})
})
</script>
</body>
</html>
CSS样式定义
CSS样式部分已一并列出供参考,用户可根据实际设计稿的需求对样式进行调整和修改。
/* 弹出框最外层 */
.msg__wrap {
position: fixed;
top: 50%;
left: 50%;
z-index: 10;
transition: all .3s;
transform: translate(-50%, -50%) scale(0, 0);
max-width: 50%;
background: #fff;
box-shadow: 0 0 10px #eee;
font-size: 10px;
}
/* 弹出框头部 */
.msg__wrap .msg-header {
padding: 10px 10px 0 10px;
font-size: 1.8em;
}
.msg__wrap .msg-header .msg-header-close-button {
float: right;
cursor: pointer;
}
/* 弹出框中部 */
.msg__wrap .msg-body {
padding: 10px 10px 10px 10px;
display: flex;
}
/* 图标 */
.msg__wrap .msg-body .msg-body-icon{
width: 80px;
}
.msg__wrap .msg-body .msg-body-icon div{
width: 45px;
height: 45px;
margin: 0 auto;
line-height: 45px;
color: #fff;
border-radius: 50% 50%;
font-size: 2em;
}
.msg__wrap .msg-body .msg-body-icon .msg-body-icon-success{
background: #32a323;
text-align: center;
}
.msg__wrap .msg-body .msg-body-icon .msg-body-icon-success::after{
content: "成";
}
.msg__wrap .msg-body .msg-body-icon .msg-body-icon-wrong{
background: #ff8080;
text-align: center;
}
.msg__wrap .msg-body .msg-body-icon .msg-body-icon-wrong::after{
content: "误";
}
.msg__wrap .msg-body .msg-body-icon .msg-body-icon-info{
background: #80b7ff;
text-align: center;
}
.msg__wrap .msg-body .msg-body-icon .msg-body-icon-info::after{
content: "注";
}
/* 内容 */
.msg__wrap .msg-body .msg-body-content{
min-width: 200px;
font-size: 1.5em;
word-break: break-all;
display: flex;
align-items: center;
padding-left: 10px;
box-sizing: border-box;
}
/* 弹出框底部 */
.msg__wrap .msg-footer {
padding: 0 10px 10px 10px;
display: flex;
flex-direction: row-reverse;
}
.msg__wrap .msg-footer .msg-footer-btn {
width: 50px;
height: 30px;
border: 0 none;
color: #fff;
outline: none;
font-size: 1em;
border-radius: 2px;
margin-left: 5px;
cursor: pointer;
}
.msg__wrap .msg-footer .msg-footer-cancel-button{
background-color: #ff3b3b;
}
.msg__wrap .msg-footer .msg-footer-cancel-button:active{
background-color: #ff6f6f;
}
.msg__wrap .msg-footer .msg-footer-confirm-button{
background-color: #4896f0;
}
.msg__wrap .msg-footer .msg-footer-confirm-button:active{
background-color: #1d5fac;
}
/* 遮罩层 */
.msg__overlay {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 5;
background-color: rgba(0, 0, 0, .4);
transition: all .3s;
opacity: 0;
}
JavaScript核心逻辑
JavaScript部分是核心,涉及弹窗的交互逻辑与方法封装。开发者可参考此部分封装自己的组件库,实现更灵活的UI交互。
/*
*自定义弹窗
*/
//自执行函数 形成封闭的作用域 避免全局污染
//传入windwo和document对象 相当于将window和document作为了作用域中的局部变量,
//就不需要内部函数沿着作用域链再查找到最顶层的window 提高运行效率。
(function (window, document) {
//定义一个构造函数Msg 作为弹窗实例的构造函数。
let Msg = function (options) {
//执行初始化操作
this._init(options);
}
//定义初始化方法 并对方法传递的参数进行初始化
Msg.prototype = {
_init({
content = "", //文本内容
type = "info", //信息类型
useHTML = false, //是否解析html字符串
showIcon = true, //是否展示弹窗图标
confirm = null, //确认后得回调
cancle = null, //取消后得回调
footer = true, //是否显示底部的确认按钮
header = true, //是否显示头部信息及关闭按钮
title = "提示", //弹窗标题
contentStyle = {}, //内容样式
contentFontSize = "1.5em", //内容字体大小
btnName = ["确定", "取消"] //按钮文字内容
}) {
//将传入的值绑定到this上
this.content = content;
this.type = type;
this.useHTML = useHTML;
this.showIcon = showIcon;
this.confirm = confirm;
this.cancle = cancle;
this.footer = footer;
this.header = header;
this.title = title;
this.contentStyle = contentStyle;
this.contentFontSize = contentFontSize;
this.btnName = btnName;
//执行创建元素方法
this._creatElement();
//显示弹窗及遮罩
this._show({
el: this._el,
overlay: this._overlay
});
//绑定事件处理函数
this._bind({
el: this._el,
overlay: this._overlay
});
},
//创建弹窗元素方法
_creatElement() {
//创建最外层得包裹元素
let wrap = document.createElement("div");
wrap.className = "msg__wrap";
//定义弹窗得两个按钮
const [confirmBtnName, cancelBtnName] = this.btnName;
//判断是否显示弹窗标题
const headerHTML = this.header ?
`<div class="msg-header">
<span>${this.title}</span>
<span class="msg-header-close-button">×</span>
</div>` : "";
//判断是否显示图标
const iconHTML = this.showIcon ?
`<div class="msg-body-icon">
<div class="msg-body-icon-${this.type}"></div>
</div>` : "";
//判断是否显示弹窗底部按钮
const footerHTML = this.footer ?
`<div class="msg-footer">
<button class="msg-footer-btn msg-footer-cancel-button">${cancelBtnName}</button>
<button class="msg-footer-btn msg-footer-confirm-button">${confirmBtnName}</button>
</div>` : "";
//拼接完整html
const innerHTML = `${headerHTML}
<div class="msg-body">
${iconHTML}
<div class="msg-body-content"></div>
</div>
${footerHTML}`;
//将拼接的html赋值到wrap中
wrap.innerHTML = innerHTML;
//把自定义的样式进行合并
const contentStyle = {
fontSize: this.contentFontSize,
...this.contentStyle
}
//获取内容所属DOM
let content = wrap.querySelector(".msg-body .msg-body-content");
//将传过来的样式添加到contentDOM
for (const key in contentStyle) {
if (contentStyle.hasOwnProperty(key)) {
content.style[key] = contentStyle[key];
}
}
//给弹窗的conntent赋值
if (this.useHTML) {
content.innerHTML = this.content;
} else {
content.innerText = this.content;
}
//创建遮罩层
let overlay = document.createElement("div");
overlay.className = "msg__overlay";
//把dom挂载到当前实例上
this._overlay = overlay;
this._el = wrap;
},
//弹窗展现方法
_show({
el,
overlay
}) {
//把弹窗的dom和遮罩插入到页面中
document.body.appendChild(el);
document.body.appendChild(overlay);
//将弹窗显示出来 timeout进行异步处理显示动画
setTimeout(() => {
el.style.transform = "translate(-50%,-50%) scale(1,1)";
overlay.style.opacity = "1";
})
},
//关闭弹窗方法
_close({
el,
overlay
}) {
//隐藏dom
el.style.transform = "translate(-50%,-50%) scale(0,0)";
overlay.style.opcity = "0";
//根据动画时间 动画完成再移除
setTimeout(() => {
//把弹窗的dom和遮罩移除
document.body.removeChild(el)
document.body.removeChild(overlay);
}, 300);
},
//事件处理函数,为DOM绑定事件
_bind({
el,
overlay
}) {
//保存当前this
//const _this = this;
const cancle = (e) => {
this.cancle && this.cancle.call(this, e);
//隐藏弹窗
//hideMsg();
this._close({
el,
overlay
});
}
//确认弹窗
const confirm = (e) => {
this.confirm && this.confirm.call(this, e);
this._close({
el,
overlay
});
}
//顶部关闭按钮绑定事件
if (this.header) {
el.querySelector(".msg-header-close-button").addEventListener("click", cancle);
}
//弹窗底部两个按钮事件监听
if (this.footer) {
el.querySelector(".msg-footer-cancel-button").addEventListener("click", cancle);
el.querySelector(".msg-footer-confirm-button").addEventListener("click", confirm)
}
}
}
//将构造函数暴露到window,这样才能在全局作用域下直接调用
window.$Msg = Msg;
})(window, document);
组件使用与总结
至此,一个完整的自定义弹窗组件已构建完毕。使用时只需引入对应的JS和CSS文件,或将相关代码整合至公共JS库中即可直接调用。需要注意的是,实例化时必须使用new关键字调用构造函数。
总结
以上分享了基于JavaScript实现自定义弹窗的完整过程,希望能为读者提供有益参考。如有疑问欢迎留言,小编将及时回复。感谢大家对本网站的支持!
JS合并多个数组的三种方法:concat、spread与flat
2026-11-05 17:39:45
JavaScript怎么准确判断数据类型:typeof、instanceof与Object.prototype.toString
2026-11-05 17:09:21
JS中将数组和对象混合组装为JSON字符串
2026-11-05 16:41:42
JS运算符优先级与结合性的区别是什么?
2026-11-05 13:22:02
JS Map怎么只遍历Key或Value
2026-11-05 13:00:36
