jQ的html属性操作【前篇】
发布在# 菜鸟解读 jQuery #2014年5月27日view:6501
在文章任何区域双击击即可给文章添加【评注】!浮到评注点上可以查看详情。

本篇介绍关于 html属性 的操作
$.attr(), $().attr(), $.removeAttr(), $().removeAttr()
这个api使用的时候很简单,但是jQ内部考虑到了很多兼容性和纠正的处理;

jQuery.fn.extend({
    attr: function( name, value ) {
        //这里就是对每个元素调用 jQuery.attr,
        //如果value是一个对象的话: 批量设置,则进行遍历对象然后再设置单个key,val
        return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
    },
    removeAttr: function( name ) {
        //遍历元素,逐个进行删除
        //这种不支持对象参数,支持字符串切割
        return this.each(function() {
            jQuery.removeAttr( this, name );
        });
    }
});
var rclass = /[\n\t\r]/g,
    rspace = /\s+/,
    rreturn = /\r/g,
    rtype = /^(?:button|input)$/i,
    rfocusable = /^(?:button|input|object|select|textarea)$/i,
    rclickable = /^a(?:rea)?$/i,
    rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
    getSetAttribute = jQuery.support.getSetAttribute,
    nodeHook, boolHook, fixSpecified;
jQuery.extend({
    attrFn: {
        val: true,
        css: true,
        html: true,
        text: true,
        data: true,
        width: true,
        height: true,
        offset: true
    },
    //设置读取元素的html属性
    attr: function( elem, name, value, pass ) {
        var ret, hooks, notxml,
            nType = elem.nodeType;
        //不能对 文本节点[3],注释节点[8],属性节点[2] 进行属性的设置/读取
        if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
            return;
        }
        //如果pass是true && jQ存在与name命名相同的fn,则调用
        //jQuery.attrFn是在前面定义的对象,这里做的映射
        if ( pass && name in jQuery.attrFn ) {
            return jQuery( elem )[ name ]( value );
        }
        //不支持getAttribute,则使用jQuery.prop进行dom属性的操作
        if ( typeof elem.getAttribute === "undefined" ) {
            return jQuery.prop( elem, name, value );
        }
        //元素不是一个xml对象
        notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
        if ( notxml ) {
            //转成小写,html属性都是小写的
            name = name.toLowerCase();
            // jQuery.attrHooks = {type:,value:,tabindex:};
            // rboolean: bool值修改方法;
            // nodeHook: 是针对ie6,7的一系列修正,
            // 下一篇讲解
            // a || ( b ? c : d )
            hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
        }
        if ( value !== undefined ) {
            if ( value === null ) {
                // $.attr(elem,key,null); 则做删除html属性操作
                jQuery.removeAttr( elem, name );
                return;
            //如果需要使用修正方法,则调用修正对象方法
            }else if( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ){
                return ret;
            //没有修正则调用原生的setAttribute
            } else {
                elem.setAttribute( name, "" + value );
                return value;
            }
        //如果有修正,则调用修正对象的方法
        } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
            return ret;
        //调用原生的 getAttribute
        } else {
            ret = elem.getAttribute( name );
            //不应该存在返回null的时候,如果存在则修正为 undefined
            return ret === null ? undefined : ret ;
        }
    },
    //删除html属性
    removeAttr: function( elem, value ) {
        var propName, attrNames, name, l, isBool,
            i = 0;
        //检测是dom元素
        if ( value && elem.nodeType === 1 ) {
            //按照空格进行拆分
            attrNames = value.toLowerCase().split( rspace );
            l = attrNames.length;
            for ( ; i < l; i++ ) {
                name = attrNames[ i ];
                if ( name ) {
                    // 取出修正的dom属性
                    propName = jQuery.propFix[ name ] || name;
                    // boolean值元素
                    isBool = rboolean.test( name );
                    //如果不是boolean值类型的,则调用将其设置为空
                    //这是为了解决webkit内核不能正确移除html属性style的问题
                    if ( !isBool ) {
                        jQuery.attr( elem, name, "" );
                    }
                    //如果是ie低版本则使用修正后的propName
                    elem.removeAttribute( getSetAttribute ? name : propName );
                    //如果是boolean值,则同步设置对应的dom属性为false
                    if ( isBool && propName in elem ) {
                        elem[ propName ] = false;
                    }
                }
            }
        }
    },
    attrHooks: {
        type: {
            set: function( elem, value ) {}
        },
        value: {
            get: function( elem, name ) {},
            set: function( elem, value, name ) {}
        }
    },
    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"
    }
});
/*这里对于boolean值的读取和写入的修正方法*/
boolHook = {
    get: function( elem, name ) {
        var attrNode,
            //获取dom属性的值
            property = jQuery.prop( elem, name );
        // getAttributeNode 获取元素的属性节点,然后检测节点的值
        // 如果值是true 或者 不是false,则返回小写的属性名,否则【false】,返回undefined
        // 对于有些值,即使设置了其他值 浏览器也会认为是true 来处理
        return property === true || 
        typeof property !== "boolean" && 
        ( attrNode = elem.getAttributeNode(name) ) && 
        attrNode.nodeValue !== false ?
        name.toLowerCase() :
        undefined;
    },
    set: function( elem, value, name ) {
        var propName;
        if ( value === false ) {
            // 直接进行移除属性
            jQuery.removeAttr( elem, name );
        } else {
            // html属性名对应的dom名, 有些是需要进行驼峰转换的,有的就不用,比如 checked
            propName = jQuery.propFix[ name ] || name;
            if ( propName in elem ) {
                // 设置dom属性
                elem[ propName ] = true;
            }
            //调用原生方法,设置修正后的html属性
            elem.setAttribute( name, name.toLowerCase() );
        }
        return name;
    }
};

本篇就介绍到这里,下一篇小编将介绍 attrHooks,nodeHook 的各种修正操作;

感谢您的阅读,欢迎留言:交流,提问,斧正

评论
发表评论
暂无评论
WRITTEN BY
前端狮子
JS前端开发工程师 :喜欢研究js,nodejs,html5; 希望结交更多朋友~
TA的新浪微博
PUBLISHED IN
# 菜鸟解读 jQuery #

本栏解读的jQ为1.7.2版本。 本人也是刚开始读起源码,在这里分享下成长的心得。 本人能力有限,也是接触JS不久的初学者,定会有不少解析不全不够明朗【甚至BUG】的地方, 希望各位牛牛多多留言斧正 感谢阅读 ps:由于工作不定时繁忙,本人也无法定期更新,但是会尽量抽时间学习,分享给大家

我的收藏