本文作者:云初冀北

使用纯JavaScript封装一个消息提示条功能示例详解

使用纯JavaScript封装一个消息提示条功能示例详解摘要: 介绍一个类似Element UI、Ant-Design UI等 UI 框架的消息提示功能,方便在任何网页环境中直接调用函数使用;区别在不依赖 js 及 css 引用,而是使用纯 j...

使用纯JavaScript封装一个消息提示条功能示例详解

?=

介绍

一个Element UIAnt-Design UI等 UI 框架消息提示功能,方便在任何网页环境中直接调用函数使用;区别在不依赖 JS 及 css 引用,而是使用纯 js封装实现代码更精简,同时保持和 UI 框架一样的视觉效果(可自行修改成自己喜欢的样式

代码仓

在线预览效果(点击登录】、【点击复制】按钮时触发提示效果)

使用纯JavaScript封装一个消息提示条功能示例详解

思路&amP;布局

先来写单个提示条,并实现想要的过渡效果,最后再用逻辑操作输出节点即可;这里不需要父节点裹,直接输出到<body>中,保证提示条的代码结构位置永远在最上层。
<style>   .msg-box { positiON: fixed; top: 0; left: 50%; DIsplay: flex; padding: 12px 16px; border-radius: 2px; background-color: #fff; box-shadow: 0 3px 3px -2px rgba(0,0,0,.2),0 3px 4px 0 rgba(0,0,0,.14),0 1px 8px 0 rgba(0,0,0,.12); transform: translate3D(-50%, 0%, 0);   } </style> <body>   <div class="msg-box"></div> </body> 
基础的样式写好之后,来定义进入的过渡动画,这里使用animation作为进入动画,因为节点一输出就会执行了
.msg-box {   ...省略以上代码   animation: msg-move .4s; } @keyframes msg-move {   0% { opacity: 0; transfORM: translate3d(-50%, -100%, 0);   }   100% { opacity: 1; transform: translate3d(-50%, 0%, 0);   } } 
最后就是过渡结束动画,这里使用transition的过渡方式,即定义一个.hIDE,之后通过 js 去控制切换 class 去实现过渡切换
.msg-box {   ...省略以上代码   opacity: 1;   transition: .4s all; // 保持和 animation 的过渡时间一致 } .msg-box.hIDe {   opacity: 0;   transform: translate3d(-50%, -100%, 0); } 

这里样式布局就全部完成了,剩下的交给 js 去处理对应的操作逻辑。

操作逻辑

因为调用时,消息条是多个,并且为往下叠加的效果,且节点是散布在<body>下,有可能给其他DOM操作插入节点。所以在输出节点的时候要将其存放起来,然后通过循环的方式去设置每一个节点的padding-top,这样就能保证视觉排效果和代码操作的顺序保持一致了,之后所做的删除操作也是通过循环去设置每一个节点的padding-top
/**  * 消息队列  * @type {Array<htmlElement>}  */ const messagelist = []; /**  * 获取指定`item`的定位`top`  * @param {HTMLElement=} el   */ function GetItemTop(el) {   let top = 10; // 起始的边距   for (let i = 0; i < messageList.length; i++) { const item = messageList[i]; if (el && el === item) {   break; } top += item.clientHeight + 20; // 两个消息条的间距为20   }   return top; } /**  * 删除指定列表项  * @param {HTMLElement} el   */ function removeItem(el) {   for (let i = 0; i < messageList.length; i++) { const item = messageList[i]; if (item === el) {   messageList.splice(i, 1);   break; }   }   el.classList.add(".hide");   messageList.forEach(function (item) { item.style.top = `${getItemTop(item)}px`;   }); } 
输出节点,并监听 动画进入过渡持续时间动画退出过渡 ; 进入的过渡使用addEventListener("animationend", fn)持续时间使用settimeout(延迟 N 秒之后为节点添加.hide)退出的过渡使用addEventListener("transitionend", fn)
/** 一直累加的定位层级 */ let zIndex = 1000; /**  * 显示一条消息  * @param {string} content 内容  * @param {number} duration 持续时间,优先级比默认值高  */ function show(content, duration) {   const el = document.createElement("div");   el.style.top = `${getItemTop()}px`;   el.style.zIndex = zIndex;   el.innerHTML = content;   zIndex++;   messageList.push(el);   document.body.appendChild(el);   // 添加动画监听事件   function animationEnd() { el.removeEventListener("animationend", animationEnd); setTimeout(removeItem, duration || 3000, el);   }   el.addEventListener("animationend", animationEnd);   function transitionEnd() { if (getComputedStyle(el).opacity !== "0") return; el.removeEventListener("transitionend", transitionEnd); el.remove();   }   el.addEventListener("transitionend", transitionEnd); } 

整个消息输出功能就完成了,最后只需要把对应的方法封装起来并暴露需要调用的函数,并把css样式写进方法里就可以在任意地方使用了;css写进js里其实就是把上面写好的样式,通过字符串模板的方式用变量接收并赋值给动态输入<style>标签就完事,另外样式隔离可以通过模拟css.modeule的方案去实现,具体看下面完整代码。

完整代码

/**  * 消息提示条  * @param {object} params   * @param {number} params.duration 持续时间(毫秒),默认`3000`  * @param {number} params.zIndex 起始定位层级,默认`1000`  */ function useMessage(params = {}) {   const doc = document;   const cssmodule = `__${Math.random().toString(36).Slice(2, 7)}`;   const className = { box: `msg-box${cssmodule}`, hide: `hide${cssModule}`, text: `msg-text${cssModule}`, icon: `msg-icon${cssModule}`   }   const style = doc.createElement("style");   style.textContent = `   .${className.box}, .${className.icon}, .${className.text} { padding: 0; margin: 0; box-sizing: border-box;   }   .${className.box} { position: fixed; top: 0; left: 50%; display: flex; padding: 12px 16px; border-radius: 2px; background-color: #fff; box-shadow: 0 3px 3px -2px rgba(0,0,0,.2),0 3px 4px 0 rgba(0,0,0,.14),0 1px 8px 0 rgba(0,0,0,.12); white-space: nowrap; animation: ${className.box}-move .4s; transition: .4s all; transform: translate3d(-50%, 0%, 0); opacity: 1; overflow: hidden;   }   .${className.box}::after { content: ""; position: absolute; left: 0; top: 0; height: 100%; width: 4px;   }   @keyframes ${className.box}-move { 0% {   opacity: 0;   transform: translate3d(-50%, -100%, 0); } 100% {   opacity: 1;   transform: translate3d(-50%, 0%, 0); }   }   .${className.box}.${className.hide} { opacity: 0; /* transform: translate3d(-50%, -100%, 0); */ transform: translate3d(-50%, -100%, 0) scale(0);   }   .${className.icon} { display: inline-block; width: 18px; height: 18px; border-radius: 50%; overflow: hidden; margin-right: 6px; position: relative;   }   .${className.text} { font-size: 14px; line-height: 18px; color: #555;   }   .${className.icon}::after,   .${className.icon}::before { position: absolute; content: ""; background-color: #fff;   }   .${className.box}.info .${className.icon}, .${className.box}.info::after { background-color: #1890ff;   }   .${className.box}.success .${className.icon}, .${className.box}.success::after { background-color: #52c41a;   }   .${className.box}.warning .${className.icon}, .${className.box}.warning::after { background-color: #faad14;   }   .${className.box}.error .${className.icon}, .${className.box}.error::after { background-color: #ff4d4f;   }   .${className.box}.info .${className.icon}::after,   .${className.box}.warning .${className.icon}::after { top: 15%; left: 50%; margin-left: -1px; width: 2px; height: 2px; border-radius: 50%;   }   .${className.box}.info .${className.icon}::before,   .${className.box}.warning .${className.icon}::before { top: calc(15% + 4px); left: 50%; margin-left: -1px; width: 2px; height: 40%;   }   .${className.box}.error .${className.icon}::after,    .${className.box}.error .${className.icon}::before { top: 20%; left: 50%; width: 2px; height: 60%; margin-left: -1px; border-radius: 1px;   }   .${className.box}.error .${className.icon}::after { transform: rotate(-45deg);   }   .${className.box}.error .${className.icon}::before { transform: rotate(45deg);   }   .${className.box}.success .${className.icon}::after { box-sizing: content-box; background-color: transparent; border: 2px solid #fff; border-left: 0; border-top: 0; height: 50%; left: 35%; top: 13%; transform: rotate(45deg); width: 20%; transform-origin: center;   }   `.replace(/(\n|\t|\s)*/ig, "$1").replace(/\n|\t|\s(\{|\}|\,|\:|\;)/ig, "$1").replace(/(\{|\}|\,|\:|\;)\s/ig, "$1");   doc.head.appendChild(style);   /** 一直累加的定位层级 */   let zIndex = params.zIndex || 1000;   /**    * 消息队列    * @Type {Array<HTMLElement>}    */   const messageList = [];   /**    * 获取指定`item`的定位`top`    * @param {HTMLElement=} el     */   function getItemTop(el) { let top = 10; for (let i = 0; i < messageList.length; i++) {   const item = messageList[i];   if (el && el === item) { break;   }   top += item.clientHeight + 20; } return top;   }   /**    * 删除指定列表项    * @param {HTMLElement} el     */   function removeItem(el) { for (let i = 0; i < messageList.length; i++) {   const item = messageList[i];   if (item === el) { messageList.splice(i, 1); break;   } } el.classList.add(className.hide); messageList.forEach(function(item) {   item.style.top = `${getItemTop(item)}px`; });   }   /**    * 显示一条消息    * @param {string} content 内容    * @param {"info"|"success"|"warning"|"error"} type 消息类型    * @param {number} duration 持续时间,优先级比默认值高    */   function show(content, type = "info", duration) { const el = doc.createElement("div"); el.className = `${className.box} ${type}`; el.style.top = `${getItemTop()}px`; el.style.zIndex = zIndex; el.innerHTML = ` <span class="${className.icon}"></span> <span class="${className.text}">${content}</span> `; zIndex++; messageList.push(el); doc.body.appendChild(el); // 添加动画监听事件 function animationEnd() {   el.removeEventListener("animationend", animationEnd);   setTimeout(removeItem, duration || params.duration || 3000, el); } el.addEventListener("animationend", animationEnd); function transitionEnd() {   if (getComputedStyle(el).opacity !== "0") return;   el.removeEventListener("transitionend", transitionEnd);   el.remove(); } el.addEventListener("transitionend", transitionEnd);   }   return { show, /**  * 普通描述提示  * @param {string} msg   */ info(msg) {   show(msg, "info"); }, /**  * 成功提示  * @param {string} msg   */ success(msg) {   show(msg, "success"); }, /**  * 警告提示  * @param {string} msg   */ warning(msg) {   show(msg, "warning"); }, /**  * 错误提示  * @param {string} msg   */ error(msg) {   show(msg, "error"); }   } }

以上就是使用纯JavaScript封装一个消息提示条功能示例详解的详细内容,更多关于JavaScrIPt封装消息提示条的资料请关注云初冀北其它相关文章!

免责声明
本站提供的资源,都来自网络,版权争议与本站无关,所有内容及软件的文章仅限用于学习和研究目的。不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负,我们不保证内容的长久可用性,通过使用本站内容随之而来的风险与本站无关,您必须在下载后的24个小时之内,从您的电脑/手机中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。侵删请致信E-mail:Goliszhou@gmail.com
$

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏

阅读
分享

发表评论

快捷回复:

评论列表 (暂无评论,200人围观)参与讨论

还没有评论,来说两句吧...