• jQuery attributes(上)


    jQuery attributes提供了文档节点的属性操作方法。

    为了更好的理解,我们先解决jQuery core中的access参数设置函数。

    jQuery.access

    jQuery.access是一个专用于参数设置以及读取的方法。

    jQuery链式操作中我们对BigInteger的值获取是通过方法val来获取的,很显然此时val后面不能再链式操作了。所以:

    如果要读取参数值,那么这个操作就不能链式操作。

    /*************************
     *    elems: 接受操作的元素组
     *    fn: 设置或读取函数
     *    key: 要设置的属性
     *    value: 要设置的值,也可以是函数
     *    chainable: 是否可以链式操作,即是读还是写操作
     *    emptyGet: 读取如果为空用什么表示
     *    raw: value能否直接传给fn,如果的确就是想将属性设置成函数value,那么要把这个值设成true
     */
    jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
        var i = 0,
            length = elems.length,
            //key是否为空
            bulk = key == null;
    
        // 设置许多属性
        if ( jQuery.type( key ) === "object" ) {
            chainable = true;
            for ( i in key ) {
                //迭代执行设置一个值
                jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
            }
    
        // 只设置一个值
        } else if ( value !== undefined ) {
            chainable = true;
    
            //如果value不是函数
            if ( !jQuery.isFunction( value ) ) {
                raw = true;
            }
    
            //如果key为空
            if ( bulk ) {
                // 如果raw为true,即value不是函数
                if ( raw ) {
                    //执行fn,其this为elems,参数为value
                    fn.call( elems, value );
                    fn = null;
    
                // 如果value是函数
                } else {
                    //用bulk保存fn
                    bulk = fn;
                    //将fn变成特定形式
                    fn = function( elem, key, value ) {
                        return bulk.call( jQuery( elem ), value );
                    };
                }
            }
            
            //如果fn存在
            if ( fn ) {
                //遍历所有elems
                for ( ; i < length; i++ ) {
                    //value是函数则运行fn(elem, key, value.call(elem, i, fn(elem, key)))
                    //value非函数则运行fn(elem, key, value)
                    fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
                }
            }
        }
    
        //如果是可链式操作的则返回elems
        return chainable ?
            elems :
    
            // 否则则是读取操作
            bulk ?
                fn.call( elems ) :
                // 否则如果长度不为0,则返回fn( elems[0], key ),否则返回空
                length ? fn( elems[0], key ) : emptyGet;
    }

    jQuery官方文档没有该函数,应该说这是jQuery的一个内部工具。主要是为了实现jQuery中设置与读取复用性逻辑以及其内循环的,也就是为了节省写代码而已。

    jQuery.fn.attr()

    fn也就是jQuery实例对象的方法集。

    fn中的方法attr也就是我们常用的attr方法。

    如获取em标签的title属性:

    var title = $("em").attr("title");

    那么这个函数式怎么实现的呢?

    jQuery.fn.attr = function( name, value ) {
        return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
    };

    当参数长度为0或只为1时,则是读取操作,不能链式操作。

    而这里用的设置函数是jQuery.attr,即实际运行时会运行jQuery.attr(elem, name, value)。

    那么jQuery.attr是如何实现的呢?

    /***************************
     *    elem: 要操作的元素
     *    name: 元素的属性名
     *    value: 要改变的值
     */
    jQuery.attr = function( elem, name, value ) {
        var ret, hooks, notxml,
            nType = elem.nodeType;
    
        // 不处理text,comment,attribute节点
        if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
            return;
        }
    
        // 如果属性不支持则使用jQuery.prop
        if ( typeof elem.getAttribute === "undefined" ) {
            return jQuery.prop( elem, name, value );
        }
    
        //是否不是XML
        notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
    
        // 如果不是XML
        if ( notxml ) {
            //那么所有属性名应当是小写
            name = name.toLowerCase();
            //如果属性定义了,那么就抓住必要的钩子,解决IE6-9的相关问题
            hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
        }
    
        //如果value不是没有定义,即写入操作
        if ( value !== undefined ) {
            //如果value为空,则是删除操作
            if ( value === null ) {
                jQuery.removeAttr( elem, name );
            //如果钩子有set方法,则设置了之后,返回其值
            } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
                return ret;
            //否则使用setAttribute方法
            } else {
                elem.setAttribute( name, value + "" );
                return value;
            }
        //如果是读取操作,如果钩子有get方法,则通过get得到返回值
        } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
            return ret;
        //如果没有get方法
        } else {
    
            // IE9+中Flash对象没有.getAttrubute方法,判断防止错误
            if ( typeof elem.getAttribute !== "undefined" ) {
                ret =  elem.getAttribute( name );
            }
    
            // 返回undefined或则值
            return ret == null ?
                undefined :
                ret;
        }
    };

    jQuery.removeAttr

    removeAttr = function( elem, value ) {
        var name, propName,
            i = 0,
            //分解value成为多个属性的数组
            attrNames = value && value.match( core_rnotwhite );
        
        //如果有要删除的属性名
        if ( attrNames && elem.nodeType === 1 ) {
            //遍历所有属性名
            while ( (name = attrNames[i++]) ) {
                //看看需不需要用propFix来修改名字,不用直接用name
                propName = jQuery.propFix[ name ] || name;
    
                // 如果属性是布尔量先改成false
                if ( rboolean.test( name ) ) {
                    elem[ propName ] = false;
                }
    
                //删除属性
                elem.removeAttribute( name );
            }
        }
    };

    jQuery.propFix干了什么呢?

    实际只是修改一下属性名,比如很多人喜欢用class来表示css类名,但实际上是className。

    jQuery.propFix = {
        tabindex: "tabIndex",
        readonly: "readOnly",
        "for": "htmlFor",
        "class": "className",
        maxlength: "maxLength",
        cellspacing: "cellSpacing",
        cellpadding: "cellPadding",
        rowspan: "rowSpan",
        colspan: "colSpan",
        usemap: "useMap",
        frameborder: "frameBorder",
        contenteditable: "contentEditable"
    };

    jQuery.fn.removeAttr

    这个函数实现比较简单,只是用each方法来调用jQuery.removeAttr而已。

    jQuery.fn.removeAttr = function( name ) {
        return this.each(function() {
            jQuery.removeAttr( this, name );
        });
    };

    jQuery.fn.prop

    jQuery.fn.prop = function( name, value ) {
        return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
    };

    可见jQuery.fn.prop和jQuery.fn.attr差不多。

    jQuery.prop

    jQuery.prop = function( elem, name, value ) {
        var ret, hooks, notxml,
            nType = elem.nodeType;
    
        if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
            return;
        }
    
        notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
    
        if ( notxml ) {
            // 修复name和钩子
            name = jQuery.propFix[ name ] || name;
            hooks = jQuery.propHooks[ name ];
        }
    
        if ( value !== undefined ) {
            if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
                return ret;
    
            } else {
                return ( elem[ name ] = value );
            }
    
        } else {
            if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
                return ret;
    
            } else {
                return elem[ name ];
            }
        }
    };

    由于和jQuery.attr差不多,就不备注了。

    jQuery.fn.removeProp

    removeProp = function( name ) {
        name = jQuery.propFix[ name ] || name;
        return this.each(function() {
            // try/catch handles cases where IE balks (such as removing a property on window)
            try {
                this[ name ] = undefined;
                delete this[ name ];
            } catch( e ) {}
        });
    };

    removeProp相对简单些,只是通过each将所有元素的属性设为undefined然后delete掉而已。

    Attrubute和Property

    从源代码我们可以发现,jQuery.attr如果找不到相应的方法会使用jQuery.prop。

    jQuery 1.6加入jQuery.prop方法后,对很多人来说可能根本没啥用,因为用jQuery.attr方法肯定是对的。

    但jQuery.attr和jQuery.prop到底差别在哪里呢?

    这是Attrubute和Property的差别。

    jQuery.attr方法会处理Attrubute和Property,但jQuery.prop只处理Property。

    虽然这两个单词都可以翻译成“属性”,但是这两个实际上是不同的。

    我们用一个例子来说明这个问题:

    function Demo(){
        var attrs = {};
        this.name = "Bob";
        this.setAttr = function(name, value){
            attrs[name] = value;
            return value;
        }
        this.getAttr = function(name){
            return attrs[name];
        }
    }

    那么对于一个实例:

    var i = new Demo();
    i.name    //Property
    i.setAttr("name", "Tom");
    i.getAttr("name")    //Attrubute

    所以jQuery文档中对jQuery.prop的解释是:获取在匹配的元素集中的第一个元素的属性值。

  • 相关阅读:
    Python Django 编写一个简易的后台管理工具2-创建项目
    leetcode-解题记录 771. 宝石与石头
    leetcode-解题记录 1108. IP 地址无效化
    Python Django 编写一个简易的后台管理工具1-安装环境
    备忘录
    Pollard_rho 因数分解
    ProgrammingContestChallengeBook
    HDU ACM-Steps
    ARCH-LINUX 折(安)腾(装)记
    各种Python小玩意收集
  • 原文地址:https://www.cnblogs.com/justany/p/2867547.html
Copyright © 2020-2023  润新知