jQuery源碼學習(四)

隊列queue()

隊列(先進先出)方法,執行順序的管理。

<script type="text/javascript">
    //大體框架
    //隊列其實就是一個數組
    jQuery.extend([//工具方法
        queue//相當於數組的push操作-往數組的後面添加數據   入隊操作
        dequeue//相當於數組的shift操作-從數組的前面取數據    出隊操作
        _queueHooks
        ]);
    jQuery.fn.extend([//實例方法
        queue //入隊
        dequeue //出隊
        delay //延遲隊列
        clearQueue //清除隊列
        promise //隊列全部執行完後再執行
        ]);
    </script>

隊列的基本使用

隊列中存的都是函數
隊列操作存儲的必須是函數,因爲在出隊的時候會對函數進行操作
工具方法操作:

<script type="text/javascript" src="../../jquery-2.1.4.js"></script>
    <script type="text/javascript">
    $(function(){
        function fn1(){
            alert(111);
        }
        function fn2(){
            alert(222);
        }
        //工具方法操作
        $.queue(document,'q1',fn1);
        $.queue(document,'q1',fn2);//三個參數分別表示添加隊列的對象、隊列名稱和隊列中的函數數據
        //也可以整體添加
        //$.queue(document,'q1',[fn1,fn2]);
        console.log($.queue(document,'q1'));//[function, function]
        $.dequeue(document,'q1');//111  出隊操作-從隊列中取出第一個函數並執行,而不是僅僅取出來
        //進行了一次出隊操作後,數組就減少一項。只剩下[fn2]
        $.dequeue(document,'q1');//222  出隊操作-從隊列中取出第一個函數並執行
    });
    </script>

實例操作:

<script type="text/javascript" src="../../jquery-2.1.4.js"></script>    
    <script type="text/javascript">
    $(function(){
        function fn1(){
            alert(111);
        }
        function fn2(){
            alert(222);
        }
        //實例操作
        $(document).queue('q1',fn1);//入隊操作
        $(document).queue('q1',fn2);
        console.log($.queue(document,'q1'));//[function, function]
        $(document).dequeue('q1');//111
        $(document).dequeue('q1');//222
    });
    </script>

在jQuery中queue主要是針對動畫操作的,與運動有關
Demo:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>queue</title>
    <style type="text/css">
        div{
            width: 100px;
            height: 100px;
            background-color: red;
            position: absolute;
        }
    </style>
</head>
<body>
    <div id="#div1"></div>
    <script type="text/javascript" src="../../jquery-2.1.4.js"></script>
    <script type="text/javascript">
    $(function(){
        $('div').click(function(){
            $(this).animate({ //通過開啓一個定時器setInterval來不斷改變寬度
                width:300
            },2000);
            $(this).animate({//通過開啓一個定時器setInterval來不斷改變高度
                height:300
            },2000);
            $(this).animate({//通過開啓一個定時器setInterval來不斷改變left值
                left:300
            },2000);
        });
    });
    </script>
</body>
</html>

當動畫開始之前將三個定時器放到queue的隊列數組中[setInterval1,setInterval2,setInterval3],然後調用dequeue出隊,從前往後依次執行。
queue也可以對異步進行管理(定時器就是異步的),而且可以對多個異步進行管理
deferred是針對單個異步操作的
注意:在隊列操作中,如果不進行出隊操作,則隊列後面的操作永遠不會執行。
Demo:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>queue</title>
    <style type="text/css">
        div{
            width: 100px;
            height: 100px;
            background-color: red;
            position: absolute;
        }
    </style>
</head>
<body>
    <div id="#div1"></div>
    <script type="text/javascript" src="../../jquery-2.1.4.js"></script>
    <script type="text/javascript">
    $(function(){
        $('div').click(function(){
        $(this).animate(
        {width:300},2000).queue('fx',function(){
//這裏沒有出隊操作,後面的操作都不會執行,只會改變寬度值,不會改變高度值
            }).animate({height:300},2000);
        });
    });
    </script>
    <script type="text/javascript">
    $(function(){
        $('div').click(function(){
//fx爲默認的隊列名稱,可以省略
$(this).animate({width:300},2000).queue('fx',function(next){
        //$(this).dequeue();//出隊操作 可以進行後續操作
            next();//和上面的代碼功能一樣,都是出隊操作
            }).animate({height:300},2000);
        });
    });
    </script>
</body>
</html>

queue與回調的區別

回調是不可控制的
queue是可以控制的,想什麼出隊就什麼時候出隊

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>queue</title>
    <style type="text/css">
        div{
            width: 100px;
            height: 100px;
            background-color: red;
            position: absolute;
        }
    </style>
</head>
<body>
    <div id="#div1"></div>
    <script type="text/javascript" src="../../jquery-2.1.4.js"></script>
    <script type="text/javascript">
    $(function(){
        $('div').click(function(){
            $(this).animate({width:300},2000,function(){
                $(this).css('left',300);
            }).animate({height:300},2000);
        });
    });
    </script>
    <script type="text/javascript">
    $(function(){
        $('div').click(function(){
            $(this).animate({width:300},2000,function(){
                var that = this;
                //因爲定時器是異步的
                //這裏使用回調函數不會影響後續動畫的執行
                //所以回調裏面的運動會和後面的運動一起發生
                var timer = setInterval(function(){
                    that.style.left = that.offsetLeft + 1 + 'px';
                    if(that.offsetLeft == 200){
                        clearInterval(timer);
                    }
                },30);
            }).animate({height:300},2000);
        });
    });
    </script>
    <script type="text/javascript">
    $(function(){
        $('div').click(function(){
            $(this).animate({width:300},2000).queue(function(next){
                //這裏使用queue,保證left改變完成後再出隊
                //如果永遠不出隊,後面的操作永遠不會執行
                var that = this;
                var timer = setInterval(function(){
                    that.style.left = that.offsetLeft + 1 + 'px';
                    if(that.offsetLeft == 200){
                        next();//這裏當left改變完成後再出隊
                        //可以控制異步的執行順序
                        clearInterval(timer);
                    }
                },30);
            }).animate({height:300},2000);
        });
    });
    </script>
</body>
</html>

delay是延遲隊列執行

<body>
    <div id="#div1"></div>
    <script type="text/javascript" src="../../jquery-2.1.4.js"></script>
    <script type="text/javascript">
    $(function(){
        $('div').click(function(){
            //delay是延遲隊列執行  
                    $(this).animate({width:300},2000).delay(2000).animate({height:300},2000);
        });
    });
    </script>
</body>

promise()隊列全部執行完後再執行

<body>
    <div id="#div1"></div>
    <script type="text/javascript" src="../../jquery-2.1.4.js"></script>
    <script type="text/javascript">
    $(function(){
        $('div').click(function(){
            //隊列全部執行完後再執行
                    $(this).animate({width:300},2000).animate({height:300},2000);
$(this).promise().done(function(){//隊列執行完畢後彈123
                alert(123);
            });
        });
    });
    </script>
</body>

源碼部分

//隊列(先進先出)方法
//執行順序的管理
jQuery.extend({
    //接收三個參數:要添加對列的對象、隊列名稱和函數數據
    //入隊
    queue: function( elem, type, data ) {
        var queue;
        if ( elem ) //當元素存在時進行後續操作
            //type || "fx"  取自定義的隊列名或者默認的fx
            type = ( type || "fx" ) + "queue";
            //data_priv數據緩存對象
            queue = data_priv.get( elem, type );

            // Speed up dequeue by getting out quickly if this is just a lookup
            if ( data ) {
                if ( !queue || jQuery.isArray( data ) ) {
                    //jQuery.isArray( data )當data是數組時,重新進行設置隊列
                    queue = data_priv.access( elem, type, jQuery.makeArray(data) );
                } else {
                    queue.push( data );
                }
            }
            return queue || [];
        }
    },
    //出隊
    dequeue: function( elem, type ) {
        type = type || "fx";
        var queue = jQuery.queue( elem, type ),//獲取隊列數組
            startLength = queue.length,//隊列長度
            fn = queue.shift(),//獲取數組第一項
            hooks = jQuery._queueHooks( elem, type ),
            next = function() {//next就是執行出隊操作
                jQuery.dequeue( elem, type );//出隊操作
            };
        // If the fx queue is dequeued, always remove the progress sentinel
        if ( fn === "inprogress" ) {
            fn = queue.shift();
            startLength--;
        }
        if ( fn ) {

            // Add a progress sentinel to prevent the fx queue from being
            // automatically dequeued
            if ( type === "fx" ) {
                queue.unshift( "inprogress" );
            }

            // clear up the last queue stop function
            delete hooks.stop;
            fn.call( elem, next, hooks );
        }

        if ( !startLength && hooks ) {
            hooks.empty.fire();
        }
    },

    // not intended for public consumption - generates a queueHooks object, or returns the current one
    _queueHooks: function( elem, type ) {
        var key = type + "queueHooks";
        return data_priv.get( elem, key ) || data_priv.access( elem, key, {
            empty: jQuery.Callbacks("once memory").add(function() {
                data_priv.remove( elem, [ type + "queue", key ] );
            })
        });
    }
});
//擴展實例方法
jQuery.fn.extend({
    //入隊
    queue: function( type, data ) {
        var setter = 2;

        if ( typeof type !== "string" ) {
            data = type;
            type = "fx";
            setter--;
        }
        //根據參數長度來判斷是應該獲取還是設置
        if ( arguments.length < setter ) {
            return jQuery.queue( this[0], type );
        }

        return data === undefined ?
            this :
            this.each(function() {
                var queue = jQuery.queue( this, type, data );

                // ensure a hooks for this queue
                jQuery._queueHooks( this, type );
                //inprogress是針對動畫的第一次出隊操作
                if ( type === "fx" && queue[0] !== "inprogress" ) {
                    jQuery.dequeue( this, type );
                }
            });
    },
    //出隊
    dequeue: function( type ) {
        return this.each(function() {
            jQuery.dequeue( this, type );
        });
    },
    // Based off of the plugin by Clint Helfers, with permission.
    // http://blindsignals.com/index.php/2009/07/jquery-delay/
    // 延遲隊列
    delay: function( time, type ) {
        time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
        type = type || "fx";

        return this.queue( type, function( next, hooks ) {
            //next就是出隊
            var timeout = setTimeout( next, time );
            hooks.stop = function() {
                clearTimeout( timeout );
            };
        });
    },
    //清除隊列
    clearQueue: function( type ) {
        return this.queue( type || "fx", [] );
    },
    // Get a promise resolved when queues of a certain type
    // are emptied (fx is the type by default)
    // 隊列全部執行完後再執行
    promise: function( type, obj ) {
        var tmp,
            count = 1,
            defer = jQuery.Deferred(),
            elements = this,
            i = this.length,
            resolve = function() {
                if ( !( --count ) ) {
                    defer.resolveWith( elements, [ elements ] );
                }
            };

        if ( typeof type !== "string" ) {
            obj = type;
            type = undefined;
        }
        type = type || "fx";
        while( i-- ) {
            tmp = data_priv.get( elements[ i ], type + "queueHooks" );
            if ( tmp && tmp.empty ) {
                count++;
                tmp.empty.add( resolve );
            }
        }
        resolve();
        return defer.promise( obj );
    }
});

元素屬性的操作

  • attr() 獲取匹配的元素集合中的第一個元素相應屬性的值或設置每一個匹配元素的一個或多個屬性值。(接收兩個參數是設置操作,接收一個參數是獲取操作)
    Demo:
<body>
    <div id="box" title="盒子1">111111</div>
    <div id="box" title="盒子2">222222</div>
    <div id="box" title="盒子3">333333</div>
    <script type="text/javascript" src="../../jquery-2.1.4.js"></script>
    <script type="text/javascript">
    $(function(){
        $("div").attr('title','盒子');//這個是設置所有div的title屬性值爲盒子
        alert($("div").attr('title'));//這個只會獲取到第一個div的title屬性值
        });
    </script>
</body>
  • prop() 獲取匹配的元素集合中第一個元素的屬性(property)值或設置每一個匹配元素的一個或多個屬性。
  • removeAttr() 爲匹配的元素集合中的每個元素中移除一個屬性(attribute)。
  • removeProp() 爲集合中匹配的元素刪除一個屬性(property)。
  • val() 獲取匹配的元素集合中第一個元素的當前值或設置匹配的元素集合中每個元素的值

attr和prop的基本用法

<body>
    <div id="box">111111</div>
    <script type="text/javascript" src="../../jquery-2.1.4.js"></script>
    <script type="text/javascript">
    $(function(){
        $("#box").attr('title','hello');//兩個參數是設置
        alert($("#box").attr('id'));//box  1個參數是獲取
        //原生實現
        var oDiv = document.getElementById("box");
        oDiv.setAttribute('title','hello');
        oDiv.getAttribute('title');

// attr在原生js是基於setAttribute和getAttribute來實現的
// prop是基於dot(.)和方括號語法[]來實現的
        //原生實現
        var oDiv = document.getElementById("box");
        oDiv.title = 'hello';
        oDiv['title'] = 'hello';
        $("#box").prop('title','hello');//兩個參數是設置
        alert($("#box").prop('id'));//box  1個參數是獲取
    });
    </script>
</body>
<body>
    <div id="box" title="盒子1">111111</div>
    <div id="box" title="盒子2">222222</div>
    <div id="box" title="盒子3">333333</div>
    <script type="text/javascript" src="../../jquery-2.1.4.js"></script>
    <script type="text/javascript">
    $(function(){
        $("div").attr('title','盒子');//這個是設置所有div的title屬性值爲盒子
        alert($("div").attr('title'));//這個只會獲取到第一個div的title屬性值
        });
    </script>
</body>

attr和prop的區別

<body>
    <div id="box">111111</div>
    <a href="hello.html" id="link"></a>
    <input type="checkbox" name="" value="" checked="checked">
    <script type="text/javascript" src="../../jquery-2.1.4.js"></script>
    <script type="text/javascript">
    $(function(){
        //獲取鏈接的href屬性值也不一樣
        console.log($("#link").attr('href'));//hello.html
        console.log($("#link").prop('href'));//file:///C:/Users/lj/Desktop/%E6%88%91%E7%9A%84%E5%89%8D%E7%AB%AF%E5%AD%A6%E…%E5%85%83%E7%B4%A0%E5%B1%9E%E6%80%A7%E7%9A%84%E6%93%8D%E4%BD%9C/hello.html

        $("#link").removeAttr('href');
        alert($("#link").attr('href'));//undefined
        $("#link").removeAttr('id');
        alert($("#link").attr('id'));//undefined
        $("#link").removeProp('id');//不會刪除掉
        alert($("#link").prop('id'));//link

        alert($('input').attr('checked'));//checked
        alert($('input').prop('checked'));//true
    });
    </script>
</body>

對於自定義屬性,attr起作用,prop不起作用。

<body>
<div id="box" muke="學前端">111111</div>
<script type="text/javascript" src="../../jquery-2.1.4.js"></script>
<script type="text/javascript">
//設置自定義屬性,attr起作用,prop不起作用
$("#box").attr('muke','學前端');
$("#box").prop('muke','學前端');//不起作用

//獲取自定義屬性
alert($("#box").attr('muke'));//可以獲取到
alert($("#box").prop('muke'));//undefined 獲取不到
</script>
</body>

attr()和prop()方法分別取的是節點的attribute值、property值

實例方法

  • jQuery.prototype.attr
  • jQuery.prototype.prop
  • jQuery.prototype.removeAttr
  • jQuery.prototype.removeProp
  • jQuery.prototype.val
    源碼部分:
attr: function( name, value ) {
        //this當前的元素
        //jQuery.attr對應回調函數
        //name和value就是屬性和值
        //arguments.length > 1判斷是讀取還是設置,1個參數是讀取,兩個參數是設置
        //實例attr實際操作的是工具方法jQuery.attr
        //下面方法也都是調用的工具方法
        return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
    },
    prop: function( name, value ) {
        return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
    }

attr()和prop()實際上是調用jQuery.access()方法。jQuery.access主要作用是修正參數。access函數裏的第二個參數jQuery.attr. 這個參數的作用是告訴access方法, 修正完參數後再去調用 靜態方法jQuery.attr()。
實例方法都是調用最終的靜態方法來實現的
access方法最後把參數又傳遞給了jQuery.attr, 在jQuery.attr裏才真正進行setAttribute和getAttribute操作.
access源碼部分:

//多功能值操作(內部)
    //chainable控制設置或者獲取
    access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
        var i = 0,
            length = elems.length,
            bulk = key == null;

        // Sets many values
        // 設置多組值
        if ( jQuery.type( key ) === "object" ) {
            chainable = true;
            for ( i in key ) {
                jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
            }

        // Sets one value
        } else if ( value !== undefined ) {
            chainable = true;

            if ( !jQuery.isFunction( value ) ) {
                raw = true;
            }

            if ( bulk ) {
                // Bulk operations run against the entire set
                //是字符串
                if ( raw ) {
                    fn.call( elems, value );
                    fn = null;

                // ...except when executing function values
                //是函數
                } else {
                    bulk = fn;
                    fn = function( elem, key, value ) {
                        return bulk.call( jQuery( elem ), value );
                    };
                }
            }

            if ( fn ) {
                for ( ; i < length; i++ ) {
                    fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
                }
            }
        }
        //chainable爲真是設置
        //爲假就是獲取  
        return chainable ?
            elems :

            // Gets
            bulk ?
                fn.call( elems ) :
                length ? fn( elems[0], key ) : emptyGet;
    }
<body>
    <div id="box" muke="學前端" class="div">111111</div>
    <script type="text/javascript" src="../../jquery-2.1.4.js"></script>
    <script type="text/javascript">
    $(function(){
        //可以同時刪除多個屬性和屬性值
        //attrNames = value && value.match( core_rnotwhite );
        //value.match( core_rnotwhite )返回一個數組
        //["id","muke","class"]
        $("div").removeAttr("id muke class");
    });
    </script>
</body>

addClass、removeClass、toggleClass和hasClass

基本用法:

<body>
    <div id="box" class="box1 box2">111111</div>
    <script type="text/javascript" src="../../jquery-2.1.4.js"></script>
    <script type="text/javascript">
    $(function(){
        //添加類名
        $("#box").addClass("box3");
        //添加多個類名
        $("#box").addClass("box3 box4");
        // 特別注意空字符串和空格字符串不一樣
        alert(Boolean(""));//false
        // 空格字符串會返回真
        alert(Boolean(" "));//true
    });
    </script>
</body>
<body>
    <div id="box">111111</div>
    <div id="box">222222</div>
    <div id="box">333333</div>
    <script type="text/javascript" src="../../jquery-2.1.4.js"></script>
    <script type="text/javascript">
    $(function(){
        // addClass()支持回調函數的形式,這種形式用的少
        $("div").addClass(function(index){
            // alert(index);//0
            return 'box'+index;//這裏根據index的不同,添加不同的class
        });
    });
    </script>
</body>
<body>
    <div id="box" class="box1 box2">111111</div>
    <script type="text/javascript" src="../../jquery-2.1.4.js"></script>
    <script type="text/javascript">
    $(function(){
        //如果removeClass()中什麼都不寫,則會將class屬性值清空
        //相當於全部刪除的操作
        $("#box").removeClass();
    });
    </script>
</body>
<body>
    <div id="box" class="box1 box2">111111</div>
    <script type="text/javascript" src="../../jquery-2.1.4.js"></script>
    <script type="text/javascript">
    $(function(){
        //toggleClass()有相應的class則刪除,沒有就添加
        //這是接收一個參數的情況
        $("#box").toggleClass("box3");
        // 這裏會刪除box2,添加box3
        $("#box").toggleClass("box2 box3");
        //接收兩個參數
        //true表示不管原來元素有沒有相應的class,都會進行添加操作
        //這樣一來toggleClass()就變成了添加操作
        //添加第二個參數true後,box2和box3都會添加
        $("#box").toggleClass("box2 box3",true);
        // 當第二個參數爲false時,box2和box3都會刪除
        $("#box").toggleClass("box2 box3",false);
    });
    </script>
</body>
<body>
    <div id="box" class="box1 box2">111111</div>
    <script type="text/javascript" src="../../jquery-2.1.4.js"></script>
    <script type="text/javascript">
    $(function(){
        //只傳遞一個布爾值,false表示全部刪除class
        //這裏會先將所有的class保存在一個緩存數據中,方便在需要的時候再添加回來
        $("#box").toggleClass(false);
        //重新添加
        $("#box").toggleClass(true);
    });
    </script>
</body>

源碼部分:

//添加class,實例方法
    addClass: function( value ) {
        var classes, elem, cur, clazz, j,
            i = 0,
            len = this.length,//緩存操作元素的個數
            //如果value是字符串,則直接返回這個字符串
            //這裏之所以判斷是不是字符串,是因爲addClass()還支持參數是回調函數的形式
            proceed = typeof value === "string" && value;
        //這裏就是判斷參數是不是函數
        if ( jQuery.isFunction( value ) ) {
            return this.each(function( j ) {
                //j就是當前的索引值
                jQuery( this ).addClass( value.call( this, j, this.className ) );
            });
        }
        //判斷proceed是否爲真
        //爲真,則是字符串類型
        if ( proceed ) {
            // The disjunction here is for better compressibility (see removeClass)
            // match( core_rnotwhite )進行正則分割,分割成數組
            // $("#box").addClass("box3 box4");
            // 分割成[box3,box4]
            // 支持同時添加多個類名,添加多個類名前需要先用空格分割一下
            classes = ( value || "" ).match( core_rnotwhite ) || [];
            //循環添加
            for ( ; i < len; i++ ) {
                elem = this[ i ];//獲取到相應的元素
                //elem.nodeType === 1判斷是不是元素節點
                //elem.className判斷元素的class屬性中有沒有值,有值就獲取到,沒有值則返回空格字符串
                //rclass = /[\t\r\n\f]/g,是一個正則
                cur = elem.nodeType === 1 && ( elem.className ?
                    ( " " + elem.className + " " ).replace( rclass, " " ) :
                    " "
                );
                //空格字符串會返回真
                if ( cur ) {
                    j = 0;
                    //classes是要添加的的class
                    //cur是當前元素已經存在的class
                    //(clazz = classes[j++])依次取到要添加的class
                    //cur.indexOf()調用indexOf()方法判斷當前元素中是否存在相應的class
                    while ( (clazz = classes[j++]) ) {
                        //返回-1則表示沒有相應的class,可以添加
                        if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
                            cur += clazz + " ";
                        }
                    }
                    elem.className = jQuery.trim( cur );//去空格

                }
            }
        }
        //jQuery的鏈式操作就是通過返回this來實現的
        return this;
    },
    //刪除class
    removeClass: function( value ) {
        var classes, elem, cur, clazz, j,
            i = 0,
            len = this.length,
            //與操作先於或操作執行
            //arguments.length === 0是什麼都不傳的情況,會清空class的所有屬性值
            proceed = arguments.length === 0 || typeof value === "string" && value;

        if ( jQuery.isFunction( value ) ) {
            return this.each(function( j ) {
                jQuery( this ).removeClass( value.call( this, j, this.className ) );
            });
        }
        if ( proceed ) {
            classes = ( value || "" ).match( core_rnotwhite ) || [];

            for ( ; i < len; i++ ) {
                elem = this[ i ];
                // This expression is here for better compressibility (see addClass)
                cur = elem.nodeType === 1 && ( elem.className ?
                    ( " " + elem.className + " " ).replace( rclass, " " ) :
                    ""
                );

                if ( cur ) {
                    j = 0;
                    while ( (clazz = classes[j++]) ) {
                        // Remove *all* instances
                        while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
                            //這裏是當存在要刪除的class時,將其替換爲空格字符串
                            cur = cur.replace( " " + clazz + " ", " " );
                        }
                    }
                    elem.className = value ? jQuery.trim( cur ) : "";
                }
            }
        }
        return this;
    },
    //切換
    //toggleClass可以接收兩個參數
    toggleClass: function( value, stateVal ) {
        var type = typeof value;

        if ( typeof stateVal === "boolean" && type === "string" ) {
            //當stateVal爲真就調用添加,爲假就調用刪除
            return stateVal ? this.addClass( value ) : this.removeClass( value );
        }
        //也支持回調函數的形式
        if ( jQuery.isFunction( value ) ) {
            return this.each(function( i ) {
                jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
            });
        }

        return this.each(function() {
            if ( type === "string" ) {
                // toggle individual class names
                var className,
                    i = 0,
                    self = jQuery( this ),
                    classNames = value.match( core_rnotwhite ) || [];

                while ( (className = classNames[ i++ ]) ) {
                    // check each className given, space separated list
                    // 判斷當前元素是否包含相應的class
                    // 有就刪除,沒有就添加
                    if ( self.hasClass( className ) ) {
                        self.removeClass( className );
                    } else {
                        self.addClass( className );
                    }
                }

            // Toggle whole class name
            // 平時用的很少
            // 是隻給toggleClass(布爾值)傳遞一個布爾值的情況
            } else if ( type === core_strundefined || type === "boolean" ) {
                if ( this.className ) {
                    // store className if set
                    // 將class存起來
                    data_priv.set( this, "__className__", this.className );
                }
                // If the element has a class name or if we're passed "false",
                // then remove the whole classname (if there was one, the above saved it).
                // Otherwise bring back whatever was previously saved (if anything),
                // falling back to the empty string if nothing was stored.
                this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";
            }
        });
    },
    //判斷有沒有相應的class
    hasClass: function( selector ) {
        var className = " " + selector + " ",
            i = 0,
            l = this.length;
        for ( ; i < l; i++ ) {
            //this[i].className是獲取到當前元素的class值
            //使用indexOf()方法判斷是否存在相應的class,存在返回true,不存在返回false
            if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
                return true;
            }
        }
        return false;
    }

val方法

<body>
<input type="text" name="" value="請輸入" id="input1">
<select multiple>
<option value="哈哈">1111</option>
<option>2222</option>
<option>3333</option>
</select>
<select>
<option>1111</option>
<option>2222</option>
<option>3333</option>
</select>
<input type="checkbox" name="" value="" id="check">
<script type="text/javascript" src="../../jquery-2.1.4.js"></script>
<script type="text/javascript">
$(function(){
alert($("#input1").val());//獲取value值
$("#input1").val("修改value值");//設置value值

alert($("#check").get(0).type);//checkbox
// 下拉菜單類型可以有單選可多選兩種
alert($("select").get(0).type);//select-multiple
alert($("select").get(1).type);//select-one
alert($("select").get(0).nodeName);//SELECT

//因爲option沒有type操作,但是有nodeName
alert($("option").eq(0).get(0).type);//undefined
alert($("option").eq(0).get(0).nodeName);//OPTION
alert($("option").eq(0).get(0).value);//1111  說明默認的value值就是option的內容

$("#check").click(function(){
    alert($("select").eq(0).val());
});
});
</script>
</body>

源碼部分:

//獲取屬性值方法
    val: function( value ) {
        var hooks, ret, isFunction,
            elem = this[0];//獲取第一個元素
            //因爲獲取操作都是針對集合中的第一個元素
            //arguments.length等於0則是獲取操作
        if ( !arguments.length ) {//獲取
            if ( elem ) {
                //先獲取元素的elem.type類型
                //或者獲取元素的elem.nodeName.toLowerCase()節點類型的小寫形式
                //valHooks:option select radio checkbox只有這四個
                //所以對於select-multiple和select-one都無法找到,這樣就需要獲取相應元素的nodeName
                //select的nodeName是SELECT,轉爲小寫就是select
                //對於option select我們取的是相應的nodeName
                //對於radio checkbox我們取的是相應的elem.type
                hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
                if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
                    return ret;
                }
                //如果沒有兼容性,則直接獲取value值
                ret = elem.value;
                return typeof ret === "string" ?
                    // handle most common string cases
                    ret.replace(rreturn, "") :
                    // handle cases where value is null/undef or number
                    ret == null ? "" : ret;
            }
            return;
        }
        //判斷value是不是函數
        isFunction = jQuery.isFunction( value );
        return this.each(function( i ) {
            var val;
            //只有元素才能夠添加value值
            if ( this.nodeType !== 1 ) {
                return;
            }
            //如果value函數,則走下面的回調進行處理
            if ( isFunction ) {
                val = value.call( this, i, jQuery( this ).val() );
            } else {//如果不是函數,則進行簡單的賦值就可以了
                val = value;
            }
            // Treat null/undefined as ""; convert numbers to string
            //這裏是將元素的value值變爲""
            if ( val == null ) {
                val = "";
            }
            //如果傳一個數字進來,則會將數字轉爲字符串
            else if ( typeof val === "number" ) {
                val += "";
            }
            //如果傳的是一個數組
            else if ( jQuery.isArray( val ) ) {
                //則針對數組中的每一項進行判斷,並返回一個新數組
                val = jQuery.map(val, function ( value ) {
                    //如果value == null則返回""
                    //爲數字,則將數字轉爲字符串
                    return value == null ? "" : value + "";
                });
            }

            hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];

            // If set returns undefined, fall back to normal setting
            if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
                this.value = val;
            }
        });
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章