1.offset家族
offset這個(gè)單詞本身是--偏移,補(bǔ)償,位移的意思。
js中有一套方便的獲取元素尺寸的辦法就是offset家族,offsetWidth、offsetHight 以及offsetLeft、offsetTop、offsetParent共同組成了offset家族。
1. offsetWidth和offsetHeight(檢測(cè)自身盒子寬高+padding+border)
- offsetWidth = width+padding+border;
- offsetHeight = Height+padding+border;
2. offsetLeft和offsetTop (檢測(cè)距離父盒子有定位的左/上面的距離)
- 返回距離上級(jí)盒子(帶有定位)左邊的位置
- 如果父級(jí)都沒(méi)有定位則以body為準(zhǔn)
- offsetLeft 從父親的padding 開(kāi)始算,父親的border 不算。
- 在父盒子有定位的情況下,offsetLeft == style.left(去掉px)
3. offsetParent (檢測(cè)父系盒子中帶有定位的父盒子節(jié)點(diǎn))
- 返回該對(duì)象的父級(jí) (帶有定位),如果當(dāng)前元素的父級(jí)元素沒(méi)有進(jìn)行CSS定位 (position為absolute或 relative,fixed), offsetParent為body。
- 如果當(dāng)前元素的父級(jí)元素中有CSS定位(position為absolute或relative,fixed),offsetParent取最近的那個(gè)父級(jí)元素。
4. offsetLeft和style.left的區(qū)別:
- 最大的區(qū)別在于offsetLeft可以返回沒(méi)有定位盒子的距離左側(cè)的位置,而style.left不行
- offsetLeft返回的是number型,而style.left返回的是string型,且?guī)в袉挝籶x
- offsetLeft只讀,而style.left可讀寫(xiě)
- 還有只有寫(xiě)在行內(nèi)樣式的left,才可以被style.left拿到 ,否則返回的就是空字符串。
5.offsetTop和style.top同上
2. Scroll家族組成
1. scrollWidth和scrollHeight( 不包括border 和 margin)
- scrollWidth = 盒子本身width+padding
- 檢測(cè)盒子的寬高。(調(diào)用者:節(jié)點(diǎn)元素。屬性。)
- 盒子內(nèi)容的寬高。(如果有內(nèi)容超出了,顯示內(nèi)容的寬高度,不超過(guò)則為盒子本身的寬高度)
- IE567可以比盒子小。 IE8+火狐谷歌不能比盒子小
2. scrollTop和scrollLeft
- 網(wǎng)頁(yè),被瀏覽器遮擋的頭部和左邊部分。
- 被卷去的頭部和左邊部分。
- 兼容問(wèn)題:
一、未聲明 DTD(谷歌只認(rèn)識(shí)他、IE9+)、document.body.scrollTop
二、已經(jīng)聲明DTD(IE678只認(rèn)識(shí)他、IE9+任何時(shí)候)、document.documentElement.scrollTop
三、火狐/谷歌/ie9+以上支持的、window.pageYOffset
說(shuō)簡(jiǎn)單點(diǎn):就是谷歌只識(shí)別 document.body, 而IE只識(shí)別document.documentElement
火狐才有DTD的聲明問(wèn)題。
兼容寫(xiě)法:
var top = window.pageYOffset
|| document.documentElement.scrollTop
|| document.body.scrollTop;
或 var top = document.body.scrollTop + document.documentElement.scrollTop;
判斷頁(yè)面是否已聲明DTD
document.compatMode === 'BackCompat'
BackCompat -- 未聲明
CSS1Compat --- 聲明
// scroll方法的封裝
// 需求: 封裝一個(gè)兼容的scroll(),返回值是json,用scroll().top獲取scrollTop的屬性
function scroll() {
// 如果存在,返回0~無(wú)窮大
// 不存在返回undefined
// 兼容谷歌、火狐以及IE9+
if (window.pageYOffset !== undefined) {
return {
"top": window.pageYOffset,
"left": window.pageXOffset
};
} else if (document.compatMode === 'CSS1Compat') {
// IE9以下的 還需要判斷是否已聲明DTD,CSS1Compat標(biāo)識(shí)已聲明
return {
"top": document.documentElement.scrollTop,
"left": document.documentElement.scrollLeft
};
} else {
return {
"top": document.body.scrollTop,
"left": document.body.scrollLeft
}
}
// 實(shí)際使用的
// return {
// "top": window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop,
// "left": window.pageYOffset || document.body.scrollLeft || document.documentElement.scrollLeft
// }
}
3. 獲取title、body、head、html標(biāo)簽
- document.title --- 文檔標(biāo)題;
- document.head --- 文檔的頭標(biāo)簽
- document.body --- 文檔的body標(biāo)簽;
- document.documentElement --- 這個(gè)很重要,它表示文檔的html標(biāo)簽, 也就是說(shuō),基本結(jié)構(gòu)當(dāng)中的html標(biāo)簽并不是通過(guò)document.html 去訪(fǎng)問(wèn)的,而是document.documentElement
3. client家族
1. clientWidth和clientHeight
- 調(diào)用者不同,意義不同:
- 盒子調(diào)用: 指盒子本身。
- body/html調(diào)用: 可視區(qū)域大小。
- clientX: 鼠標(biāo)距離可視區(qū)域左側(cè)距離(event調(diào)用)
- clientY: 鼠標(biāo)距離可視區(qū)域上側(cè)距離(event調(diào)用)
- clientTop / clientLeft : 盒子的border寬高
兼容寫(xiě)法:
var w=window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
var h=window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight;
2.三大家族的區(qū)別:
1. width和height:
clientWidth = width + padding
clientHeight = height + padding
offsetWidth = width + padding + border
offsetHeight = height + padding + border
scrollWidth = 內(nèi)容寬度(不包含border)
scrollHeight = 內(nèi)容高度(不包含border)
2. top和left:
offsetTop/offsetLeft :
調(diào)用者:任意元素。(盒子為主)
作用:距離父系盒子中帶有定位的距離。
scrollTop/scrollLeft:(盒子也可以調(diào)用,必須有滾動(dòng)條)
調(diào)用者:document.body.scrollTop/.....(window)
作用:瀏覽器無(wú)法顯示的部分(被卷去的部分)。
clientY/clientX:(clientTop/clientLeft 值的是border)
調(diào)用者:event.clientX(event)
作用:鼠標(biāo)距離瀏覽器可視區(qū)域的距離(左、上)。
3.緩動(dòng)動(dòng)畫(huà)原理
leader = leader + (target - leader) /10;
盒子位置 = 盒子本身位置 + (目標(biāo)位置 - 盒子本身位置)/10
動(dòng)畫(huà)原理: 目標(biāo)位置 = 盒子位置 + 步長(zhǎng)
// 需注意的一點(diǎn)是: JS實(shí)際運(yùn)算時(shí)會(huì)四舍五入取整,然后計(jì)算
// 獲取盒子距離左側(cè)具有定位的父盒子的距離(沒(méi)有的body),四舍五入取整。
// style.left獲取的是具體值。
/***
*緩動(dòng)動(dòng)畫(huà)封裝
* @param ele
* @param target
* @param type [left || top]
*/
function animate(ele, target, type) {
// 開(kāi)始動(dòng)畫(huà) 首先要清除定時(shí)器
clearInterval(ele.timer);
// 開(kāi)始定時(shí)器
ele.timer = setInterval(function () {
// 開(kāi)閉原則
var CLOSE_INTERVAL = false; // 是否關(guān)閉定時(shí)器
//遍歷屬性和值,分別單獨(dú)處理json
//attr == k(鍵) target == json[k](值)
for (var k in json) {
// 動(dòng)畫(huà)原理: 盒子位置 = 盒子位置 + ((目標(biāo)位置 - 盒子自身位置)/10)
// 1.獲取步長(zhǎng) (目標(biāo)位置 - 盒子自身位置)/10
var leader = parseInt(getStyle(ele, k)) || 0;
var step = (json[k] - leader) / 10;
// 2. 二次加工, 小于0向下取整 或 大于0向上取整
step = step > 0 ? Math.ceil(step) : Math.floor(step);
// 3.移動(dòng) 盒子位置 = 盒子位置 + 步長(zhǎng)
leader = leader + step;
ele.style[k] = leader + "px";
// 4.清除定時(shí)器的條件 當(dāng)步長(zhǎng) 大于 (目標(biāo)位置 - 盒子自身位置)
// 不考慮小數(shù)的情況下,只要目標(biāo)位置和當(dāng)前位置不相等,就不能清除清除定時(shí)器。
if (Math.abs(json[k] - leader) > Math.abs(step)) {
CLOSE_INTERVAL = true;
}
}
//只有所有的屬性都到了指定位置,CLOSE_INTERVAL值才不會(huì)變成true;
if (!CLOSE_INTERVAL) {
// 將盒子位置直接賦為 目標(biāo)位置
// ele.style[type] = target + "px";
clearInterval(ele.timer);
callback && callback();
}
}, 25);
}
// 獲取元素樣式的兼容寫(xiě)法
function getStyle(ele, attr) {
if (window.getComputedStyle) {
return window.getComputedStyle(ele, null)[attr];
}
return ele.currentStyle[attr];
}

元素位置及事件