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;
            }
        });
    }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值