原生js实现自定义alert风格和实现
2018年6月29 最新更新
添加函数节流,解决多次点击问题,添加单例模式,提高代码性能。
1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <meta charset="UTF-8"> 6 <title>自定义alert</title> 7 <style type="text/css"> 8 html, 9 body { 10 padding: 0; 11 margin: 0; 12 } 13 /* //防止鼠标双击选中文字 14 */ 15 16 div { 17 18 -khtml-user-select: none; 19 /*早期浏览器*/ 20 user-select: none; 21 } 22 /* //来自animated.css的样式 */ 23 24 .animated { 25 animation-duration: 1s; 26 animation-fill-mode: both; 27 } 28 29 @keyframes bounceInDown { 30 from, 31 60%, 32 75%, 33 90%, 34 to { 35 animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 36 } 37 38 0% { 39 opacity: 0; 40 transform: translate3d(0, -3000px, 0); 41 } 42 43 60% { 44 opacity: 1; 45 transform: translate3d(0, 25px, 0); 46 } 47 48 75% { 49 transform: translate3d(0, -10px, 0); 50 } 51 52 90% { 53 transform: translate3d(0, 5px, 0); 54 } 55 56 to { 57 transform: none; 58 display: none; 59 } 60 } 61 62 .bounceInDown { 63 animation-name: bounceInDown; 64 } 65 66 </style> 67 </head> 68 69 <body> 70 <button onclick="test" id="btn">点我测试</button> 71 <script type="text/javascript"> 72 (function(win, doc) { 73 var firstTime = true, 74 startTime = 0; 75 76 function alert(txt, autoTime, top) { 77 //工具函数 78 function $(dom) { 79 return document.querySelector(dom); 80 } 81 //单利模式核心 82 var getSingle = function(fn) { 83 var result; 84 return function() { 85 return (result || (result = fn.apply(this, arguments))); 86 } 87 } 88 89 //函数节流 90 var throttle = function(fn, interval) { 91 var __self = fn; // 保存需要被延迟执行的函数引用// 是否是第一次调用 92 return function() { 93 var args = arguments, 94 __me = this; 95 if (firstTime) { // 如果是第一次调用,不需延迟执行 96 __self.apply(__me, args); 97 return firstTime = false; 98 } 99 100 var endTime = new Date() * 1; //时间大于3000秒下次执行 101 if (endTime - startTime > (autoTime || 3000)) { 102 __self.apply(__me, args); 103 } 104 }; 105 }; 106 107 108 //创建div代码 109 var createDiv = function() { 110 111 var div = doc.createElement("div"); 112 div.style.backgroundColor = " #22b9ff"; 113 div.style.color = " #fff"; 114 div.style.position = " fixed"; 115 div.style.zIndex = 9999999; 116 div.style.height = " 60px"; 117 div.style.top = top || "10%"; 118 div.style.left = "50%"; 119 div.style.lineHeight = " 60px"; 120 div.style.borderRadius = " 4px"; 121 div.style.fontSize = " 20px"; 122 div.style.textAlign = "center"; 123 div.style.padding = "0 10px"; 124 div.className = "animated bounceInDown"; 125 div.id = "alert"; 126 div.innerHTML = txt || "不能为空!"; 127 return div; 128 } 129 130 var createSingleDiv = getSingle(createDiv); 131 132 return throttle(function() { 133 134 var div = createSingleDiv(); //创建div 135 startTime = new Date() * 1; //初始位置 136 $("body").appendChild(div); 137 //动态调整位置 138 var alertWidth = win.getComputedStyle($("#alert"), null).width; 139 div.style.marginLeft = -parseInt(alertWidth) / 2 + "px"; 140 setTimeout(function() { 141 $("body").removeChild(div); 142 }, autoTime || 3000); 143 }).apply(this, null); 144 } 145 146 win.alert = alert; //导出 147 148 })(window, document); 149 150 151 document.getElementById('btn').onclick = function() { 152 alert("手机号不能为空!"); 153 } 154 155 </script> 156 </body> 157 158 </html>
上篇文章介绍了自定义confirm的必要性,可以说alert是比confirm更为常用的浏览器自带组件了。但更因为常用,而原生组件无论是样式还是体验都不是很好,所以更加有必要自定义。
此为改造的背景。
本来第一版是自定义的第一版是没有防止提示期间,用户进行其他操作的透明层的;js代码是这样:
1 <script type="text/javascript"> 2 window.alert = function(text) { 3 4 //实现alert 5 var div = document.createElement("div"); 6 div.style.backgroundColor = " #22b9ff"; 7 div.style.color = " #fff"; 8 div.style.position = " fixed"; 9 div.style.zIndex = 9999999; 10 div.style.height = " 60px"; 11 div.style.top = " 10%"; 12 div.style.left = "50%"; 13 div.style.lineHeight = " 60px"; 14 div.style.borderRadius = " 4px"; 15 div.style.fontSize = " 20px"; 16 div.style.textAlign = "center"; 17 div.style.padding = "0 10px"; 18 div.className = "animated bounceInDown"; 19 div.id = "alert"; 20 div.innerHTML = text; 21 document.getElementsByTagName("body")[0].appendChild(div); 22 var selfObj = document.getElementById("alert"); 23 //动态调整位置 24 var alertWidth = window.getComputedStyle(selfObj, null).width; 25 div.style.marginLeft = -parseInt(alertWidth) / 2 + "px"; 26 setTimeout(function() { 27 document.getElementsByTagName("body")[0].removeChild(div); 28 }, 30000); 29 } 30 alert("这是自定义的alert"); 31 </script>
后来想到实际的alert效果,提示期间是无法做其它操作的,于是改造为这样
1 <script type="text/javascript"> 2 window.alert = function(text) { 3 //透明遮罩层 4 var mask = document.createElement("div"); 5 mask.style.position = " fixed"; 6 mask.style.zIndex = 1000000; 7 mask.style.top = 0; 8 mask.style.bottom = 0; 9 mask.style.left = 0; 10 mask.style.right = 0; 11 //实现alert 12 var div = document.createElement("div"); 13 div.style.backgroundColor = " #22b9ff"; 14 div.style.color = " #fff"; 15 div.style.position = " fixed"; 16 div.style.zIndex = 9999999; 17 div.style.height = " 60px"; 18 div.style.top = " 10%"; 19 div.style.left = "50%"; 20 div.style.lineHeight = " 60px"; 21 div.style.borderRadius = " 4px"; 22 div.style.fontSize = " 20px"; 23 div.style.textAlign = "center"; 24 div.style.padding = "0 10px"; 25 div.className = "animated bounceInDown"; 26 div.id = "alert"; 27 div.innerHTML = text; 28 document.getElementsByTagName("body")[0].appendChild(div); 29 document.getElementsByTagName("body")[0].appendChild(mask); 30 var selfObj = document.getElementById("alert"); 31 //动态调整位置 32 var alertWidth = window.getComputedStyle(selfObj, null).width; 33 div.style.marginLeft = -parseInt(alertWidth) / 2 + "px"; 34 setTimeout(function() { 35 document.getElementsByTagName("body")[0].removeChild(div); 36 document.getElementsByTagName("body")[0].removeChild(mask); 37 }, 3000); 38 } 39 alert("这是自定义的alert"); 40 </script>
值得一提的是动态位置的调整哪块,通过实时计算alert组件的宽度,保证组件始终处于中间位置,至于alert组件的显示时间,就自己改源代码时间吧。
整体代码如下
1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <meta charset="UTF-8"> 6 <title>自定义alert</title> 7 <style type="text/css"> 8 html, 9 body { 10 padding: 0; 11 margin: 0; 12 } 13 /* //防止鼠标双击选中文字 14 */ 15 16 div { 17 18 -khtml-user-select: none; 19 /*早期浏览器*/ 20 user-select: none; 21 } 22 /* //来自animated.css的样式 */ 23 24 .animated { 25 animation-duration: 1s; 26 animation-fill-mode: both; 27 } 28 29 @keyframes bounceInDown { 30 from, 31 60%, 32 75%, 33 90%, 34 to { 35 animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 36 } 37 38 0% { 39 opacity: 0; 40 transform: translate3d(0, -3000px, 0); 41 } 42 43 60% { 44 opacity: 1; 45 transform: translate3d(0, 25px, 0); 46 } 47 48 75% { 49 transform: translate3d(0, -10px, 0); 50 } 51 52 90% { 53 transform: translate3d(0, 5px, 0); 54 } 55 56 to { 57 transform: none; 58 } 59 } 60 61 .bounceInDown { 62 animation-name: bounceInDown; 63 } 64 65 </style> 66 </head> 67 68 <body> 69 <script type="text/javascript"> 70 (function(win,doc) { 71 var alert = function(text, time, top) { 72 text = text || "确定删除?",time = time || 3000,top = top || "10%";//增加默认值,增强健壮性 73 var body=doc.getElementsByTagName("body")[0];//优化dom 74 //实现alert 75 var div = doc.createElement("div"); 76 div.style.backgroundColor = " #22b9ff"; 77 div.style.color = " #fff"; 78 div.style.position = " fixed"; 79 div.style.zIndex = 9999999; 80 div.style.height = " 60px"; 81 div.style.top = top; 82 div.style.left = "50%"; 83 div.style.lineHeight = " 60px"; 84 div.style.borderRadius = " 4px"; 85 div.style.fontSize = " 20px"; 86 div.style.textAlign = "center"; 87 div.style.padding = "0 10px"; 88 div.className = "animated bounceInDown"; 89 div.id = "alert"; 90 div.innerHTML = text; 91 body.appendChild(div); 92 var selfObj = doc.getElementById("alert"); 93 //动态调整位置 94 var alertWidth = win.getComputedStyle(selfObj, null).width; 95 div.style.marginLeft = -parseInt(alertWidth) / 2 + "px"; 96 setTimeout(function() { 97 body.removeChild(div); 98 }, time); 99 } 100 win.alert=alert;//导出 101 })(window,document); 102 alert(); 103 </script> 104 </body> 105 106 </html>
2018年6月24日更新 增加参数的默认值,该少dom访问慢的问题,使用闭包包裹,alert导出覆盖window
在整体代码中,有一个用来防止双击选中文字的css样式,值得关注一下。
样式中的css动画来自知名的动画库animation.css。因此,可以根据实际业务需要更换动画类。基本就是这样。
仿京东注册web移动端提示。
1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <meta charset="UTF-8"> 6 <title>自定义alert</title> 7 <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0,user-scalable=no" name="viewport" /> 8 <style type="text/css"> 9 html, 10 body { 11 padding: 0; 12 margin: 0; 13 } 14 /* //防止鼠标双击选中文字 15 */ 16 17 div { 18 19 -khtml-user-select: none; 20 /*早期浏览器*/ 21 user-select: none; 22 } 23 /* //来自animated.css的样式 */ 24 25 @-webkit-keyframes fadeIn { 26 0% { 27 opacity: .7 28 } 29 50% { 30 opacity: 1 31 } 32 100% { 33 opacity: .7 34 } 35 } 36 37 .toast { 38 -webkit-animation-name: fadeIn; 39 -webkit-animation-duration: 3s; 40 -webkit-animation-iteration-count: 1; 41 -webkit-animation-delay: 0s; 42 -webkit-transition: all .3s ease; 43 -moz-transition: all .3s ease; 44 transition: all .3s ease; 45 max-width: 80%; 46 color:#fff; 47 background: #2B2B2B; 48 padding: 8px 15px; 49 display: inline-table; 50 border-radius: 3px; 51 } 52 53 .toast-ui { 54 position: fixed; 55 top:20%; 56 color:#fff; 57 width: 100%; 58 text-align: center; 59 } 60 61 .maskfadeout { 62 display: block; 63 -webkit-animation: fadeout 3s linear; 64 animation: fadeout 3s linear; 65 -webkit-animation-iteration-count: 1; 66 animation-iteration-count: 1 67 } 68 69 @-webkit-keyframes fadeout { 70 0%, 71 80% { 72 opacity: 1 73 } 74 100% { 75 opacity: 0 76 } 77 } 78 79 @keyframes fadeout { 80 0%, 81 80% { 82 opacity: 1 83 } 84 100% { 85 opacity: 0 86 } 87 } 88 </style> 89 </head> 90 91 <body> 92 <script type="text/javascript"> 93 (function(win, doc) { 94 var alert = function(text, time, top) { 95 text = text || "确定删除?", time = time || 3000, top = top || "10%"; //增加默认值,增强健壮性 96 var body = doc.getElementsByTagName("body")[0]; //优化dom 97 //实现alert 98 var div = doc.createElement("div"); 99 div.className = "toast-ui maskfadeout"; 100 div.id = "alert"; 101 var span = doc.createElement("span"); 102 span.innerHTML = text; 103 span.className = "toast"; 104 div.appendChild(span); 105 body.appendChild(div); 106 107 setTimeout(function() { 108 div.style.display="none"; 109 }, 3000); 110 } 111 win.alert = alert; //导出 112 })(window, document); 113 alert("是否删除这条评论?"); 114 </script> 115 </body> 116 117 </html>
本文结束。
我站在山顶看风景!下面是我的家乡!