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 相关文章推荐
跨浏览器的事件对象介绍
Jun 27 Javascript
JavaScript中的分号插入机制详细介绍
Feb 11 Javascript
JS简单实现多级Select联动菜单效果代码
Sep 06 Javascript
jQuery EasyUI Accordion可伸缩面板组件使用详解
Feb 28 Javascript
node.js+jQuery实现用户登录注册AJAX交互
Apr 28 jQuery
JavaScript实现body内任意节点的自定义属性功能示例
Sep 18 Javascript
JavaScript原生实现观察者模式的示例
Dec 15 Javascript
React中常见的动画实现的几种方式
Jan 10 Javascript
使用proxy实现一个更优雅的vue【推荐】
Jun 19 Javascript
bootstrap模态框弹出和隐藏,动态改变中间内容的实例
Aug 10 Javascript
js数组去重的方法总结
Jan 18 Javascript
解决使用layui的时候form表单中的select等不能渲染的问题
Sep 18 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
PHP Zip解压 文件在线解压缩的函数代码
2010/05/26 PHP
php使用fputcsv()函数csv文件读写数据的方法
2015/01/06 PHP
PHP callback函数使用方法和注意事项
2015/01/23 PHP
表单提交时自动复制内容到剪贴板的js代码
2007/03/16 Javascript
JavaScript使用过程中需要注意的地方和一些基本语法
2010/08/26 Javascript
jQuery获取注册信息并提示实现代码
2013/04/21 Javascript
下拉列表选择项的选中在不同浏览器中的兼容性问题探讨
2013/09/18 Javascript
jQuery 如何先创建、再修改、后添加DOM元素
2014/05/20 Javascript
贴近用户体验的Jquery日期、时间选择插件
2015/08/19 Javascript
jQuery on()方法绑定动态元素的点击事件实例代码浅析
2016/06/16 Javascript
vue2.0使用Sortable.js实现的拖拽功能示例
2017/02/21 Javascript
微信小程序实战篇之购物车的实现代码示例
2017/11/30 Javascript
swiper移动端轮播插件(触碰图片之后停止轮播)
2017/12/28 Javascript
使用vue制作探探滑动堆叠组件的实例代码
2018/03/07 Javascript
vue组件实现弹出框点击显示隐藏效果
2020/10/26 Javascript
python在Windows8下获取本机ip地址的方法
2015/03/14 Python
python3 实现验证码图片切割的方法
2018/12/07 Python
Python爬虫库BeautifulSoup的介绍与简单使用实例
2020/01/25 Python
python map比for循环快在哪
2020/09/21 Python
python 实现倒计时功能(gui界面)
2020/11/11 Python
pycharm 多行批量缩进和反向缩进快捷键介绍
2021/01/15 Python
HTML5 canvas基本绘图之绘制矩形
2016/06/27 HTML / CSS
英国在线发型和美容产品商店:Beauty Cutie
2019/04/27 全球购物
Farfetch澳大利亚官网:Farfetch Australia
2020/04/26 全球购物
临床医学大学生求职信
2013/09/28 职场文书
医学专业毕业生个人的求职信
2013/12/04 职场文书
建筑行业的大学生自我评价
2013/12/08 职场文书
24岁生日感言
2014/01/13 职场文书
《一个中国孩子的呼声》教学反思
2014/02/12 职场文书
医学生自我鉴定范文
2014/03/26 职场文书
村干部群众路线整改措施思想汇报
2014/10/12 职场文书
2014年少先队工作总结
2014/12/03 职场文书
幸福家庭事迹材料
2014/12/20 职场文书
党建工作目标管理责任书
2015/01/29 职场文书
关于考试抄袭的检讨书
2019/11/02 职场文书
React更新渲染原理深入分析
2022/12/24 Javascript