1.js盒子模型

指的是通過js中提供的一系列的屬性和方法,獲取頁面中元素的樣式資訊值

例:

#box有很多自己的私有屬性:

HTMLDivElement.prototype->HTMLElement.prototype->Element.prototype->Node.prototype->EventTarget.prototype->Object.prototype

var box = document.getElementById("box");

console.dir(box);

2.概念

2.1 內容的寬度和高度

我們設定的width/height這兩個樣式就是內容的寬和高;

● 如果沒有設定height值,容器的高度會根據裡面內容自適應,這樣獲取的值就是真實內容的高;

● 如果設定了固定的高度,不管內容是多還是少,其實我們內容的高度值的都是設定的那個值。

2.2 真實內容的寬度和高度

代指的是實際內容的寬高(和我們設定的height沒有必然的聯絡),如我設定高度為200,如果內容有溢位,那麼真實內容的高度是要把溢位內容的高度也加進來的

3. js盒子模型常用屬性

3.1 client系列

3.1.1 clientWidth/clientHeight(只讀屬性)

● 內容的寬/+左右/上下填充 (和內容是否溢位沒有關係)(即不包含border值)

● 如果設定了box-sizing:border-box; clientWidth/clientHeight =容器寬/- border

3.1.2 clientLeft/clientTop (只讀屬性)

/邊框的寬度border[Left/Top]Width

3.2 offset系列

<div id="outer">
	<div id="inner">
		<div id="center"></div>
	</div>
</div>
var outer = document.getElementById("outer"),
	inner = document.getElementById("inner"),
	center = document.getElementById("center");

3.2.1 offsetWidth/offsetHeight(只讀屬性)

clientWidth/clientHeight + 左右/上下邊框 (和內容是否溢位沒有關係(包含border)

3.2.2 offsetParent

當前元素的父級參照物,在同一個平面中,最外層的元素是裡面所有元素的父級參照物(和html層級結構沒有必然的聯絡)

● 一般來說一個頁面中所有元素的父級參照物都是body

console.log(center.offsetParent);	//body
console.log(inner.offsetParent);	//body
console.log(outer.offsetParent);	//body
console.log(document.body.offsetParent);	//null

● 想要改變父級參照物需要通過position定位來進行改變:absolute,relative,fixed中任意一個值都可以把父級參照物進行修改

outer.style.position = "relative";
inner.style.position = "relative";
console.log(center.offsetParent);	//inner
console.log(inner.offsetParent);	//outer
console.log(outer.offsetParent);	//body

3.2.3 offsetLeft/offsetTop(只讀屬性)

當前元素(外邊框)距離其父級參照物(內邊框)的偏移距離

console.log(center.offsetLeft);	//距離body左偏移距離
console.log(inner.offsetLeft);	//距離body左偏移距離
console.log(outer.offsetLeft);	//距離body左偏移距離
outer.style.position = "relative";
inner.style.position = "relative";
console.log(center.offsetLeft);	//距離inner左偏移距離

3.2.4 offset函式封裝

等同於jquery中的offset方法,實現獲取頁面中任意一個元素距離body的偏移(包含左偏移和上偏移),不管當前元素的父級參照物是誰

// 獲取的結果是一個物件{left:距離body的左偏移,top:距離body的上偏移}
// 在標準的ie8瀏覽器中,我們使用offsetLeft/offsetTop其實是把父級參照物的邊框已經算在內了,所以我們不需要自己再單獨的加邊框了

function offset(curEle){
	var totalLeft = null,
	<span style="white-space:pre">	</span>totalTop = null,
		par = curEle.offsetParent;
	// 首先把自己本身的進行累加:
	totalLeft += curEle.offsetLeft;
	totalTop += curEle.offsetTop;

	// 只要沒有找到body,我們就把父級參照物的邊框和偏移進行累加
	while (par){
		if(navigator.userAgent.indexOf("MSIE 8.0") === -1){ //不是標準ie8瀏覽器才累加邊框
			// 累加父級參照物的邊框
			totalLeft += par.clientLeft;
			totalTop += par.clientTop;
		}		

		// 累加父級參照物的偏移
		totalLeft += par.offsetLeft;
		totalTop += par.offsetTop;

		par = par.offsetParent;
	}
	return {left:totalLeft,top:totalTop};
}
console.log(offset(center));
console.log(offset(center).left);

3.3 scroll系列

3.3.1 scrollWidth/scrollHeight  (只讀屬性)

● 容器中內容沒有溢位的情況下:和我們的clientWidth/clientHeight一模一樣

● 如果容器中內容有溢位,獲取的結果如下規則:

 scrollWidth真實內容的寬度(包含溢位+左填充

 scrollHeight真實內容的高度(包含溢位)+上填充

獲取到的結果都是“約等於”的值,因為:

● 同一個瀏覽器,我們是否設定overflow="hidden",對於最終的結果是有影響的(滾動條也佔據寬度會影響);

● 在不同的瀏覽器中我們獲取到的結果也是不相同的

3.3.2 scrollLeft/scrollTop(可讀寫屬性)

滾動條捲去的寬度/高度 

注意:

1.之前我們學習的js盒子模型中:client系列/offset系列/scrollWidth/scrollHeight都是“只讀”屬性->只能通過屬性獲取值,不能通過屬性修改元素的樣式
2.scrollTop/scrollLeft:滾動條捲曲的高度/寬度(這兩個屬性是唯一“可讀寫”屬性)
 

scrollTop的值是存在邊界值(最大和最小值的),我們設定的值比最小值小或者比最大值大時都沒用,起到效果的依然是邊界的值。
[最小值是零]

box.scrollTop = -1000;	//直接回到容器頂部,沒有超出
console.log(box.scrollTop);

[最大值=真實的高度-當前容器一螢幕的高度]
var maxTop = box.scrollHeight - box.clientHeight;
console.log(maxTop);

4. 關於js盒子模型屬性取值的問題

我們通過以上這些屬性值獲取的結果永遠不可能出現小數,都是整數

瀏覽器獲取結果的時候,會在原來真實結果的基礎上進行四捨五入

5. 關於操作瀏覽器本身的盒子模型資訊

5.1 clientWidth/clientHeight

是當前瀏覽器可視視窗的寬/高(一螢幕的寬/高)

5.2 scrollWidth/scrollHeight

是當前頁面的真實/高(所有屏加起來的寬/高),但是是一個約等於的值

5.3 注意

● 不管哪些屬性,也不管是什麼瀏覽器,也不管是獲取還是設定,想要都相容的話,需要寫兩套;

● 且必須document.documentElement在前

document.documentElement[attr] || document.body[attr];

如:

[獲取]
document.documentElement.clientHeight || document.body.clientHeight
[設定]
document.documentElement.scrollTop = 0;
document.body.scrollTop = 0;

win:編寫一個有關於操作瀏覽器盒子模型的方法

如果只傳遞了attr沒有傳遞value,預設的意思的“獲取”

如果兩個引數都傳遞了,意思是“設定”

不嚴謹的來說這就是有關於“類的過載”:同一個方法,通過傳遞引數的不同實現了不同的功能

function win(attr,value){
if(typeof value === "undefined"){
return document.documentElement[attr] || document.body[attr];
}
document.documentElement[attr] = value;
document.body[attr] = value;
}
win("clientHeight");

補充

parentNode:父親節點,html結構層級關係中的上一級元素

<div id="outer">
	<div id="inner">
		<div id="center"></div>
	</div>
</div>
var outer = document.getElementById("outer"),
	inner = document.getElementById("inner"),
	center = document.getElementById("center");
●center.parentNode ->inner
●inner.parentNode ->outer
●outer.parentNode ->body
●document.body.parentNode ->
<html>
	<head></head>
	<body>..</body>
</html>

●document.documentElement.parentNode ->#document:

<!DOCTYPE html>
<html> 
<head></head>
<body>..</body>
</html>

●document.parentNode->null