效果以下:css
关闭message后先后message的衔接很是丝滑,这部分是我比较感兴趣的。带着这个问题先了解下DOM结构,顺便整理下做者的思路。react
从DOM里咱们能够看到全部的message都在一个容器里,而这个容器作了绝对定位实现了可视窗口的水平居中,新增的message只要在容器里append对应的元素就会在页面上显示出来。jquery
接下来咱们看下每一个message元素的秘密~数组
咱们能够看到这里设置了height和padding属性的动画,那上文中的动画大几率是在关闭时设置height和padding为0,由于bfc的规则在动画期间先后的message也会挤占其空间,因此看起来比较丝滑。动画执行完成后再将元素remove掉。浏览器
这里注意到一个不太经常使用的css属性:will-change,援引MDN上的表述,这个属性会根据开发者指定的要改变的值提早作优化准备。will-change服务器
其余内部的元素是常见的根据弹框类型和消息进行渲染,再也不进行细究。接下来关注点放到js上。app
引入方式很简单,只有一个js文件svg
代码示例以下:函数
1 // 配置全局默认参数 2 cocoMessage.config({ 3 duration: 10000, 4 }); 5 // 普通消息,可传入自动关闭时间、提示信息、关闭回调 6 cocoMessage.info(3000, "请先登陆!", function () { 7 console.log("close"); 8 }); 9 // 成功消息,可传入element元素 10 var div1 = document.createElement("div"); 11 div1.innerText = "修改为功!"; 12 cocoMessage.success(div1); 13 // 警告消息,时间设置0不会自动关闭 14 cocoMessage.warning("须要手动关闭", 0); 15 // 失败消息 16 cocoMessage.error("修改失败!", 3000); 17 // loading消息 18 var closeMsg = cocoMessage.loading(true); 19 setTimeout(function () { 20 closeMsg(); 21 }, 4000); 22 // 关闭全部消息 23 cocoMessage.destroyAll();
这里咱们可看到支持的类型有info、success、warning、error、loading五种,基本场景都覆盖到了。传参比较灵活,能够一个两个三个,并且类型也不固定。带着这些疑问开始了真正的代码走读,解开它神秘的面纱:性能
首先看下代码结构:
定义了一个兼容的_typeof方法(原谅我没看懂这个兼容逻辑,有明白的兄弟能够在评论区留言);而后是一个常见的当即执行函数,函数前的!和用括号包裹起来的效果同样,常见的还有+-。
传进去两个参数,第一个是void 0(也就是undefined,我的感受用this也没问题,感兴趣的能够了解下),另外一个参数是主体函数,后面会作详细介绍,咱们先看下这个当即执行函数都作了什么:
先检查环境中是否有module.exports再检查define.amd,最后才用全局变量。显然这个是兼容CommonJs规范、AMD/CMD规范和直接引用的写法。其中用global = global || self 的写法而不是window由于能够兼容服务器端(global全局变量)和浏览器端(window全局变量)。这样会在浏览器window变量下暴露cocoMessage变量。另外提一下使用当即执行函数是能够避免污染全局变量的。在进入方法内部前,建议把这部分代码收藏一波
1 !function (global, factory) { 2 (typeof exports === "undefined" ? "undefined" : _typeof(exports)) === "object" && typeof module !== "undefined" ? 3 module.exports = factory() : 4 typeof define === "function" && define.amd ? 5 define(factory) : 6 (global = global || self, global.cocoMessage = factory()); 7 }(void 0, function () { 8 // code here 9 });
刚进入方法会建立msgWrapper变量保存消息父元素,定义默认配置initArgs,暴露cocoMessage变量并在页面元素加载完毕后添加style标签。上图中白色备注是比较通用的方法,下文会将重点放在红色备注的方法上。
首先关注下建立msgWrapper元素的c方法:
第一个参数传输对象,key能够是className来给元素添加class属性,另外一种能够是以_开头能够给元素绑定相应的事件。
第二个参数能够传输文本、元素、包含多个元素的数组(或者伪数组)。
// 建立class为coco-msg-stage的div元素 var msgWrapper = c({ className: "coco-msg-stage" }, "默认消息"); // 建立class为coco-msg-wait并在元素上绑定click事件 c({ className: "coco-msg-wait " , _click: function _click () { if (closable) { closeMsg(el, onClose); } } } // 屡次调用建立复杂元素 c({ className: "coco-msg-stage" }, c({ className: "coco-msg-loading", _click: function(){ console.log("loading") } }) );
共有info、success、warning、error、loading、destoryAll、config这七个方法,这也正是这个插件想要暴露给用户的。默认参数中消息是空字符串,关闭时间是2s,不会显示关闭按钮,固然这些均可以经过config方法修改全局的默认配置,从中也能够看到随时能够修改配置,即时生效。除去destoryAll方法咱们先关注下消息的5中类型,建立方法大同小异:都是经过initConfig方法建立的。其中arguments是伪数组,也就是咱们调用info等方法传递的全部参数,能够经过通数组同样角标方式取值。loading方法是特殊的,把initConfig方法的结果返回了,经过demo咱们知道返回值是个方法,执行后会关闭loading,下文咱们再关注下loading类型的消息有什么特殊处理,开始进入initConfig方法。
这里仅是对参数进行统一,上文中有个疑问,为何参数能够随便传,并且顺序不一致也不影响?答案就在这个方法里,以前传的参数有提示信息:字符串(string类型)或元素(Element或object类型)、延迟时间:数字(number类型)、关闭后的回调:方法(function类型)、是否显示关闭按钮(boolean类型)。到这里应该发现这里的玄机了,每一个参数都有惟一的类型并且还不会冲突,这样就能够根据传参类型的不一样识别传的值了。封装后的对象大体以下:
{ msg: "提示消息", type: "info", showClose: false, duration: 2000, onClose: function(){ console.log("closed") } }
虽然以上方法设计得很巧妙,可是健壮性要差一些,若是要扩展设置文字是否居中、自定义类名、自定义图标等功能时难免会要进行重构。因此调用方法改为这样会便于扩展:
cocoMessage.info({ msg: '请先登陆', duracion: '2000', showClose: true, onClose: function(){ console.log('closed') } });
到这一步须要的参数封装完成了,接下来会调用createMsgEl方法建立消息元素。
方法较长分为两个部分,完成了根据传入的参数建立元素并添加到body中显示出来,并绑定关闭按钮的点击事件和触发自动关闭的条件。图中画问好的正是上文中咱们存疑的问题,正由于这里返回了关闭消息的方法就能够实现执行后关闭loading。
到这里还剩closeMsg方法和destoryAll方法,咱们先看closeMsg:
首先会设置padding和height为0,进而实现开头说的动画效果,而后执行自定义的关闭回调方法。最后再删除消息元素,若是没有消息也会把父元素一并删除。须要注意的是这里还会判断消息元素是否存在,这并非冗余的代码,而是考虑到点击按钮关闭和执行所有关闭一块儿执行时后触发的会报错的问题,由于这里有300ms的延迟。
最后是destoryAll方法,关闭全部消息。
获取父元素全部的消息元素再循环调用closeMsg方法进行删除。