jQuery的XX如何实现?——2.show与链式调用

往期回顾:

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

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

源码链接:内附实例代码

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

下面将使用简化的代码来介绍,主要关注jQuery的实现思想~>_<~

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

 1 (function(window, undefined){
 2
 3     function jQuery(sel){
 4         return new jQuery.prototype.init(sel);
 5     }
 6
 7     jQuery.prototype = {
 8         constructor: jQuery,
 9         init: function(sel){
10             if(typeof sel === ‘string‘){
11                 var that = this;
12                 var nodeList = document.querySelectorAll(sel);
13                 Array.prototype.forEach.call(nodeList, function(val, i){
14                     that[i] = val;
15                 })
16                 this.selector = sel;
17                 this.length = nodeList.length;
18             }
19         },
20
21         show: function(){
22             Array.prototype.forEach.call(this, function(node){
23                 //if(node.style) continue; //textnode没有style
24
25                 //删除style上的display:none
26                 var display = node.style.display;
27                 if(display === ‘none‘){
28                     //dispaly置为空后,css如果有display则css的生效
29                     //否则默认的生效
30                     node.style.display = ‘‘;
31                 }
32
33                 //元素display值为非默认值情况,需要还原为oldDisplay:div->display:inline-block
34                 //或 检测css上的display是否为none
35                 if(node.style.display===‘‘ || isHidden(node)){
36                     //有oldDispaly则设置
37                     if(node.oldDisplay) node.style.display = node.oldDisplay;
38                     //没有则设置为元素默认值或元素当前值
39                     else node.style.display = getDisplay(node);
40                 }
41             })
42
43             //链式调用
44             return this;
45         },
46
47         hide: function(){
48             Array.prototype.forEach.call(this, function(node){
49                 if(!isHidden(node)) {
50                     //jQuery使用其cache机制存储信息,这里简化一下
51                     //直接挂载在对应的dom下
52                     node.oldDisplay = getDisplay(node);
53                     node.style.display = ‘none‘;
54                 }
55             })
56
57             return this;
58         }
59     }
60
61     function getDisplay(node){
62         var display = window.getComputedStyle(node, null).getPropertyValue(‘display‘);
63
64         if(display === ‘none‘){
65             var dom = document.createElement(node.nodeName);
66             //插入到body中
67             document.body.appendChild(dom);
68             //即可获取到元素display的默认值
69             var display = window.getComputedStyle(dom, null).getPropertyValue(‘display‘);
70             document.body.removeChild(dom);
71         }
72         return display;
73     }
74
75     function isHidden(node) {
76         //忽略未append进document的元素这种隐藏情况:$(‘<div>block</div>‘)未append
77         return window.getComputedStyle(node, null).getPropertyValue(‘display‘) === ‘none‘;
78     }
79
80     jQuery.prototype.init.prototype = jQuery.prototype;
81
82     window.$ = jQuery;
83 })(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处保存原来的值不就行了吗?就像以下的代码:

52 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;
}

然后,综合这两种情况:

36 //有oldDispaly则设置
37 if(node.oldDisplay) node.style.display = node.oldDisplay;
38 //没有则设置为元素默认值或元素当前值
39 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函数变成了这鬼样ψ(╰_╯)。大致思路如下:

21 show: function(){
22     Array.prototype.forEach.call(this, function(node){
23         //if(node.style) continue; //textnode没有style
24
25         //删除style上的display:none
26         var display = node.style.display;
27         if(display === ‘none‘){
28             //dispaly置为空后,css如果有display则css的生效
29             //否则默认的生效
30             node.style.display = ‘‘;
31         }
32
33         //元素display值为非默认值情况,需要还原为oldDisplay:div->display:inline-block
34         //或 检测css上的display是否为none
35         if(node.style.display===‘‘ || isHidden(node)){
36             //有oldDispaly则设置
37             if(node.oldDisplay) node.style.display = node.oldDisplay;
38             //没有则设置为元素默认值或当前值
39             else node.style.display = getDisplay(node);
40         }
41     })
42 }

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

链式调用就是类似这种情况:$(‘div‘).show().hide().css(‘height‘,‘300px‘).toggle()

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

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

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

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

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

div{ display:none !important; }

<div>大家自己开脑洞,怎么处理吧(⊙0⊙)</div>
时间: 2024-10-14 13:49:29

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

jquery设计思想之写法-方法函数化&amp;链式操作

1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta http-equiv="

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

啦啦!今天又学了一招,js写几十行的tab标签页jquery写一行就行啦,用到了链式操作!以下是代码: <!DOCTYPE html> <html lang="en"> <head> <style> *{ padding: 0; margin: 0; } ul{ list-style-type: none; } #ul{ height: 30px; margin-bottom: 10px; } #ul li { height: 30px;

通过JavaScript中的链式方法实现JQuery的链式调用

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>实现JQuery的链式调用</title> </head> <body> <script> function A(){} A.prototype.v = 2; A.prototype.set = function(num)

实现函数,类似jQuery链式调用.

1 var origin = [ 2 {id:1,title:'title1'}, 3 {id:2,title:'abcd'}, 4 {id:3,title:'title2'}, 5 {id:4,title:'efg'} 6 ]; 7 8 var find = function(data){ 9 // your code here 10 } 11 12 var result = find(origin).where({'title':/\d$/}).order('id','desc'); //d

jQuery特性效果与链式调用

1.显示效果 <!doctype html><html><head><meta charset="utf-8"><title>特殊效果</title><script type="text/javascript" src="../jQuery库/jquery-3.3.1.min.js"></script><script type="tex

jQuery的链式调用原理,Promise的链式调用,this的问题

最近被问到这个问题,jq的链式调用原理,当时比较懵=.=,毕竟现在jq接触的机会变很少了. jq的链式调用 jq的链式调用其实就是比如我们在选择dom的时候, $('input[type="button"]') .eq(0).click(function() { alert('点击我!'); }).end().eq(1) .click(function() { $('input[type="button"]:eq(0)').trigger('click'); }).

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

源码链接:内附实例代码 jQuery使用许久了,但是有一些API的实现实在想不通.于是抽空看了jQuery源码,现在把学习过程中发现的一些彩蛋介绍给大家(⊙0⊙). 下面将使用简化的代码来介绍,主要关注jQuery的实现思想~>_<~ 1 //匿名立即执行函数 2 //1.防止污染全局空间 3 //2.选择性保护内部变量 4 (function(window, undefined){ 5 //第二参数undefined设置而不传的原因: 6 // 外部发生这种情况:var undefined

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

往期回顾: jQuery的XX如何实现?——1.框架 jQuery的XX如何实现?——2.show与链式调用 jQuery的XX如何实现?——3.data与cache机制 -------------------------- 源码链接:内附实例代码 jQuery使用许久了,但是有一些API的实现实在想不通.于是抽空看了jQuery源码,现在把学习过程中发现的一些彩蛋介绍给大家(⊙0⊙). 下面将使用简化的代码来介绍,主要关注jQuery的实现思想~>_<~ 相较于第一篇(与第二.三篇无相关性)

简述jQuery的链式操作

首先,两个问题: JQuery的链式操作是如何实现的? 为什么要用链式操作? 怎样使用链式操作? 原理百度上面一大把,我也不能很好的解释,不过它的用法很简单: 关键就在于对象里的方法有:return this.这就是说调用了方法之后把对象给返回了回来,不就可以继续调用方法了吗?所以链式操作就这样实现了.举个栗子: //定义一个类 function Obj(){} //扩展它的原型 Obj.prototype = { setName:function(name){ this.name = name