1. 程式人生 > >珠峰JS筆記3.1(盒子模型、偏移量)

珠峰JS筆記3.1(盒子模型、偏移量)

> 盒子模型常用的屬性

元素操作相關 <div id='box'> ... </div> 檢視控制檯

odiv.attributes.getNamedItem(‘id’) 回車 得到 id的值
id=​"box"
odiv.classList.add(‘test100’) 回車 給元素添加了一個 test100 的類
undefined
odiv.classList.remove(‘test100’) 回車 刪除 類 test100
undefined
box.className = ‘cur red’ 回車 設定元素的類
“cur red”
odiv.contentEditable = true 回車 可以直接在瀏覽器上更改內容

\1 client 系列

clientWidth / clientHeight content + padding
clientLeft 左邊框的寬度 clientTop 上邊框的高度 ( 即各邊框寬度 borderWidth )

\2 offset 系列

offsetWidth / offsetHeight : content + padding + border
offsetParent: 當前元素的父級參照物
offsetLeft/offsetTop 當前元素的外邊框距離父級參照物的內邊框的偏移量

\3 scroll 系列

scrollWidth / scrollHeight

在沒有內容溢位的情況下,等於 clientWidth
有溢位時: scrollHeight 值 為:真實的高度(包含溢位)+ 上 padding
這個值是約等於的,設定 overflow: hidden; 對結果有影響,不同瀏覽器處理的結果不同
scrollTop / scrollLeft 滾動條捲去的寬 / 高度

ps: 關於 JS 盒子模型取值的問題
通過以上屬性獲取的結果永遠不可能出現小數,都是整數,瀏覽器在獲取結果的時候,進行了四捨五入

關於操作瀏覽器本身的盒子模型資訊
clientWidth / clientHeight 是當前瀏覽器可視視窗的寬 / 高度(一屏)
scrollWidth / scrollHeight 是當前頁面的真實寬 / 高度(所有屏相加的結果) , 是一個約等於的值
不管哪些屬性,也不管是什麼瀏覽器,想要相容的話,設定和取值都要寫兩套

document.documentElement[attr] || document.body[attr] document.documentElement[attr] 必須在前

var len = document.documentElement.clientWidth || document.body.clientWidth;

編寫一個有關於操作瀏覽器盒子模型的方法
如果只傳遞了 attr,該方法為獲取值
如果兩個引數都傳遞了,該方法為設定屬性值
這就是 JS 中的類似 類的過載,同一個方法,通過傳遞引數的不同實現不同的功能

function myAttr( attr, value){
	if( typeof value === 'undefined'){   // [] 
		return document.documentElement[attr] || document.body[attr];
	}
	// 設定 屬性值
	document.documentElement[attr] = value;
	document.body[attr] = value;
}

獲取元素的某一個具體的樣式的屬性值
\1 元素.style.屬性名
需要把樣式寫在行內樣式上才可以得到,(寫在樣式表中的是不能獲取的)
在真實專案中,這種方式不常用 (無法實現 css 和 html 的分離)
\2 使用 window.getComputedStyle 這個方法獲取所有經過瀏覽器計算過的樣式(沒寫的樣式,也可以獲取)
window.getComputedStyle( 要操作的元素物件,null )
第二個引數是當前要操作元素的偽類,一般寫成 null
該方法獲取的結果是 CSSStyleDeclaration 這個類的一個例項 ,包含了當前元素的所有樣式屬性和值
取值:

var cssVal = window.getComputedStyle( box, null);
cssVal.height  或者 
cssVal['height']

注意: 這個方法在 IE6-8 下是不相容的,在 IE6-8 下使用 currentStyle 來獲取所有經過瀏覽器計算過的樣式 box.currentStyle.height

處理相容
\1 用 try catch 來處理(只有在不得已的情況下才使用它)
前提:必須保證 try 中的程式碼在不相容的瀏覽器中執行的時候報錯,這們才可以用 catch 捕獲到異常的資訊,進行其他處理 ( 消耗效能 )

function getCssVal( cur, attr){
	var val = null;
	try {
		val = document.getComputedStyle(cur,null)[attr];
	} catch(e){
		val = cur.currentStyle[attr];
	}
	return val;
}
console.log( getCssVal(box, 'fontFamily'));  // 'height'

\2 判斷瀏覽器是否存在這屬性,存在就相容,不存在就不相容(最常用 )
if( 'getComputedStyle' in window ) 或者 if( window.getComputedStyle )
\3 通過檢測瀏覽器版本和型別來處理相容
window.navigator.userAgent
if(/MSIE (6|7|8)/.test(navigator.userAgent))

處理相容後,用相容後的方法獲取值,標準瀏覽器和 IE 獲取的結果,部分樣式還是不一樣的,主要是由於兩個方法的不一樣

第一次升級:將獲取到的值去掉單位(parseFloat)
第二次升級 :有些樣式在不同瀏覽器中是不相容的 例如 opacity
opacity: 0.1; 透明度,在 IE 6-8 下不相容
filter: alphpa(opacity=10); 用濾鏡來處理
if( attr === "opacity" ) { val = cur.currentStyle["filter"]; } else { ... }
ps: 寫 CSS 時先初始化預設樣式,避免瀏覽器之間的差異,對 JS 獲取到的結果一致也是有幫助的

第二個引數傳入 after before 可以得到偽類的樣式
偽類:在一個元素標籤的前面或者後面,建立一個新的虛擬的標籤(可以給這個標籤增加樣式,內容等…)

.clearfix {      /*偽元素清浮動*/
	zoom: 1;
}
.clearfix {
	content: "";
	width: 0;
	height: 0;
	display: block;
	overflow: hidden;
	clear: both;
}

null / undefined
兩者都代表沒有,但是 null 是屬性存在,但是值不存在
undefined 是連這個屬性都不存在
document.parentNode (瀏覽器天生自帶的一個屬性,父親節點,HTML 結構層級關係中的上一級元素),值為 null, 因為頁面中 document 已經是最頂級的元素了
document.parentnode 值為 undefined 因為沒有這個屬性

offsetParent 父級參照物,預設最外層的元素是裡面所有元素的父級參照物
可以通過修改父級 position 的值( relative / absolute / fixed )來修改父級參照物
offsetTop / offsetLeft 當前元素外邊框距離父級參照物內邊框的距離

思考 :求出頁面任意一個元素距離 body 的偏移量
\1 先獲取自身的左偏移
\2 獲取父級參照物 P,加上 P 的偏移量和邊框
\3 基於當前 P,再找父級參照物,加上其偏移量和邊框,再往上找父級參照物,加上其偏移量和邊框,再往上找進行相加操作,直到父級參考物為 null

function getEleToBody(curEle){   // 父級參照物
	var totalLeft = null,totalTop=null, par = curEle.offsetParent;
	totalLeft += curEle.offsetLeft;
	totalTop += curEle.offsetTop;
	while(par){  // 迴圈的條件 
		// 加上父級的 偏移和邊框 
		totalLeft = totalLeft + par.offsetLeft + par.clientLeft;
		totalTop = totalTop + par.offsetTop + par.clientTop;
		
		par = par.offsetParent; // 重賦值
	}
	return { "totalLeft":totalLeft, "totalTop": totalTop };

}
console.log(getEleToBody(box));

> 瀏覽器捲去的寬度 / 高度

前面的 client 系列 / offset 系列 / scrollWidth / scrollHeight 都是隻讀屬性
scrollTop / scrollLeft 滾動條捲去的高度 / 寬度 , 這兩個是唯一可讀寫屬性
scrollTop 存在邊界值,超出邊界值無效
最小 0
最大 元素.scrollHeight - 元素.clientHeight

box.scrollTop = -1000; // 超出邊界範圍,回到頂部
console.log(box.scrollTop); // 結果為 0

ps:
a 標籤的 hover 樣式是相容的,其它的可能不相容
a 標籤
\ href = “” 為空,重新整理本頁面
\ href = “#idname” 頁面跳轉到 id 為 idname 處
\ href = “javascript:;” 取消頁面預設行為
css 選擇器
\ p ~ div 選擇 p 標籤後面的兄弟元素 div
\ p + div 選擇 p 標籤後面相鄰的一個 div 元素
a 標籤實現 tab 選項卡

設定 body 高度為可視區域的 5 倍高: html,body { height: 500%} html 也要寫上
設定每屏 li 為可視區域大小:
html > body > ul > li
html, body, ul, li 都設定了 height: 100%;檢視高度是一樣的

定時器:

var timer = window.setTimeout(function(){ },1000); // 1 秒後執行,執行後定時器清除
window.setInterval(function(){},1000); // 每秒執行一次,直到手動清除定時器

設定定時器是有返回值的,值為 數字,代表當前是第幾個定時器

清除定時器

window.clearTimeout(1);  // 清除第一個定時器(定時器是從1開始計數的)
window.clearInterval(timer); // 可清除 setTimeout 開啟的定時器

setTimeout 模擬 setInterval ( 遞迴思想 )

function fn(){
	// 優化:每次執行前,先把前面的定時器清除
	clearTimeout(timer);
	n++;
	console.log( n + 'js 程式碼');
	if( 5 === n ){ return; }
	timer = setTimeout(fn,1000);
}
fn();

緩步動畫

var duration = 500; // 總時間 500ms 回到頂部 
var interval = 10;  // 頻率  多長時間走一次 10ms 一次
var target = document.documentElement.scrollTop || document.body.scrollTop; // 總距離 
var step = target / duration * interval; // 每一次走的距離  步長

再開定時器, setInterval( function(){...}, interval );
回頂部的按鈕條件出現 ( 距離超過一屏出現,少於一屏消失 )

window.onscroll = function(){
	// 頁面捲去的距離
	var curTop = document.documentElement.scrollTop || document.body.scrollTop; 
	// 當前螢幕高度
	var het = document.documentElement.clientHeight || document.body.clientHeight; 
	backTop.style.display = curTop > het ? 'block' : 'none';
}

點選回頂部按鈕時也消失,只事件中新增 this.style.display = "none" 沒用,因為 window.onscroll 一直在監聽
所以,在點選後,要把 window.onscroll 事件置空,在最後關閉定時器的時候再開啟這個事件 (處理:window.onscroll = 函式名; )

文字左右跑馬燈
滑鼠滑上時停止移動,移開滑鼠繼續移動
onmouseover
onmouseout
white-space: nowrap; 強制文字不換行
原理: 複製一份文字到後面,當前一份完全走完的時候,重置 scrollLeft 為 0;
文字向左走,到最大值的時候自動停止移動,但定時器還沒有消失
判斷程式碼相加前後值相等,
讓塊級元素同行顯示
\ display: block;
\ display: inline-block; 注意空格的問題

JS 中的兩種程式設計思想: 同步 、非同步
同步:上一件事情沒有完成,繼續處理上一件事件,只有上一件完成了,才會做下一件事件(JS 中大部分都是同步程式設計的)
非同步: 規劃要做一件事情,但是不是當前立馬去執行,需要等一段時間,這樣,繼續執行下面的操作,只有後面的事情都處理完成了,才會返回處理之前的事情 ,如果下面的事情並沒有處理完成,不管之前的事情有沒有到時間,都只能等著

JS 中非同步程式設計只有四種情況
定時器
所有的事件繫結
Ajax 讀取資料的時候,一般設定為非同步
回撥函式

var n = 0; 
window.setTimeout(function(){
	n++;
	console.log(n); // 1 第 2 個輸出
},0);
console.log(n); // 0 第 1 個輸出

\1 每一個瀏覽器對於定時器的等待時間都有一個最小的值,谷歌:5-6 ms, IE: 10-13 ms ,如果設定的等待時間小於這個值,也不起作用,還是要等到最小時間後才執行

\2 在上面程式碼的最後面加 while( 1 ) { ..} 程式碼死迴圈,while 後面的程式碼不執行,定時器中的程式碼也不執行(定時器中設定的等待時間,時間到了,程式碼也不一定執行)

\3 定義一個變數 n ;
a 再設定兩個定時器,前一個定時器等待的時間要長一些 ;
b 列印變數 n ;
c 空的 for 迴圈, i 到 100000;
d 再列印變數 n;

> 圖片延遲載入 (優化)

網站效能優化:
\ 儘量減少向伺服器請求的次數 “減少 HTTP 請求”
css / js 檔案進行合併
ICON 圖片也進行合併 -》 雪碧圖 css spite
圖片的延遲載入
資料的非同步載入
在移動端,如果做的是一個簡單的宣傳頁,儘量把 CSS / JS 寫成內嵌式

圖片延遲載入 ,作用:保證頁面開啟的速度 
原理:
\1 對於首屏內容中的圖片,首先給對應的區域一張預設圖片佔著位置(預設圖非常小,一般可以維持在 5kb 以內),當首屏載入完成後(或者給一個個延遲的時間),再開始載入真實的圖片
\2 對於其它屏的圖片,也是一張預設圖佔位置,當滾動條滾動到對應區域的時候,再開始載入真實的圖片

擴充套件: 資料的非同步載入,開始只把前兩屏的資料進行繫結,後面的資料不進行處理,當頁面滾動到對應區域的時候再重新請求資料,然後繫結渲染資料

相關程式碼: div.box > img
開始時,img 標籤 沒有設定 src 屬性,元素設定 display: none; 因為沒有 src 屬性,頁面會顯示一張碎圖,不美觀,將元素隱藏,當真實的圖片載入時再顯示

給圖片父級 div.box 設定背景: background: url("img/default.gif") no-repeat center center #e1e1e1; 用預設圖佔位,告訴使用者此處圖片正在載入中
圖片標籤: <img src="" trueImg="img/jd.jpg"/>
考慮:獲取到自定義屬性上的 真實圖片地址就直接賦值給圖片的 src 屬性是不嚴謹的,地址可能出錯,控制檯也會報錯,這樣顯示的頁面還是出錯碎圖
得到地址後,驗證地址的有效性,才進行賦值操作

window.setTimeout(function(){
	var tempImg = new Image; // 建立一個臨時的 img 物件 
	tempImg.src = oImag.getAttribute('trueImg');
	tempImg.onload = function(){  // 當圖片能夠正常載入才執行
		console.log("圖片載入完成!")
		oImag.style.display = 'block';
		oImag.src = oImag.getAttribute('trueImg');
		tempImg = null; 

		var nowDate = new Date;
		console.log(nowDate - newDate); // 圖片載入用時
	}
	console.log("圖片正在載入中...");
	var newDate = new Date; // 計算圖片載入時間 
},500);

其它屏圖片的載入
window.onscroll 事件中:
當 ( 圖片的容器高度 + 圖片距離頁面的高度 )< (一屏的高度 + 頁面捲去的高度度)圖片載入
當條件成立時,載入真實的圖片,第一次載入完成後,頁面繼續滾動,條件一直成立,又重新載入了圖片,影響網站效能
可以在條件成立後,給元素加一自定義屬性 banner.isload = true; 表示載入真實圖片的操作已經處理過了,不管是否正確載入了圖片,都不再處理圖片載入了
條件判斷中 if( banner.isload ) { return ; }

例項: 移動端多張圖上延遲載入
做移動端響應佈局必須加 meta 標籤name = viewport :快捷鍵 meta:vp 按 tab

右側文字自適應
圖片 img 樣式 display: block; border: none;