jQuery从入门到精通源码分析系列(三十) 元素操作 – 窗口尺寸
沉沙 2018-07-24 来源 : 阅读 1101 评论 0

摘要:本篇jQuery教程探讨了jQuery中对应每种不同兼容的处理,希望阅读本篇文章以后大家有所收获,帮助大家对jQuery的理解更加深入。

· .height()

· .innerHeight()

· .innerWidth()

· .outerHeight()

· .outerWidth()

· )

基础回顾

· 

一般的,在获取浏览器窗口的大小和位置时,有以下几个属性可以使用:

· 

在不同的浏览器中,以下12个属性所代表的意义也是不一样的

· 

特别需要注意的是,当使用或者不使用<!DOCTYPE>声明显示一个文档的时候,以上12个属性的意义也会发生变化。

· 

特在IE 9中,无论是否使用<!DOCTYPE>声明显示一个文档,document.documentElement和document.body中的相关属性的意义总是相同的。这点与IE 6/7/8表现不一样。

· 

· 

正常情况:Firefox/Chrome/Safari(带<!DOCTYPE>声明)

· 

· 

窗口显示区(可视区域)的宽度和高度,包括滚动条区域

· 

window.innerHeight

window.innerWidth

· 

· 

窗口显示区(可视区域)的宽度和高度,不包括滚动条区域

· 

document.documentElement.clientHeight

document.documentElement.clientWidth

· 

· 

<body>元素的宽度和高度(注意,包括了不可见的区域)

· 

document.body.clientHeight

document.body.clientWidth

· 

· 

当前页面相对于窗口显示区左上角的 X /Y位置,即水平/垂直滚动条已滚动的距离

· 

window.pageXOffset

window.pageYOffset

· 

· 

Firefox:当前页面相对于窗口显示区左上角的 X /Y位置,即水平/垂直滚动条已滚动的距离,同window.pageXOffset/pageYOffset

· 

Chrome/Safari:总为0

· 

document.documentElement.scrollLeft

document.documentElement.scrollTop

· 

· 

FireFox:总为0

· 

Chrome/Safari:当前页面相对于窗口显示区左上角的 X /Y位置,即水平/垂直滚动条已滚动的距离,同window.pageXOffset/pageYOffse

· 

document.body.scrollLeft

document.body.scrollTop

· 

· 

如下一图说明所有问题

· 

· 

首先先解释下普通元素和非普通元素,

· 

非普通元素是指window,document这些 元素对象,

· 

普通元素是指除window,document之外的元素,如:div

· 

· 

· 

innerHeight属性:窗口中文档显示区域的高度,不包括菜单栏、工具栏等部分。该属性可读可写。

· 

IE不支持该属性,IE中body元素的clientHeight属性与该属性相同。

· 

innerWidth属性:窗口中文档显示区域的宽度,同样不包括边框。该属性可读可写。

· 

IE不支持该属性,IE中body元素的clientWidth属性与该属性相同。

· 

       clientHeight与clientWidth属性是只读的。

· 

       另外,IE不支持outerWidth、outerHeight属性。

· 

· 

兼容IE与DOM浏览器,如何获取窗口中文档显示区域的宽度及高度,使用?:条件语句,如下:

· 

windows.innerWidth ? windows.innerWidth : document.body.clientWidth;

· 

windows.innerHeight ? windows.innerHeight : document.body.clientHeight

· 

· 

源码实现

· 

window,document

· 

$(window).height()     代表了当前可见区域的大小

· 

$(document).height()  则代表了整个文档的高度

· 

注意当浏览器窗口大小改变时(如最大化或拉大窗口后) (window).height()随之改变,但是(window).height()随之改变,但是(document).height()是不变的。

· 

https://github.com/jquery/jquery/pull/764

· 

window 反映的是视图窗口,没有用window.innerWidth

· 

源码是通过document.documentElement

· 

return elem.document.documentElement[ "client" + name ];

· 

· 

因为有些样式不是简单的读写属性就可以的,比如width就不是简单地读取el.style.width。为了解决这个问题,jquery定义了一个属性 $.cssHooks,这里可以自定义对某个属性的get和set操作。而且jquery中就是用cssHooks来处理某些特殊属性

· 

具体涉及了:

· 

1. borderWidth: Object

2. height: Object

3. margin: Object

4. opacity: Object

5. padding: Object

6. width: Object

做dom选择器的时候,需要考虑各种兼容问题,所以就算是定位2X的源码,只考虑标准的w3c,不免也要额外才处理一些属性

比如盒子模型的解释:

说到 IE 的 bug,它对于“盒模型”的错误解释:在 IE5.x 以及 Quirks 模式的 IE6/7 中,将 border 与 padding 都包含在 width 之内。这为前端工程师的工作平添了不少麻烦,几户每个需要定义尺寸的 box 都要思量一下:是否触发了“盒模型 bug”?

同时,由于另一撮浏览器对标准的遵从,我们在精确定义一个在有限空间内显示的 box 时,也需要计算一下:留给它的空间只有那么大,刨去 border 和 padding,我们该把它的 width 写成多少呢?

这种情况在 CSS3 时代有了改善,得益于这个叫做 box-sizing 的属性,它具有“content-box”和“border-box”两个值。

定义 box-sizing: content-box; 时,浏览器对盒模型的解释遵从我们之前认识到的 W3C 标准;

定义 box-sizing: border-box; 时,浏览器对盒模型的解释与 IE6 相同;

我们看看width,height方法

jQuery还提供两个单独的API,width, height获取元素的长宽,可以取得隐藏元素的长宽

这里是属于cssHooks处理

jQuery.each([ "height", "width" ], function( i, name ) {

        jQuery.cssHooks[ name ] = {

            get: function( elem, computed, extra ) {

                if ( computed ) {

                    return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ?

                        jQuery.swap( elem, cssShow, function() {

                            return getWidthOrHeight( elem, name, extra );

                        }) :

                        getWidthOrHeight( elem, name, extra );

                }

            },

            set: function( elem, value, extra ) {

                var styles = extra && getStyles( elem );

                return setPositiveNumber( elem, value, extra ?

                    augmentWidthOrHeight(

                        elem,

                        name,

                        extra,

                        jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",

                        styles

                    ) : 0

                );

            }

        };

    });

出于性能的考量,浏览器对隐藏元素的样式是统统不计算的,有一套默认值返回给你,对于长宽就是0。对于动画来说,这有点不方便,比如show, slideDown等特效!因此jQuery等偷偷让它们显示出来,取得精确值,再隐藏回来,这个是由jquery.swap方法来处理

所以最终通过getWidthOrHeight方法获取了width,height

当然正常情况下offsetWidth,offsetHeigth是可以了,但是某些元素比如SVG,MathML返回尺寸出错(这里不考虑)

即便如此CSS3还增加了一个box-sizing选择盒子模型,于是有了augmentWidthOrHeight这个方法。

augmentWidthOrHeight方法其实就是对IE盒子模型的一个处理

所以最终的尺寸值其实是

offsetWidth/offsetHeigth + augmentWidthOrHeight方法

return ( val +

            augmentWidthOrHeight(

                elem,

                name,

                extra || ( isBorderBox ? "border" : "content" ),

                valueIsBorderBox,

                styles

            )

            ) + "px";

augmentWidthOrHeight

1.8增加了对css属性box-sizing的支持,需要注意与1.7.2的区别了。

1.7.2及以前的版本无论是否定义box-sizing: border-box返回的都是盒模型中元素内容的宽度或高度,不包括padding和border。

augmentWidthOrHeight方法是特别针对盒子模型的处理

例如,假如您需要并排放置两个带边框的框,可通过将 box-sizing 设置为 "border-box"。这可令浏览器呈现出带有指定宽度和高度的框,并把边框和内边距放入框中。

<style>

        div { width:60px; height:60px; margin:5px; float:left; }

        #aaron-box-test {

            box-sizing: border-box;

            -moz-box-sizing: border-box;

            width: 500px;

            padding: 5px;

            border: 5px solid gold;

        }

    </style>

</head>

<body>

<div id="aaron-box-test"></div>

<script>

    var $el = $('#aaron-box-test')

    var w = $el.width(); //480

</script>

定义了

box-sizing = border-box , width  = 480px

box-sizing = content-box ,width = 500px

IE6/7不支持box-sizing,输出的依然是500。但支持该熟悉的浏览器此时输出的结果则是480(刨去了盒模型的border和padding

border遵循的是IE的标准,跟IE6一样,将 border 与 padding 都包含在 width 之内

当然盒子模型的好处也有的:无论如何改动 border 与 padding 的值,都不会导致 box 总尺寸发生变化,也就不会打乱页面整体布局。而在 Firefox 等现代浏览器下,如果我们要改变一下 padding 的值,就不得不重新计算 box 的 width

innerWidth

为匹配的元素集合中获取第一个元素的当前计算宽度值,包括padding,但是不包括border。

这个方法返回元素的宽度,包括左边和右边的padding,单位是像素。

这个方法不适用于window and document对象,可以使用.width() 代替。

jQuery对CSS的处理统一调用了 jQuery.css( elem, type, extra ) 处理,不同的是这里额外的提供一个参数extra

当为innerWidth其实就满足这一条件,所以 extra: "padding", 即额外还包行padding的处理

对width操作是属性有兼容问题要处理的

故而代码要走钩子处理,此刻就是get方法,流程如上

其中有比较大的hack

比如Edwards大神的

curCSS方法中用于在标准浏览器下转换百分比值为更有用的像素值

整个流程代码看下来,你就发现jQuery的处理真的是细到极致,你可能就一个简简单单的width(), 实现的背后可能是几百 上千行的代码量!!!


本文由职坐标整理发布,学习更多的jQuery相关知识,请关注职坐标WEB前端jQuery频道!

本文由 @沉沙 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程