众所周知,浏览器自带的原生弹窗很不美观,而且功能比较单一,绝大部分时候我们都会按照设计图自定义弹窗或者直接使用注入layer的弹窗等等。前段时间在 慕课网 上看到了一个自定义弹窗的实现,自己顺便就学习尝试写了下,下面是主要的实现代码并添加了比较详细的注释,分享出来供大家参考。(代码用了ES6部分写法如需兼容低版本浏览器请把相关代码转成es5写法,后面有时间更新为一个兼容性较好的es5版本)
HTML部分:(没什么内容 放置一个按钮调用函数,js中调用实例即可供参考)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>自定义弹窗</title> <link href="https://www.jb51.net/alert.css" > </head> <body> <button>Click me</button> <script src="https://www.jb51.net/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>
样式部分:也放出来供参考,样式可以根据自己的设计图自行更改即可
/* 弹出框最外层 */ .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; }
JS部分:下面是最主要的部分,js方法及交互。自己封装自定义组件均可以此为参考,封装自己的组件。
/* *自定义弹窗 */ //自执行函数 形成封闭的作用域 避免全局污染 //传入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> <span>${this.title}</span> <span>×</span> </div>` : ""; //判断是否显示图标 const iconHTML = this.showIcon ? `<div> <div></div> </div>` : ""; //判断是否显示弹窗底部按钮 const footerHTML = this.footer ? `<div> <button>${cancelBtnName}</button> <button>${confirmBtnName}</button> </div>` : ""; //拼接完整html const innerHTML = `${headerHTML} <div> ${iconHTML} <div></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);