jQuery链式调用与show知识浅析


Posted in Javascript onMay 11, 2016

上篇文章给大家介绍了jQuery的框架,有关jquery的基础知识可以参考下。

jQuery使用许久了,但是有一些API的实现实在想不通。下面将使用简化的代码来介绍,主要关注jQuery的实现思想。

相较于上一篇,代码更新了:21~78

(function(window, undefined){
function jQuery(sel){
return new jQuery.prototype.init(sel);
}
jQuery.prototype = {
constructor: jQuery,
init: function(sel){
if(typeof sel === 'string'){
var that = this;
var nodeList = document.querySelectorAll(sel);
Array.prototype.forEach.call(nodeList, function(val, i){
that[i] = val;
})
this.selector = sel;
this.length = nodeList.length;
}
},
show: function(){
Array.prototype.forEach.call(this, function(node){
//if(node.style) continue; //textnode没有style
//删除style上的display:none
var display = node.style.display;
if(display === 'none'){
//dispaly置为空后,css如果有display则css的生效
//否则默认的生效
node.style.display = '';
}
//元素display值为非默认值情况,需要还原为oldDisplay:div->display:inline-block
//或 检测css上的display是否为none
if(node.style.display==='' || isHidden(node)){
//有oldDispaly则设置
if(node.oldDisplay) node.style.display = node.oldDisplay;
//没有则设置为元素默认值或元素当前值
else node.style.display = getDisplay(node);
}
})
//链式调用
return this;
},
hide: function(){
Array.prototype.forEach.call(this, function(node){
if(!isHidden(node)) {
//jQuery使用其cache机制存储信息,这里简化一下
//直接挂载在对应的dom下
node.oldDisplay = getDisplay(node);
node.style.display = 'none';
}
})
return this;
}
}
function getDisplay(node){
var display = window.getComputedStyle(node, null).getPropertyValue('display');
if(display === 'none'){
var dom = document.createElement(node.nodeName);
//插入到body中
document.body.appendChild(dom);
//即可获取到元素display的默认值
var display = window.getComputedStyle(dom, null).getPropertyValue('display');
document.body.removeChild(dom);
}
return display;
}
function isHidden(node) {
//忽略未append进document的元素这种隐藏情况:$('<div>block</div>')未append
return window.getComputedStyle(node, null).getPropertyValue('display') === 'none';
}
jQuery.prototype.init.prototype = jQuery.prototype;
window.$ = jQuery;
})(window);

先拿hide函数热身一下。如上篇提到的,jQuery会将获取到的nodeList处理成数组,所以一上来,我们用forEach处理数组里的每一个node节点。

接下来,我们只需要将每一个节点的style.display置为'none'即可隐藏。很简单,对吧?(⊙0⊙) 。oldDisplay和return this先不管?( ̄? ̄)?

hide: function(){
Array.prototype.forEach.call(this, function(node){
if(!isHidden(node)) {
//jQuery使用其cache机制存储信息,这里简化一下
//直接挂载在对应的dom下
node.oldDisplay = getDisplay(node);
node.style.display = 'none';
}
})
return this;
}

其中isHidden是判断该元素是否隐藏:已经隐藏的元素就没必要再去处理了,直接跳过

function isHidden(node) {
//忽略未append进document的元素这种隐藏情况:$('<div>block</div>')未append
return window.getComputedStyle(node, null).getPropertyValue('display') === 'none';
}

--------------------------

接下来,来个稍繁琐的show。先抛出一个问题来引发一系列问题:

hide某个元素只需要将display:none,那么show呢?

display:block不就行了吗?这样确实可以将元素显示出来。但是万一元素原来的值是display:inline呢?

那在hide处保存原来的值不就行了吗?就像以下的代码:

node.oldDisplay = getDisplay(node);

要是执行show前没有不执行hide呢?比如下面这种情况,不就没有oldDisplay了吗(⊙0⊙)

<style>
div{ display:none; }
</style>
<div>display:none</div>$('div').show()

好,关键的地方到了:我们获取元素display的默认值就可以了吧?比如div默认是block,span默认是inline。

思路有了,那么接下来的问题是:如何获取元素display的默认值

嘿嘿嘿,想不到吧?这里需要用点小技巧,大体思路如下:通过nodeName创建一个新的标签,再获取。

有个地方可以再优化一下,getDisplay获取到元素display默认值后,可以使用jQuery的cache机制存起来(实际上jQuery也是这么做了)。

function getDisplay(node){
var display = window.getComputedStyle(node, null).getPropertyValue('display');
if(display === 'none'){
var dom = document.createElement(node.nodeName);
//插入到body中
document.body.appendChild(dom);
//即可获取到元素display的默认值
var display = window.getComputedStyle(dom, null).getPropertyValue('display');
document.body.removeChild(dom);
}
return display;
}

然后,综合这两种情况:

//有oldDispaly则设置
if(node.oldDisplay) node.style.display = node.oldDisplay;
//没有则设置为元素默认值或元素当前值
else node.style.display = getDisplay(node);

以为这样就结束了?NO,show函数的情况还是挺复杂的,我们大致要应对这几种情况:

<style>
#none,#none2{ display: none; }
</style>
<body>
<div id="div">默认值为block</div>
<span id="span">默认值为inline</span>
<div id="div2" style="display:inline-block;">修改为inline-block</div>
<div id="none">通过css隐藏了</div>
<div id="none2" style="display:none">通过css和style隐藏了</div>
</body>

最终,show函数变成了这鬼样ψ(?_?)。大致思路如下:

jQuery链式调用与show知识浅析

show: function(){
Array.prototype.forEach.call(this, function(node){
//if(node.style) continue; //textnode没有style
//删除style上的display:none
var display = node.style.display;
if(display === 'none'){
//dispaly置为空后,css如果有display则css的生效
//否则默认的生效
node.style.display = '';
}
//元素display值为非默认值情况,需要还原为oldDisplay:div->display:inline-block
//或 检测css上的display是否为none
if(node.style.display==='' || isHidden(node)){
//有oldDispaly则设置
if(node.oldDisplay) node.style.display = node.oldDisplay;
//没有则设置为元素默认值或当前值
else node.style.display = getDisplay(node);
}
})
}

--------------------------

链式调用就是类似这种情况:

$('div').show().hide().css('height','300px').toggle()

实现起来非常简单,只要在每个函数后面return this即可

--------------------------

有同学说:喂!这个show,hide不对吧?是不是漏了时间参数? 用setTimeOut自己实现吧~>_<~+。

本节最主要是让大家知道jQuery需要考虑的情况非常多(很多脏活)。即时简化了代码,依然还是这么长。

写完后,发现show还有一种情况没考虑:

div{ display:none !important; }
<div>大家自己开脑洞,怎么处理吧(⊙0⊙)</div>
Javascript 相关文章推荐
JQuery中使用on方法绑定hover事件实例
Dec 09 Javascript
angularJS与bootstrap结合实现动态加载弹出提示内容
Oct 16 Javascript
jQuery实现页面顶部显示的进度条效果完整实例
Dec 09 Javascript
AngularJS 中文API参考手册
Jul 28 Javascript
jquery获取点击控件的绝对位置简单实例
Oct 13 Javascript
JavaScript中数组Array方法详解
Feb 27 Javascript
Vue.js结合Ueditor富文本编辑器的实例代码
Jul 11 Javascript
使用Node.js搭建静态资源服务详细教程
Aug 02 Javascript
微信小程序中实现手指缩放图片的示例代码
Mar 13 Javascript
vue生命周期实例小结
Aug 15 Javascript
详解小程序开发经验:多页面数据同步
May 18 Javascript
vue中更改数组中属性,在页面中不生效的解决方法
Oct 30 Javascript
[原创]Javascript 实现广告后加载 可加载百度谷歌联盟广告
May 11 #Javascript
Extjs4.0 ComboBox如何实现三级联动
May 11 #Javascript
javascript简单判断输入内容是否合法的方法
May 11 #Javascript
解析JavaScript面向对象概念中的Object类型与作用域
May 10 #Javascript
JavaScript根据CSS的Media Queries来判断浏览设备的方法
May 10 #Javascript
JavaScript中的原型prototype完全解析
May 10 #Javascript
简单解析JavaScript中的__proto__属性
May 10 #Javascript
You might like
第十四节 命名空间 [14]
2006/10/09 PHP
php基础知识:类与对象(2) 自动加载对象
2006/12/13 PHP
PHP无限分类的类
2007/01/02 PHP
PHP中的日期处理方法集锦
2007/01/02 PHP
PHP脚本中include文件出错解决方法
2008/11/20 PHP
ThinkPHP框架整合微信支付之JSAPI模式图文详解
2019/04/09 PHP
jQuery.getScript加载同域JS的代码
2012/02/13 Javascript
关闭ie窗口清除Session的解决方法
2014/01/10 Javascript
Javascript 绘制 sin 曲线过程附图
2014/08/21 Javascript
jquery点击缩略图切换视频播放特效代码分享
2015/09/15 Javascript
浏览器环境下JavaScript脚本加载与执行探析之动态脚本与Ajax脚本注入
2016/01/19 Javascript
AngularJS框架的ng-app指令与自动加载实现方法分析
2017/01/04 Javascript
Angular 5.0 来了! 有这些大变化
2017/11/15 Javascript
移动端吸顶fixbar的解决方案详解
2019/07/17 Javascript
TypeScript之调用栈的实现
2019/12/31 Javascript
python读取浮点数和读取文本文件示例
2014/05/06 Python
python绘图库Matplotlib的安装
2014/07/03 Python
Python 字符串大小写转换的简单实例
2017/01/21 Python
python3实现windows下同名进程监控
2018/06/21 Python
python儿童学游戏编程知识点总结
2019/06/03 Python
Python解决pip install时出现的Could not fetch URL问题
2019/08/01 Python
python对常见数据类型的遍历解析
2019/08/27 Python
Pyqt5自适应布局实例
2019/12/13 Python
pytorch ImageFolder的覆写实例
2020/02/20 Python
Python3安装模块报错Microsoft Visual C++ 14.0 is required的解决方法
2020/07/28 Python
Django框架请求生命周期实现原理
2020/11/13 Python
HTML5的结构和语义(4):语义性的内联元素
2008/10/17 HTML / CSS
世界领先的以旅馆为主的在线预订平台:Hostelworld
2016/10/09 全球购物
购买200个世界上最好的内衣品牌:Bare Necessities
2017/02/11 全球购物
编程实现当输入某产品代码则打印出该产品记录的功能
2014/05/03 面试题
linux面试题参考答案(5)
2016/11/05 面试题
银行实习自我鉴定
2013/10/12 职场文书
会计学自我鉴定
2014/02/06 职场文书
大学生在校学习的自我评价
2014/02/18 职场文书
2016个人先进事迹材料范文
2016/03/01 职场文书
2017年大学生寒假社会实践活动总结
2016/04/06 职场文书