JavaScript獲取DOM元素位置和尺寸大小

在一些復(fù)雜的頁面中經(jīng)常會(huì)用JavaScript處理一些DOM元素的動(dòng)態(tài)效果街夭,這種時(shí)候我們經(jīng)常會(huì)用到一些元素位置和尺寸的計(jì)算砰碴,瀏覽器兼容性問題也是不可忽略的一部分,要想寫出預(yù)想效果的JavaScript代碼板丽,我們需要了解一些基本知識(shí)呈枉。

基礎(chǔ)概念

為了方便理解,我們需要了解幾個(gè)基礎(chǔ)概念埃碱,每個(gè)HTML元素都有下列屬性

offset client scroll
offsetWidth clientWidth scrollWidth
offsetHeight clientHeight scrollHeight
offsetLeft clientLeft scrollLeft
offsetTop clientTop scrollTop
  1. clientHeight和clientWidth用于描述元素內(nèi)尺寸猖辫,是指 元素內(nèi)容+內(nèi)邊距 大小,不包括邊框(IE下實(shí)際包括)乃正、外邊距住册、滾動(dòng)條部分
  1. offsetHeight和offsetWidth用于描述元素外尺寸,是指 元素內(nèi)容+內(nèi)邊距+邊框瓮具,不包括外邊距和滾動(dòng)條部分
  1. clientTop和clientLeft返回內(nèi)邊距的邊緣和邊框的外邊緣之間的水平和垂直距離荧飞,也就是左凡人,上邊框?qū)挾?/li>
  1. offsetTop和offsetLeft表示該元素的左上角(邊框外邊緣)與已定位的父容器(offsetParent對(duì)象)左上角的距離
  2. offsetParent對(duì)象是指元素最近的定位(relative,absolute)祖先元素,遞歸上溯叹阔,如果沒有祖先元素是定位的話挠轴,會(huì)返回null

寫個(gè)小例子方便理解

<div id="divParent" style="padding: 18px; background-color: #aaa; position: relative;">
    <div id="divDisplay" style="background-color: #0f0; margin: 30px; padding: 10px;
        height: 200px; width: 200px; border: solid 10px #f00;">
    </div>
</div>



var div = document.getElementById('divDisplay');

var clientHeight = div.clientHeight;
var clientWidth = div.clientWidth;
div.innerHTML += 'clientHeight: ' + clientHeight + '<br/>';
div.innerHTML += 'clientWidth: ' + clientWidth + '<br/>';

var clientLeft = div.clientLeft;
var clientTop = div.clientTop;
div.innerHTML += 'clientLeft: ' + clientLeft + '<br/>';
div.innerHTML += 'clientTop: ' + clientTop + '<br/>';

var offsetHeight = div.offsetHeight;
var offsetWidth = div.offsetWidth;
div.innerHTML += 'offsetHeight: ' + offsetHeight + '<br/>';
div.innerHTML += 'offsetWidth: ' + offsetWidth + '<br/>';

var offsetLeft = div.offsetLeft;
var offsetTop = div.offsetTop;
div.innerHTML += 'offsetLeft: ' + offsetLeft + '<br/>';
div.innerHTML += 'offsetTop: ' + offsetTop + '<br/>';

var offsetParent = div.offsetParent;
div.innerHTML += 'offsetParent: ' + offsetParent.id + '<br/>';

效果如圖

Paste_Image.png
Paste_Image.png

從圖中我們可以看到,clientHeight就是div的高度+上下各10px的padding耳幢,clientWidth同理

而clientLeft和ClientTop即為div左岸晦、上邊框?qū)挾?/p>

offsetHeight是clientHeight+上下個(gè)3px的邊框?qū)挾戎停琽ffsetWidth同理

offsetTop是div 30px的 maggin+offsetparent 8px的 padding睛藻,offsetLeft同理

6.scrollWidth和scrollHeight是元素的內(nèi)容區(qū)域加上內(nèi)邊距加上溢出尺寸启上,當(dāng)內(nèi)容正好和內(nèi)容區(qū)域匹配沒有溢出時(shí),這些屬性與clientWidth和clientHeight相等

7.scrollLeft和scrollTop是指元素滾動(dòng)條位置店印,它們是可寫

下面寫個(gè)簡(jiǎn)單例子理解

<div id="divParent" style="background-color: #aaa; padding:8px; border:solid 7px #000; height:200px; width:500px; overflow:auto;">
    <div id="divDisplay" style="background-color: #0f0; margin: 30px; padding: 10px;
        height: 400px; width: 200px; border: solid 3px #f00;">
    </div>
</div>



var divP = document.getElementById('divParent');
var divD = document.getElementById('divDisplay');

var scrollHeight = divP.scrollHeight;
var scrollWidth = divP.scrollWidth;
divD.innerHTML += 'scrollHeight: ' + scrollHeight + '<br/>';
divD.innerHTML += 'scrollWidth: ' + scrollWidth + '<br/>';

效果圖

Paste_Image.png

在FireFox和IE10(IE10以下版本盒模型和W3C標(biāo)準(zhǔn)不一致冈在,不加討論,兼容性問題下面會(huì)介紹到)下得到結(jié)果scrollHeight: 494按摘,而在Chrome和Safari下得到結(jié)果scrollHeight: 502包券,差了8px,根據(jù)8可以簡(jiǎn)單推測(cè)是divParent的padding炫贤,來算一下是不是

我們可以看看它們的結(jié)果是怎么來的溅固,首先scrollHeight肯定包含了divDisplay所需的高度 400px的高度+上下各10px的padding+上下各3px的border+上下各30px的margin,這樣

400+102+32+30*2=486

這樣486+8=494兰珍, 486+82=502果真是這樣侍郭,在FireFox和IE10下沒有計(jì)算下padding*

有了這些基礎(chǔ)知識(shí)后,我們就可以計(jì)算元素的位置和尺寸了俩垃。

相對(duì)于文檔與視口的坐標(biāo)

當(dāng)我們計(jì)算一個(gè)DOM元素位置也就是坐標(biāo)的時(shí)候励幼,會(huì)涉及到兩種坐標(biāo)系汰寓,文檔坐標(biāo)視口坐標(biāo)口柳。

我們經(jīng)常用到的document就是整個(gè)頁面部分,而不僅僅是窗口可見部分有滑,還包括因?yàn)榇翱诖笮∠拗贫霈F(xiàn)滾動(dòng)條的部分跃闹,它的左上角就是我們所謂相對(duì)于文檔坐標(biāo)的原點(diǎn)。

視口是顯示文檔內(nèi)容的瀏覽器的一部分毛好,它不包括瀏覽器外殼(菜單望艺,工具欄,狀態(tài)欄等)肌访,也就是當(dāng)前窗口顯示頁面部分找默,不包括滾動(dòng)條。

如果文檔比視口小吼驶,說明沒有出現(xiàn)滾動(dòng)惩激,文檔左上角和視口左上角相同店煞,一般來講在兩種坐標(biāo)系之間進(jìn)行切換,需要加上或減去滾動(dòng)的偏移量(scroll offset)风钻。

為了在坐標(biāo)系之間進(jìn)行轉(zhuǎn)換顷蟀,我們需要判定瀏覽器窗口的滾動(dòng)條位置。window對(duì)象的pageXoffset和pageYoffset提供這些值骡技,IE 8及更早版本除外鸣个。也可以通過scrollLeft和scrollTop屬性獲得滾動(dòng)條位置,正常情況下通過查詢文檔根節(jié)點(diǎn)(document.documentElement)來獲得這些屬性值布朦,但在怪異模式下必須通過文檔的body上查詢囤萤。

function getScrollOffsets(w) {
    var w = w || window;
    if (w.pageXoffset != null) {
        return {
            x: w.pageXoffset,
            y: pageYoffset
        };
    }
    var d = w.document;
    if (document.compatMode == "CSS1Compat")
        return {
            x: d.documentElement.scrollLeft,
            y: d.documentElement.scrollTop
        };
    return {
        x: d.body.scrollLeft,
        y: d.body.scrollTop
    };
}

有時(shí)候能夠判斷視口的尺寸也是非常有用的

function getViewPortSize(w) {
    var w = w || window;
    if (w.innerWidth != null)
        return {
            w: w.innerWidth,
            h: w.innerHeight
        };
    var d = w.document;
    if (document.compatMode == "CSS1Compat")
        return {
            w: d.documentElement.clientWidth,
            h: d.documentElement.clientHeight
        };
    return {
        w: d.body.clientWidth,
        h: d.body.clientHeight
    };
}

文檔坐標(biāo)

任何HTML元素都擁有offectLeft和offectTop屬性返回元素的X和Y坐標(biāo),對(duì)于很多元素是趴,這些值是文檔坐標(biāo)阁将,但是對(duì)于以定位元素后代及一些其他元素(表格單元),返回相對(duì)于祖先的坐標(biāo)右遭。我們可以通過簡(jiǎn)單的遞歸上溯累加計(jì)算

function getElementPosition(e) {
    var x = 0,
        y = 0;
    while (e != null) {
        x += e.offsetLeft;
        y += e.offsetTop;
        e = e.offsetParent;
    }
    return {
        x: x,
        y: y
    };
}

盡管如此做盅,這個(gè)函數(shù)也不總是計(jì)算正確的值,當(dāng)文檔中含有滾動(dòng)條的時(shí)候這個(gè)方法就不能正常工作了窘哈,我們只能在沒有滾動(dòng)條的情況下使用這個(gè)方法吹榴,不過我們用這個(gè)原理算出一些元素相對(duì)于某個(gè)父元素的坐標(biāo)。

視口坐標(biāo)

計(jì)算視口坐標(biāo)就相對(duì)簡(jiǎn)單了很多滚婉,可以通過調(diào)用元素getBoundingClientRect方法图筹。方法返回一個(gè)有l(wèi)eft、right让腹、top远剩、bottom屬性的對(duì)象,分別表示元素四個(gè)位置的相對(duì)于視口的坐標(biāo)骇窍。getBoundingClientRect所返回的坐標(biāo)包含元素的內(nèi)邊距和邊框瓜晤,不包含外邊距。兼容性很好腹纳,非常好用

元素尺寸

由上面計(jì)算坐標(biāo)方法痢掠,我們可以方便得出元素尺寸。在符合W3C標(biāo)準(zhǔn)的瀏覽器中g(shù)etBoundingClientRect返回的對(duì)象還包括width和height,但在原始IE中未實(shí)現(xiàn)嘲恍,但是通過返回對(duì)象的right-left和bottom-top可以方便計(jì)算出足画。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市佃牛,隨后出現(xiàn)的幾起案子淹辞,更是在濱河造成了極大的恐慌,老刑警劉巖俘侠,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件象缀,死亡現(xiàn)場(chǎng)離奇詭異彬向,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)攻冷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門娃胆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人等曼,你說我怎么就攤上這事里烦。” “怎么了禁谦?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵胁黑,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我州泊,道長(zhǎng)丧蘸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任遥皂,我火速辦了婚禮力喷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘演训。我一直安慰自己弟孟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布样悟。 她就那樣靜靜地躺著拂募,像睡著了一般。 火紅的嫁衣襯著肌膚如雪窟她。 梳的紋絲不亂的頭發(fā)上陈症,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音震糖,去河邊找鬼录肯。 笑死,一個(gè)胖子當(dāng)著我的面吹牛试伙,可吹牛的內(nèi)容都是我干的嘁信。 我是一名探鬼主播于样,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼疏叨,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了穿剖?” 一聲冷哼從身側(cè)響起蚤蔓,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎糊余,沒想到半個(gè)月后秀又,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體单寂,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年吐辙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了茉继。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胀葱。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出镀赌,到底是詐尸還是另有隱情,我是刑警寧澤菜皂,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布燕侠,位于F島的核電站,受9級(jí)特大地震影響孵构,放射性物質(zhì)發(fā)生泄漏屁商。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一颈墅、第九天 我趴在偏房一處隱蔽的房頂上張望蜡镶。 院中可真熱鬧,春花似錦恤筛、人聲如沸帽哑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽妻枕。三九已至,卻和暖如春粘驰,著一層夾襖步出監(jiān)牢的瞬間屡谐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工蝌数, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留愕掏,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓顶伞,卻偏偏與公主長(zhǎng)得像饵撑,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子唆貌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容