【源码解读】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 ...
随机推荐
- 近期一些使用MATLAB常用的代码
背景 最近处理行为学数据和fMRI数据,主要使用MATLAB.有一些常用的代码被自己重复使用,所以在此记录,以便于随时调取使用. 1.PVT原生mat文件→txt文件 遇到在处理一些被试的PVT数据时 ...
- 工具-效率工具-listary快速打开文件,win+R使用(99.1.1)
@ 目录 1.使用WIN+R打开软件 2.使用listary软件 1.使用WIN+R打开软件 添加环境变量 找到需要打开应用的目录 如我的桌面(C:\Users\Public\Desktop) 添加p ...
- Redis集群的分布式部署
3.2.2:Redis Cluster: Redis 分布式部署方案: 1) 客户端分区:由客户端程序决定 key 写分配和写入的 redis node,但是需要客户端自己处理写入 分配.高可用管 ...
- 干货满满,32个常用 Python 实现,你学废了嘛!
1. 冒泡排序 lis = [56,12,1,8,354,10,100,34,56,7,23,456,234,-58] def sortport(): for i in range(len(lis)- ...
- 基于frp的内网穿透实例1-通过SSH访问内网机器
原文地址:https://wuter.cn/1804.html/ 老母鸡终于到了,作为一个能运行linux系统的四核1G硬件,它还是比较小巧的. FRP 全名:Fast Reverse Proxy.F ...
- python序列(五)切片操作
功能:截取列表中的任何部分. 切片适用于列表.元组.字符串.range对象等类型.. 格式:[::]切片使用两个冒号分隔的3个数字来完成. 第一个数字表示切片开始位置(默认为0). 第二个数字表示切片 ...
- 由innodb锁引起的数据库相关
innodb 锁的问题 1.事务 原子性:要么成功,要么失败 一致性:前后数据保持一致状态 隔离性:多个事务并行,相互不影响 持久性:事务提交之后,对数据的影响是永久性的,即使故障也可以保持. 2.并 ...
- 读取平台管理员xlsx文件
package com.cn.peitest.excel; import java.io.File; import java.io.FileInputStream; import java.io.Fi ...
- Eclipse中,No compiler is provided in this environment. Perhaps you are running on a JRE rather than a
问题说明 Eclipse导入Maven项目后,执行 mvn clean install后,出现如下错误: [INFO] ---------------------------------------- ...
- 51 张图助你彻底掌握 HTTP!
前言 如果说 TCP/IP 协议是互联网通信的根基,那么 HTTP 就是其中当之无愧的王者,小到日常生活中的游戏,新闻,大到双十一秒杀等都能看到它的身影,据 NetCraft 统计,目前全球至少有 1 ...