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 相关文章推荐
javascript编程起步(第四课)
Feb 27 Javascript
面向对象继承实例(a如何继承b问题)(自写)
Jul 01 Javascript
jQuery函数map()和each()介绍及异同点分析
Nov 08 Javascript
Node.js node-schedule定时任务隔多少分钟执行一次的方法
Feb 10 Javascript
JS+DIV+CSS排版布局实现美观的选项卡效果
Oct 10 Javascript
分享我的jquery实现下拉菜单心的
Nov 29 Javascript
jQuery实现CheckBox全选、全不选功能
Jan 11 Javascript
利用Vue.js实现checkbox的全选反选效果
Jan 18 Javascript
JS正则表达式完美实现身份证校验功能
Oct 18 Javascript
微信小程序实现多宫格抽奖活动
Apr 15 Javascript
javascript设计模式 ? 迭代器模式原理与用法实例分析
Apr 17 Javascript
JavaScript 接口原理与用法实例详解
May 12 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
几种显示数据的方法的比较
2006/10/09 PHP
PHP 类相关函数的使用详解
2013/05/10 PHP
PHP+Mysql+jQuery中国地图区域数据统计实例讲解
2015/10/10 PHP
PHP实现长文章分页实例代码(附源码)
2016/02/03 PHP
简单的JS多重继承示例
2008/03/13 Javascript
jquery 简单导航实现代码
2009/09/11 Javascript
javascript new后的constructor属性
2010/08/05 Javascript
深入理解JavaScript系列(3) 全面解析Module模式
2012/01/15 Javascript
js内存泄露的几种情况详细探讨
2013/05/31 Javascript
在JavaScript中使用JSON数据
2016/02/15 Javascript
javascript高级选择器querySelector和querySelectorAll全面解析
2016/04/07 Javascript
js阻止浏览器默认行为触发的通用方法(推荐)
2016/05/15 Javascript
简单总结JavaScript中的String字符串类型
2016/05/26 Javascript
分享jQuery封装好的一些常用操作
2016/07/28 Javascript
AngularJS 单元测试(二)详解
2016/09/21 Javascript
javascript实现去除HTML标签的方法
2016/12/26 Javascript
基于JavaScript实现本地图片预览
2017/02/08 Javascript
JavaScript EventEmitter 背后的秘密 完整版
2018/03/29 Javascript
vue-mugen-scroll组件实现pc端滚动刷新
2019/08/16 Javascript
JavaScript实现抖音罗盘时钟
2019/10/11 Javascript
简单使用webpack打包文件的实现
2019/10/29 Javascript
JavaScript实现好看的跟随彩色气泡效果
2020/02/06 Javascript
python模块之time模块(实例讲解)
2017/09/13 Python
Python基础学习之类与实例基本用法与注意事项详解
2019/06/17 Python
python 解决flask uwsgi 获取不到全局变量的问题
2019/12/22 Python
Django DRF APIView源码运行流程详解
2020/08/17 Python
Django返回HTML文件的实现方法
2020/09/17 Python
浅析python函数式编程
2020/09/26 Python
初中校园广播稿
2014/02/02 职场文书
贷款委托书范本
2014/04/08 职场文书
解除劳动合同协议书
2014/04/14 职场文书
小学教师师德师风演讲稿
2014/08/22 职场文书
社区宣传标语口号
2015/12/26 职场文书
幼儿园师德师风心得体会
2016/01/12 职场文书
SpringDataJPA在Entity中常用的注解介绍
2021/12/06 Java/Android
苹果可能正在打击不进行更新的 App
2022/04/24 数码科技