如何实现一个 messagebox/日期组建/popup
常规实现思路
- 新建一个messagebox组建...- 黑色遮罩封装在messagebox中- 黑色遮罩 加上样式 { position: fixed: z-index: 999; opcity: .6 } 收工~
这样有两个问题
- 多个弹窗连续弹出的时候 遮罩层会叠加越来越深
- 如果再有一个类似的其他弹窗(如第二幅图)还要再写一个遮罩,这个时候他们的层级高低容易出现问题
解决方案:参考mintui 的popup实现方法
对黑色弹窗做统一管理 popup-manager.js
关键就再下面两个方法
openModal: function(id, zIndex, dom, modalClass, modalFade) { if (Vue.prototype.$isServer) return; if (!id || zIndex === undefined) return; this.modalFade = modalFade; const modalStack = this.modalStack; for (let i = 0, j = modalStack.length; i < j; i++) { const item = modalStack[i]; if (item.id === id) { return; } } const modalDom = getModal(); addClass(modalDom, 'v-modal'); if (this.modalFade && !hasModal) { addClass(modalDom, 'v-modal-enter'); } if (modalClass) { let classArr = modalClass.trim().split(/\s+/); classArr.forEach(item => addClass(modalDom, item)); } setTimeout(() => { removeClass(modalDom, 'v-modal-enter'); }, 200); if (dom && dom.parentNode && dom.parentNode.nodeType !== 11) { dom.parentNode.appendChild(modalDom); } else { document.body.appendChild(modalDom); } if (zIndex) { modalDom.style.zIndex = zIndex; } modalDom.style.display = ''; this.modalStack.push({ id: id, zIndex: zIndex, modalClass: modalClass }); }, closeModal: function(id) { const modalStack = this.modalStack; const modalDom = getModal(); if (modalStack.length > 0) { const topItem = modalStack[modalStack.length - 1]; if (topItem.id === id) { if (topItem.modalClass) { let classArr = topItem.modalClass.trim().split(/\s+/); classArr.forEach(item => removeClass(modalDom, item)); } modalStack.pop(); if (modalStack.length > 0) { modalDom.style.zIndex = modalStack[modalStack.length - 1].zIndex; } } else { for (let i = modalStack.length - 1; i >= 0; i--) { if (modalStack[i].id === id) { modalStack.splice(i, 1); break; } } } } ifIsNested(modalDom) if (modalStack.length === 0) { if (this.modalFade) { addClass(modalDom, 'v-modal-leave'); } setTimeout(() => { if (modalStack.length === 0) { if (modalDom.parentNode) modalDom.parentNode.removeChild(modalDom); modalDom.style.display = 'none'; PopupManager.modalDom = undefined; } removeClass(modalDom, 'v-modal-leave'); }, 200); } }};
modal --表示 黑色遮罩
dom -- 表示 黑色遮罩上面的白色内容区域
当打开弹窗的时候主要做两件事
1 手动生成 modal 并添加到modalDom的父节点下 dom.parentNode.appendChild(modalDom);
- modal 的每一个id 唯一- modal 的z-index 每当新生成一个都会自增 - dom的z-index 每当新生成一个都会自增 且比modal的大一- appendChild 有一个重要的属性 如果文档树中已经存在了 newchild,它将从文档树中删除,然后重新插入它的新位置,这个有什么用呢,如下如此便能不用手动removechild 同时保证只有一个遮罩,
2 把生成的modal 添加到数组里
当关闭弹窗的时候主要做一件事
1 将遮罩的 z-index改成之前保存在数组里的上一个遮罩的index值
如此基本可以满足大部分需求
然而当 popup 嵌套modal的时候 原库会出现modal位置错误的问题
解决方案也很简单在调用关闭方法的时候调用下面方法
/** * 判断modalDom 是否是再其他 popup中嵌套,如果是嵌套则将modal 移动到最外层modal的父节点下面 * @param {最后一次生成的modalDom} modalDom */const ifIsNested = function(modalDom) { if (modalDom) { if (modalDom.parentNode && modalDom.parentNode !== document.body) { if (modalDom.parentNode.parentNode && modalDom.parentNode.parentNode.className && modalDom.parentNode.parentNode.className.indexOf('mint-popup') !== -1) { modalDom.parentNode.parentNode.parentNode.appendChild(modalDom) } else { isNested(modalDom.parentNode) } } }}
补充二
想到一种弹窗组件 按照常规写法,调用的时候如果是要在业务组件里 通过 这样调用 而不是通过 this.$messagebox('')这样调用 会产生的问题
这种情况是 当我们有如下页面
我是聊天左侧我是聊天右侧我是弹窗,无论给我设置多高的zindex 我都不会盖住左侧聊天框