【jq 源码解析4-样式操作】

jq源码 | 2020-12-24 11:42:19 237次 0次

样式操作涉及到元素的尺寸大小、类名、表现等。


CSS操作

jQuery.fn.extend( {
    css: function( name, value ) {
        return access( this, function( elem, name, value ) {
                ...
                // 这里第二部分有说明
                hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];

                        // If a hook was provided get the computed value from there
                        if ( hooks && "get" in hooks ) {
                            val = hooks.get( elem, true, extra );
                        }
            ...
            // 支持数组的形式设置
            if ( Array.isArray( name ) ) {
                ... jQuery.css
            }
            // 主要看 style 和 css 方法,这两个方法挂载在 jq 本身静态方法
            return value !== undefined ?
                jQuery.style( elem, name, value ) :
                jQuery.css( elem, name );
        }, name, value, arguments.length > 1 );
    }
} );

jQuery.css 静态方法:


//属性值的获取操作
    css: function( elem, name, extra, styles ) {
            // 转为驼峰
            origName = cssCamelCase( name ),
          ...
            // 如果需要比如 -transform 自动补全前缀  webkit  moz ms
            // 如果是 transform 不带前面的 - 则不处理
            name = finalPropName( origName );
          ...
         // 这个方法通过 getComputedStyle  
         // 不支持这个的则使用 elem.ownerDocument.defaultView
         // 获取当前属性值
        if ( val === undefined ) {
            val = curCSS( elem, name, styles );
        }
        ...
        return val;
    }


jQuery.style 静态方法:

这里的逻辑和上面的css操作基本一致,
    真正的设置样式由这个方法触发
    ...
    if ( isCustomProp ) {
        style.setProperty( name, value );
    } else {
        style[ name ] = value;
    }


尺寸操作

window: 

  window.screenTop      浏览器顶部距离屏幕顶部的距离(全屏时为0) 

  window.screen.height 分辨率

  window.innerWidth     窗口宽度(打开控制台时剩余的宽度)===  document.documentElement.clientWidth

  注:document.documentElement.offsetWidth(不包括 margin ),clientWidth则包含


元素:

242021032231634.png242021075498650.png

图片转载来源

定义入口:

dimensions.js 中:

jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
    jQuery.each( {
        padding: "inner" + name,
        content: type,
        "": "outer" + name
    }, function( defaultExtra, funcName ) {

        // Margin is only for outerHeight, outerWidth
        jQuery.fn[ funcName ] = function( margin, value ) {
            ...
            return access( this, function( elem, type, value ) {
                var doc;

                if ( isWindow( elem ) ) {

                    // $( window ) 
                    return funcName.indexOf( "outer" ) === 0 ?
                        elem[ "inner" + name ] :
                        elem.document.documentElement[ "client" + name ];
                }

                // $(document)
                if ( elem.nodeType === 9 ) {
                    doc = elem.documentElement;
                    // 不指定 <!DOCTYPE HTML> 时
                    // document.body.XXX 取到的值不正确
                    // document.documentElement.XX 取值正确
                    return Math.max(
                        elem.body[ "scroll" + name ], doc[ "scroll" + name ],
                        elem.body[ "offset" + name ], doc[ "offset" + name ],
                        doc[ "client" + name ]
                    );
                }
                // 对于 dom 则还是通过 css style 来操作
                return value === undefined ?
                    // get
                    jQuery.css( elem, type, extra ) :
                    // set
                    jQuery.style( elem, type, value, extra );
            }, type, chainable ? margin : undefined, chainable );
        };
    } );
} );

其中对于 width height 等属性的操作,jq 中有一个 hooks 的设计,用来专门处理尺寸的样式:

jQuery.each( [ "height", "width" ], function( _i, dimension ) {
    jQuery.cssHooks[ dimension ] = {
        get: function( elem, computed, extra ) {
            if ( computed ) {
                ...
                // 取值操作
                getWidthOrHeight( elem, dimension, extra );
            }
        },

        set: function( elem, value, extra ) {
            ...
               // 根据 box-sizing 模型修正数据
                subtract = extra ?
                    boxModelAdjustment(...) :
                    0;
            ...
            // 赋值  $('.test').height('+=400')这种写法也会修正处理
            return setPositiveNumber( elem, value, subtract );
        }
    };
} );

通过 getWidthOrHeight 方法发现 jq 并没有通过 js 提供这些 api 来获取节点的样式,而是通过 getComputedStyle 返回的对象 CSSStyleDeclaration 类型对象来取值,并且取值后再次执行 boxModelAdjustment 修正盒模型的值 :

EleObj.ownerDocument.defaultView.getComputedStyle(EleObj).getPropertyValue('height')

setPositiveNumber 设置值操作直接返回值本身。

对于偏移的一些计算可以通过 getBoundingClientRect 方法实现


属性操作

class 操作

// 这个方法很简单,后续可能会改为 classList
jQuery.fn.extend( {
    addClass: function( value ) {
        ...
                    while ( ( clazz = classes[ j++ ] ) ) {
                        // 避免重复值 新旧class值拼一块
                        if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
                            cur += clazz + " ";
                        }
                    }
                    ...
                    // 判断新旧值 不一致再赋值
                    if ( curValue !== finalValue ) {
                        elem.setAttribute( "class", finalValue );
                    }
                }
            }
        }
        return this;
    },
    removeClass: function( value ) {
        ...
                    while ( ( clazz = classes[ j++ ] ) ) {
                        // 和添加的区别是这里替换已存在的class为空
                        while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
                            cur = cur.replace( " " + clazz + " ", " " );
                        }
                    }
                   ...
                }
            }
        }
        return this;
    },
    ...

} );

prop & attr

        prop 是指 dom 对象上自带的一些属性,属于标准中预置的

        attr 是指后面可以自己添加自定义的一些特性

prop:elem[ name ] = value  直接赋值给当前dom对象
attr: elem.setAttribute( name, value + "" );  通过 setAttribute 添加特性


0人赞

分享到: