往期回顾:

jQuery的XX如何实现?——1.框架

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

源码链接:内附实例代码

jQuery使用许久了,但是有一些API的实现实在想不通。于是抽空看了jQuery源码,现在把学习过程中发现的一些彩蛋介绍给大家(⊙0⊙)。

下面将使用简化的代码来介绍,主要关注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函数变成了这鬼样ψ(╰_╯)。大致思路如下:

 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>

jQuery的XX如何实现?——2.show与链式调用的更多相关文章

  1. 如何一行jquery代码写出tab标签页(链式操作)

    啦啦!今天又学了一招,js写几十行的tab标签页jquery写一行就行啦,用到了链式操作!以下是代码: <!DOCTYPE html> <html lang="en&quo ...

  2. mark jquery 链式调用的js原理

    我们在使用jquery的时候会用到类似$("#id").css('color','red').show(200); 这样写有点减少代码量,减少了逐步查询DOM的性能损耗: js 原 ...

  3. jQuery链式调用

    <script> var arr = function(){ return new arr.prototype.init(); } arr.prototype.init = functio ...

  4. jQuery的XX如何实现?——4.类型检查

    往期回顾: jQuery的XX如何实现?——1.框架 jQuery的XX如何实现?——2.show与链式调用 jQuery的XX如何实现?——3.data与cache机制 -------------- ...

  5. jQuery的XX如何实现?——1.框架

    源码链接:内附实例代码 jQuery使用许久了,但是有一些API的实现实在想不通.于是抽空看了jQuery源码,现在把学习过程中发现的一些彩蛋介绍给大家(⊙0⊙). 下面将使用简化的代码来介绍,主要关 ...

  6. jQuery链式操作[转]

    用过jQuery的朋友都知道他强大的链式操作,方便,简洁,易于理解,如下 $("has_children").click(function(){ $(this).addClass( ...

  7. 仿jQuery之链式调用

    链式调用的形式其实就是对象调用一连串的方法.为什么能连续调用这么多的方法?因为调用方法返回调用的对象,于是乎就可以一如既往,一往无前地调用下去.链式调用的原理就是在方法中返回执行上下文this,每次调 ...

  8. 模拟jquery底层链式编程

    //特点1:快级作用域,程序启动自动执行 //内部的成员变量,外部无法访问(除了var) //简单的函数链式调用 function Dog(){ this.run=function(){ alert( ...

  9. jQuery的XX如何实现?——3.data与cache机制

    往期回顾: jQuery的XX如何实现?——1.框架 jQuery的XX如何实现?——2.show与链式调用 -------------------------- 源码链接:内附实例代码 jQuery ...

随机推荐

  1. VC++ 标准C++中的string类的用法总结

    相信使用过MFC编程的朋友对CString这个类的印象应该非常深刻吧?的确,MFC中的CString类使用起来真的非常的方便好用.但是如果离开了MFC框架,还有没有这样使用起来非常方便的类呢?答案是肯 ...

  2. Keynote of Python III

    [Keynote of Python III] 1.许多大型网站是用Python开发的,例如YouTube.Instagram,还有国内的豆瓣.很多大公司,包括Google.Yahoo等,甚至NASA ...

  3. 【C#】 一些不常用,很容易混淆的知识点

    [C#] 一些不常用但很容易混淆的知识点 1. 访问修饰符 internal ,译为内部的, 在同一个程序集中可访问,它的内部是相对与程序集的,可不能想当然了 2. String.Compare 这个 ...

  4. samba的简单用法总结

    前两天在弄LDAP+samba管理账号的东西,发现对samba的配置不太了解,就拿鸟哥的书看看,嘿嘿,结合自己的一些理解,记录下来. samba主要是实现windos可以共享Linux的东西 1:查看 ...

  5. Filter过滤器简单应用( 接口访问控制 )

    一.描述 在提供安卓.IOS客户端接口时,可以在登陆接口分配Session给客户端,用于判断其他接口是否是合法访问,以避免将所有的接口都暴露在web中可以由路径直接访问.但是最近的一个项目中的移动接口 ...

  6. coursera 机器学习课程 GraphLab环境准备

    在网上看到coursera有机器学习的课程,正好再学习学习,温固一下,还有很多其他的课程也很好.收费的哟! 手机APP和网站收取的费用有差异,网站上要便宜一下,费用差的挺多的,果断在网站上支付了. 有 ...

  7. 01背包问题:POJ3624

    背包问题是动态规划中的经典问题,而01背包问题是最基本的背包问题,也是最需要深刻理解的,否则何谈复杂的背包问题. POJ3624是一道纯粹的01背包问题,在此,加入新的要求:输出放入物品的方案. 我们 ...

  8. Data Base MongoDB 无法创建抽象类的问题,

     无法创建抽象类BsonClassMap.RegisterClassMap 大家都知道抽象类是无法实例化的,即:不能new. 在以下这些情况会遇到这种问题: 1.基类是抽象类: 2.基类是接口: 由于 ...

  9. Linux云服务器安装tomcat

    安装tomcat需要安装JDK 1.上传 把下载好的tomcat压缩包(apache-tomcat-7.0.tar.gz)和jdk(jdk-7u76-linux-x64.tar.gz)压缩包上传到/u ...

  10. 基于PHP使用rabbitmq实现消息队列

    1.从github上面获取AMQP基于php的实现扩展 2.创建生产者 send.php   3.创建消费者 receive.php 4.在cli模式下 分别执行 send.php  receive. ...