【源码解读】js原生消息提示插件
效果如下:

关闭message后前后message的衔接非常丝滑,这部分是我比较感兴趣的。带着这个问题先了解下DOM结构,顺便整理下作者的思路。

从DOM里我们可以看到所有的message都在一个容器里,而这个容器做了绝对定位实现了可视窗口的水平居中,新增的message只要在容器里append对应的元素就会在页面上显示出来。
接下来我们看下每个message元素的秘密~

我们可以看到这里设置了height和padding属性的动画,那上文中的动画大概率是在关闭时设置height和padding为0,因为bfc的规则在动画期间前后的message也会挤占其空间,所以看起来比较丝滑。动画执行完成后再将元素remove掉。
这里注意到一个不太常用的css属性:will-change,援引MDN上的表述,这个属性会根据开发者指定的要改变的值提前做优化准备。will-change
其他内部的元素是常见的根据弹框类型和消息进行渲染,不再进行细究。接下来关注点放到js上。
引入方式很简单,只有一个js文件
代码示例如下:
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方法进行删除。
【源码解读】js原生消息提示插件的更多相关文章
- fastclick.js源码解读分析
阅读优秀的js插件和库源码,可以加深我们对web开发的理解和提高js能力,本人能力有限,只能粗略读懂一些小型插件,这里带来对fastclick源码的解读,望各位大神不吝指教~! fastclick诞生 ...
- 消息提示插件toastr.js与Messenger组件
Toastr是一款基于jQuery的通知插件,可以灵活的自定义样式和拓展其功能! toastr是一个基于Jquery简单.漂亮的消息提示插件,使用简单.方便,可以根据设置的超时时间自动消失. cdn最 ...
- js便签笔记(10) - 分享:json2.js源码解读笔记
1. 如何理解“json” 首先应该意识到,json是一种数据转换格式,既然是个“格式”,就是个抽象的东西.它不是js对象,也不是字符串,它只是一种格式,一种规定而已. 这个格式规定了如何将js对象转 ...
- js便签笔记(10) - 分享:json.js源码解读笔记
1. 如何理解“json” 首先应该意识到,json是一种数据转换格式,既然是个“格式”,就是个抽象的东西.它不是js对象,也不是字符串,它只是一种格式,一种规定而已. 这个格式规定了如何将js对象转 ...
- Mybatis源码解读-插件
插件允许对Mybatis的四大对象(Executor.ParameterHandler.ResultSetHandler.StatementHandler)进行拦截 问题 Mybatis插件的注册顺序 ...
- php-msf 源码解读【转】
php-msf: https://github.com/pinguo/php-msf 百度脑图 - php-msf 源码解读: http://naotu.baidu.com/file/cc7b5a49 ...
- 从koa-session源码解读session本质
前言 Session,又称为"会话控制",存储特定用户会话所需的属性及配置信息.存于服务器,在整个用户会话中一直存在. 然而: session 到底是什么? session 是存在 ...
- React16源码解读:开篇带你搞懂几个面试考点
引言 如今,主流的前端框架React,Vue和Angular在前端领域已成三足鼎立之势,基于前端技术栈的发展现状,大大小小的公司或多或少也会使用其中某一项或者多项技术栈,那么掌握并熟练使用其中至少一种 ...
- Vue 源码解读(8)—— 编译器 之 解析(上)
特殊说明 由于文章篇幅限制,所以将 Vue 源码解读(8)-- 编译器 之 解析 拆成了上下两篇,所以在阅读本篇文章时请同时打开 Vue 源码解读(8)-- 编译器 之 解析(下)一起阅读. 前言 V ...
随机推荐
- sychronized的实现原理和应用
一.synchronized的使用 1.1修饰方法 public synchronized void method() { // todo } 1.2修饰代码块 public void run() { ...
- Qt QChart 创建图表
Qt QChart 创建图表 @ 目录 Qt QChart 创建图表 效果 流程 代码 1. 饼图 2. 柱图 3. 折/曲线图 4. 区域图 效果 流程 graph LR q(value 数据) q ...
- Spring Cloud Alibaba基础教程-Nacos(二)
在Spring Cloud Alibaba基础教程-Nacos(一)当中学习了,如何从 nacos当中 通过Java的方式获取值,以及连接数据库,下面我们开始第二篇的学习 ,如果对你有帮助,方便下次寻 ...
- 部署docker镜像仓库及高可用
下载地址: https://github.com/goharbor/harbor/releases 安装harbor服务器: 安装harbor root@harbor-vm1:/usr/loc ...
- 基于nginx负载均衡及frp的内网穿透实例3-多用户多网站共用80端口
原文地址:点击跳转 最近frp用户量有点多,而且很多用户都是想把部署于本地或者内网的web服务暴露至公网,之前提到过,暴露到公网之后如果一般都需要用域名:端口的方法来访问,但是没有人会喜欢用这种方式访 ...
- Netty源码解析 -- PoolChunk实现原理(jemalloc 3的算法)
前面文章已经分享了Netty如何实现jemalloc 4算法管理内存. 本文主要分享Netty 4.1.52之前版本中,PoolChunk如何使用jemalloc 3算法管理内存. 感兴趣的同学可以对 ...
- select * from 多张表的用法
select * from 多张表的用法 其实就是 inner join select * from Class c,Student s where c.ClassID=s.ClassID ...
- Keil4 uVision软件生成hex文件
keil4下载地址:http://www.pc6.com/softview/SoftView_236836.html 按图操作即可,注意文件夹选择. 1.选择工程,选择第一个new uvision p ...
- 一次mongo查询不存在字段引发的事故
话说今天的一个小小的查询失误给了我比较深刻的教训,也让我对mongo有了更深刻的理解,下面我们来说说这个事情的原委: 我们经常使用阿里云子账号在DMS上查询线上数据库数据,今天也是平常的一次操作 集合 ...
- tep0.6.0更新聊聊pytest变量接口用例3个级别复用
tep是一款测试工具,在pytest测试框架基础上集成了第三方包,提供项目脚手架,帮助以写Python代码方式,快速实现自动化项目落地.fixture是pytest核心技术,本文聊聊如何使用fixtu ...