1、大綱
JS中的盒子模型
- clientWidth/clientHeight
- clientTop/clientLeft
- offsetWidth/offsetHeight
- scrollWidth/scrollHeight
- getCss方法的封裝
- offsetTop/offsetLeft
- offsetParent
- offset方法的封裝:獲取盒子偏移量
- scrollLeft/scrollTop
- 定時器基礎應用
- 案例:回撥頂部
- 案例:跑馬燈
- 案例:瀑布流
- 案例:京東樓層導航
- ...
圖片延遲載入
- 響應式佈局:流式佈局發
- 圖片懶載入的意義
- 單張圖片延遲載入
- 多張圖片延遲載入
- JS同步非同步程式設計
- 由圖片延遲載入引發的一些思考
2、傳統和新的CSS盒子模型
css盒子模型
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>css盒子模型</title>
<style>
*{
margin:0;
padding:0;
}
.box{
margin: 50px auto;
padding: 20px;
width: 200px;
height: 200px;
border: 10px solid green;
background: lightcoral;
line-height:23px;
}
</style>
</head>
<body>
<div class="box" id="box">
夫君子之行,靜以修身,儉以養德。非淡泊無以明志,非寧靜無以致遠。
夫學須靜也,才須學也,非學無以廣才,非志無以成學。淫慢則不能勵精,
險躁則不能治性。年與時馳,意與日去,遂成枯落,多不接世,悲守窮廬,
將復何及!
</div>
</body>
</html>
複製程式碼
3、JS盒子模型之clientWidth和clientHight
JS盒子模型
提供一些屬性和方法用來描述當前盒子的樣式的
clientWidth和clientHight
當前盒子可視區域的寬度和高度
可視區域:內容寬高+padding
clientWidth = width + padding(Left/Right)
clientHight = height + padding(Top/Bottom)
和內容是否溢位以及我們是否設定了overflow:hidden沒有關係
專案中:
// 獲取當前頁面一螢幕的寬度(加或者是為了相容所有的瀏覽器)
document.documentElement.clientWidth || document.body.clientWidth
// 獲取當前頁面一螢幕的高度
document.documentElement.clientHeight || document.body.clientHeight
複製程式碼
面試題: 讓一個盒子在整個頁面水平和垂直都居中的位置?如果不知道盒子的寬度和高度如何處理?
css
//使用定位,需要知道盒子的具體寬高才可以
.box{
position: absolute;
top:50%;
left: 50%;
margin: -100px 0 0 -100px;
width: 200px;
height: 200px;
background: lightcoral;
}
//使用定位:不需要知道盒子的具體寬高(不相容ie低版本瀏覽器)
.box{
position: absolute;
top:0;
left: 0;
bottom: 0;
right: 0;
margin: auto;
width: 200px;
height: 200px;
background: lightcoral;
}
//使用css3的flex伸縮盒模型(不相容ie,低版本安卓系統不相容)
html{
height: 100%;
}
body{
display: flex;
height: 100%;
flex-flow: row wrap;
align-items: center;
justify-content: center;
}
.box{
width: 200px;
height: 200px;
background: lightcoral;
}
複製程式碼
js
// css
.box{
position: absolute;
width: 200px;
height: 200px;
background: lightcoral;
}
// JS中只要獲取到當前盒子具體的left/top值即可
// 一螢幕的寬高-盒子的寬高,最後除以2,獲取的值就是它應該具備的left/top(這個值可以讓他處於頁面中間)
var winW = document.documentElement.clientWidth || document.body.clientWidth;
var winH = document.documentElement.clientHeight || document.body.clientHeight;
var boxW = box.offsetWidth;
var boxH = box.offsetHeight;
box.style.left = (winW - boxW) / 2 + "px";
box.style.top = (winH - boxH) / 2 + "px";
複製程式碼
4、JS盒子模型之clientTop和clientLeft
clientTop和clientLeft
只有top和left,沒有right和bottom這兩個屬性
clientTop:盒子上邊框的高度
clientLeft:左邊框的寬度
獲取的結果其實就是border-width值
通過js盒子模型屬性獲取的結果是不帶單位的,而且只能是整數(它會自動四捨五入)
.box{
border: 10.8px solid red;
}
box.clientLeft => 11
複製程式碼
5、JS盒子模型之offsetWidth和offsetHeight
在clientWidth和clientHeight的基礎上加上盒子的邊框即可
和內容是否溢位沒關係
真實專案中如果想獲取一個盒子的寬度和高度,我們一般用offsetWidth(而不是clientWidth),border也算是當前盒子的一部分
6、JS盒子模型之scrollHeight和scrollWidth
scrollHeight和scrollWidth
沒有內容溢位
- 獲取的結果和clientWidth/clientHight是一樣的
有內容溢位
- 真實內容的寬度或者高度(包含溢位的內容),再加上左padding或者上padding
有內容溢位的情況下,我們通過scrollHeight和scrollWidth獲取的結果是一個約等於的值
- 1)有內容溢位,每個瀏覽器由於對行高或者文字的渲染不一樣,獲取的結果也是不一樣的
- 2)是否設定overflow:hidden對最後獲取的結果也有影響
// 獲取當前頁面真實高度(包含溢位內容)
document.documentElement.scrollHeight || document.body.scrollHeight
複製程式碼
7、獲取當前元素所有經過瀏覽器計算的樣式
在js中獲取元素具體的樣式值
通過js盒子模型屬性獲取的結果都是盒子的組合樣式值,不能直接獲取某一個具體樣式值,例如:我就想獲取左padding...
curEle.style.xxx
獲取當前元素所有寫在行內樣式上的樣式值
特殊:只有把樣式寫在行內樣式上,才可以通過這種辦法獲取到(寫在其他地方的樣式是獲取不到的)
這種辦法在真實專案中使用的特別少:因為我們不可能把所有元素的樣式都寫在行內上(這樣要內嵌和外聯式就沒用了)
window.getComputedStyle / currentStyle
只要當前元素在頁面中顯示出來了,我們就可以獲取其樣式值(不管寫在行內還是樣式表中);
也就是獲取所有經過瀏覽器計算過的樣式(當前元素只要能再頁面中展示,那麼它的所有樣式都是經過瀏覽器計算的,
包含一些你沒有設定,瀏覽器按照預設樣式渲染的樣式)
window.getComputedStyle:適用於標準瀏覽器,但是在ie6~8中就不相容了,ie6~8下我們使用curEle.currentStyle來獲取需要的樣式值
複製程式碼
獲取當前元素所有經過瀏覽器計算的樣式及相容性處理
通過getComputedStyle獲取的結果是一個物件,物件中包含了所有被瀏覽器計算過的樣式屬性及屬性值
window.getComputedStyle([當前需要操作的元素],[當前元素的偽類,一般寫null])
window.getComputedStyle(box,null)['paddingLeft']這種方式可以在獲取的物件中找到某一個具體樣式屬性
的值(通過.paddingLeft也可以)
在ie6~8瀏覽器中window全域性物件中,並沒有提供getComputedStyle這個屬性方法,我們只能使用currentStyle
屬性獲取元素的樣式
[當前元素].currentStyle 獲取的結果也是一個包含當前元素所有的樣式屬性和值的物件
box.currentStyle.paddingLeft/ box.currentStyle['paddingLeft']
以後再想獲取元素的樣式,我們需要寫兩套,這樣的話,我們可以把獲取樣式的操作封裝成為一個公共的方法:getCss
getCss:獲取當前元素的某一個樣式屬性值
@parameter:
curEle:當前需要操作的元素
attr:當前需要獲取的樣式屬性名
@return
獲取的樣式屬性值
function getCss(curEle,attr){
var value=null;
if('getComputedStyle' in window){
value = window.getComputedStyle(curEle,null)[attr];
}else{
value = curEle.currentStyle[attr];
}
return value;
}
複製程式碼
8、getCss獲取元素樣式方法的優化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>css盒子模型</title>
<style>
*{
margin:0;
padding:0;
}
.box{
width: 200px;
height: 200px;
background: lightcoral;
opacity: 0.2;
filter: alpha(opacity=20);
/* ie低版本瀏覽器不支援opacity,需要使用濾鏡出來*/
}
</style>
</head>
<body>
<div class="box" id="box"></div>
<script>
// 優化2
// 已知:給元素設定透明度,需要寫兩套(相容ie6~8)
// opacity:n
// filter:alpha(opacity=n*100)
// 在js中如果我們想要獲取元素的透明度,我們一般都會這樣執行方法
// var result = getCss(box,'opacity')
// 這樣寫會存在一些問題:
// 1、標準瀏覽器下可以獲取到值,但是ie6~8下獲取不到結果(ie6~8識別filter不識別opacity)
// => 需要處理:在ie6~8下,如果我們傳遞的是opacity(使用者想獲取的是透明度),我們應該用
// filter獲取
// 2、通過filter獲取的結果是'alpha(opacity=xxx)',通過opacity獲取的直接是xxx值 =>解決:
// 我們應該把通過filter獲取的結果中的具體值捕獲到,然後除以100,讓其返回的值和opacit一樣
// 正則捕獲
// /\d+/ :不行,因為獲取的值可能是小數
// /\d+(\.\d+)?/ : ok
// /^alpha\(opacity=(.+)\)$/:捕獲第一個小分組內容
// ...
// 優化1:去除獲取結果的單位:專案中我們一般都會把獲取的樣式值進行後續的計算,不帶單位方法計算
function getCss(curEle,attr){
var value=null;
// 獲取樣式值-----------------------------------
if('getComputedStyle' in window){
value = window.getComputedStyle(curEle,null)[attr];
}else{
// ie6~8下處理透明度
if (attr === 'opacity'){
value = curEle.currentStyle['filter'];
// 優化2:把獲取的結果轉換為和opacity一樣的結果filter:alpha(opacity=20)
var reg = /^alpha\(opacity=(.+)\)$/;
reg.test(value) ? value = reg.exec(value)[1] / 100 : value = 1;
} else{
value = curEle.currentStyle[attr];
}
value = curEle.currentStyle[attr];
}
// 去除獲取值的單位-----------------------------------
// 首先把我們獲取的結果轉換為數字,然後看是否為NaN,不是NaN說明可以去除單位,我們把轉換的結果返回,如果是NaN
// ,說明當前獲取的結果並不是數字+單位的,此時我們把之前獲取的值返回即可
var temp = parseFloat(value);
!isNaN(temp) ? value = temp : null;
return value;
}
console.log(getCss(box,"color"));
console.log(getCss(box,"width"));
</script>
</body>
</html>
複製程式碼
9、解決isNaN去除單位對於複合值不準確的問題
10、setCss給元素設定樣式方法的封裝
方法一:符合加單位的css樣式(傳遞的是純數字,大部分css樣式都需要加單位)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>css盒子模型</title>
<style>
* {
margin: 0;
padding: 0;
}
.box {
width: 200px;
height: 200px;
background: lightcoral;
opacity: 0.2;
filter: alpha(opacity=20);
/* ie低版本瀏覽器不支援opacity,需要使用濾鏡出來*/
}
</style>
</head>
<body>
<div class="box" id="box" style="color: #000;">123456</div>
<script>
// 設定元素的樣式
// curEle.style.xxx=xxx 設定當前元素的行內樣式值(JS中設定的樣式一般都要設定在行內樣式上:行內上的樣式優先順序最大)
// curEle.className = xxx 設定元素的樣式類名 (addClass)
// box.style.backgroundColor = 'lightblue';
function setCss(curEle, attr, value) {
// 如果傳遞的value值沒有單位,我們根據需求自動補充單位(px)
// 1、並不是所有的樣式屬性傳遞進來的值都要補充單位
// 需要補充單位的常用樣式屬性:width、height、margin、padding、marginLeft...、paddingLeft...、top、left、right、
// bottom、borderWidth...
// 2、傳遞的值已經存在單位,我們不需要再補充,沒有單位我們再補充
// var reg = /^(width|height|margin|padding|marginLeft|marginRight|marginTop|marginBottom|paddingLeft|paddingRight|paddingTop|paddingBottom|top|left|bottom|right|borderWidth)$/i;
var reg = /^(width|height|((margin|padding)?(top|left|right|bottom)?)|borderWidth)$/i;
if (reg.test(attr)) {
if (!isNaN(value)) {
// 傳遞的是純數字,我們需要加單位
value += 'px';
}
}
curEle['style'][attr] = value;
}
setCss(box, "backgroundColor", "red");
setCss(box, "padding", "20");
setCss(box, "padding", "20px");
setCss(box, "padding", "20px 30px");
setCss(box, "padding", "20 30");//這個這裡沒做處理不會執行
setCss(box, "paddingleft", "20");//瀏覽器不能識別小寫 最終不執行curEle['style'][attr] = value;
setCss(box, "paddingLeft", "150");
</script>
</body>
</html>
複製程式碼
方法一:不符合加單位的css樣式(傳遞的是純數字,大部分css樣式都需要加單位,但是某些特殊的樣式是不需要加單位的)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>css盒子模型</title>
<style>
* {
margin: 0;
padding: 0;
}
.box {
width: 200px;
height: 200px;
background: lightcoral;
opacity: 0.2;
filter: alpha(opacity=20);
/* ie低版本瀏覽器不支援opacity,需要使用濾鏡出來*/
}
</style>
</head>
<body>
<div class="box" id="box" style="color: #000;">123456</div>
<script>
function setCss(curEle,attr,value) {
// 如果傳遞的是opacity,我們需要相容處理透明度
if (attr === "opacity") {
curEle.style.opacity = value;
curEle.style.filter = "alpha(opacity=" + value * 100 + ")";
}
// 我們也可以反思路驗證:傳遞的是純數字,大部分都需要加單位,但是某些特殊的樣式是不需要加單位的
// 不需要加單位:zIndex、zoom、lineHeight...
!isNaN(value) && !/^(zIndex|zoom|lineHeight|fontWeight)$/i.test(value) ? value += "px" : null;
curEle['style'][attr] = value;
}
setCss(box,"padding","20");
setCss(box,"opacity","0.1");
</script>
</body>
</html>
複製程式碼
11、setGroupCss實現批量設定元素的樣式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>css盒子模型</title>
<style>
* {
margin: 0;
padding: 0;
}
.box {
width: 200px;
height: 200px;
background: lightcoral;
opacity: 0.2;
filter: alpha(opacity=20);
/* ie低版本瀏覽器不支援opacity,需要使用濾鏡出來*/
}
</style>
</head>
<body>
<div class="box" id="box" style="color: #000;">123456</div>
<script>
function setCss(curEle,attr,value) {
// 如果傳遞的是opacity,我們需要相容處理透明度
if (attr === "opacity") {
curEle.style.opacity = value;
curEle.style.filter = "alpha(opacity=" + value * 100 + ")";
}
// 我們也可以反思路驗證:傳遞的是純數字,大部分都需要加單位,但是某些特殊的樣式是不需要加單位的
// 不需要加單位:zIndex、zoom、lineHeight...
!isNaN(value) && !/^(zIndex|zoom|lineHeight|fontWeight)$/i.test(value) ? value += "px" : null;
curEle['style'][attr] = value;
}
// --------批量給當前元素設定css樣式(在setCss上的擴充)----------------------------------------------------
function setGroupCss(curEle,options) {
//檢測options是不是物件,typeof不行,typeof檢測正則,物件,陣列和null都是物件
if(Object.prototype.toString.call(options) !== '[object Object]') return;
for (var attr in options) {
if (options.hasOwnProperty(attr)) {
setCss(curEle,attr,options[attr]);
}
}
}
setGroupCss(box, {
width:300,
height:300,
padding:50,
opacity:0.5,
backgroundColor:"orange"
});
</script>
</body>
</html>
複製程式碼
12、封裝css方法、實現設定、批量設定、獲取元素的樣式(封裝css函式的程式設計思想很重要)
var utils = (function () {
// =>toArray:把類陣列轉換為陣列(相容所有瀏覽器的)
var toArray = function toArray(classAry) {
var ary = [];
try {
ary = Array.prototype.slice.call(classAry);
} catch (e) {
for (var i = 0; i < classAry.length; i++) {
ary[ary.length] = classAry[i];
}
}
return ary;
};
// =>toJSON:把JSON格式的字串轉換為JSON格式的物件
var toJSON = function toJSON(str) {
//JSON.parse()不相容的原因是因為window下沒有JSON這個屬性
return "JSON" in window ? JSON.parse(str) : eval('('+ str +')');
};
// =>getCss:獲取當前元素的某一個樣式屬性值
var getCss = function (curEle, attr) {
var value = null,
reg = null;
if (window.getComputedStyle) {
value = window.getComputedStyle(curEle,null)[attr];
}else{
if (attr === 'opacity') {
value = curEle.currentStyle['filter'];
reg = /^alpha\(opacity=(.+)\)$/i;
value = reg.test(value)?reg.exec(value)[1] / 100 : 1;
} else {
value = curEle.currentStyle[attr];
}
value = curEle.currentStyle[attr];//相容ie6~8
}
reg = /^-?\d+(\.\d+)?(px|pt|rem|em)?$/i;
reg.test(value) ? value = parseFloat(value) : null;
return value;
};
// =>setCss:給當前元素的某一個樣式屬性設定值
var setCss = function (curEle, attr, value) {
if (attr === 'opacity') {
curEle['style']['opacity'] = value;
curEle['style']['filter'] = 'alpha(opacity='+ value * 100 +')';
return;
}
!isNaN(value) && !/^(zIndex|zoom|lineHeight|fontWeight)/i.test(attr) ? value += "px" : null;
curEle['style'][attr] = value;
};
// =>setGroupCss:給當前元素批量設定樣式屬性值
var setGroupCss = function (curEle, options) {
// 呼叫object基類原型上的toString方法實現資料型別檢測,檢測資料物件
// ({}).toString.call(options) <=> Object.prototype.toString.call(options)
if(({}).toString.call(options) !== '[object Object]') return;
for (var attr in options) {
if (options.hasOwnProperty(attr)) {
setCss(curEle, sttr, options[attr]);
}
}
};
// =>css:整合設定樣式、獲取樣式、批量設定樣式於一身的綜合方法 類似jq實現css原理
var css = function () {
var len = arguments.length,
type = Object.prototype.toString.call(arguments[1]),
fn = getCss;
// if (len >= 3) {
// //=>設定樣式
// // setCss(arguments[0],arguments[1],arguments[2]);把類陣列的每一項值都傳遞給setCss()
// setCss.apply(this,arguments);
// return;
// }
// if (len === 2 && Object.prototype.toString.call(arguments[1])==='[object Object]') {
// // =>批量設定樣式
// setGroupCss.apply(this, arguments);
// return;
// }
// return getCss.apply(this, arguments);
// 優化以上方法
len >=3 ? fn = setCss : (len === 2 && type ==='[object Object]' ? fn = setGroupCss : null);
return fn.apply(this, arguments)
};
return {
toArray: toArray,
toJSON: toJSON,
css: css
}
})();
// utils.css(box,'padding')//=>獲取樣式
// utils.css(box,'padding','20')//=>設定樣式
// utils.css(box,{
// padding:30,
// margin:20
// })//=>批量設定樣式
複製程式碼
13、父級參照物及盒子的偏移量
offsetParent:父級參照物(父級參照物不等價於父級元素:父級參照物和它的父級元素沒有直接的關係)
-
父級參照物:同一個平面中最外層的容器是所有裡層盒子的父級參照物
-
預設情況下:一個頁面中所有元素的父級參照物都是body(而body的父級參照物是null)
-
當我們給元素設定定位之後,會改變元素的父級參照物(因為設定定位會讓元素脫離平面(脫離文件流))
offsetLeft * offsetTop
-
當前元素的外邊框 距離 父級參照物的內邊框 的偏移量(左偏移/上偏移)
-
標準的ie8瀏覽器有特殊性:它的偏移量是從 當前元素外邊框~父級參照物的外邊框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>父級參照物及盒子的偏移量</title>
<style>
*{margin: 0; padding: 0;}
html,body{
height: 100%;
overflow: hidden;
}
.outer{
margin: 50px auto;
width: 260px;
height: 260px;
border: 20px solid green;
}
.inner{
margin: 20px auto;
width: 80px;
height: 80px;
border: 20px solid red;
}
.center{
margin: 10px auto;
width: 20px;
height: 20px;
border: 20px solid blue;
}
</style>
</head>
<body>
<div class="outer" id="outer">
<div class="inner" id="inner">
<div class="center" id="center"></div>
</div>
</div>
<script src="utils.js""></script>
<script>
utils.css(inner,"position","relative")
console.log(center.offsetParent);
console.log(inner.offsetParent);
console.log(outer.offsetParent);
</script>
</body>
</html>
複製程式碼
14、獲取當前元素距離BODY的偏移量(offset方法的封裝)
獲取頁面中任何一個元素距離body的左偏移和上偏移(它的父級參照物是誰不一定)
思路:
1、首先獲取自己的偏移量 以及自己的父級參照物
2、如果自己的父級參照物不是body,我們加上父級參照物的邊框和偏移量 ... 一直加到某一次找到的父級參照物是body為止
3、標準ie8瀏覽器不需要加邊框(偏移量已經包含父級參照物的邊框了)
console.log(navigator.userAgent);//獲取瀏覽器的版本資訊
/MSIE 8/i.test(navigator.userAgent);//判斷是不是ie8
沒有getComputerStyle這個屬性說明是ie6~8
utils.js
var utils = (function () {
// =>toArray:把類陣列轉換為陣列(相容所有瀏覽器的)
var toArray = function toArray(classAry) {
var ary = [];
try {
ary = Array.prototype.slice.call(classAry);
} catch (e) {
for (var i = 0; i < classAry.length; i++) {
ary[ary.length] = classAry[i];
}
}
return ary;
};
// =>toJSON:把JSON格式的字串轉換為JSON格式的物件
var toJSON = function toJSON(str) {
//JSON.parse()不相容的原因是因為window下沒有JSON這個屬性
return "JSON" in window ? JSON.parse(str) : eval('('+ str +')');
};
// =>getCss:獲取當前元素的某一個樣式屬性值
var getCss = function (curEle, attr) {
var value = null,
reg = null;
if (window.getComputedStyle) {
value = window.getComputedStyle(curEle,null)[attr];
}else{
if (attr === 'opacity') {
value = curEle.currentStyle['filter'];
reg = /^alpha\(opacity=(.+)\)$/i;
value = reg.test(value)?reg.exec(value)[1] / 100 : 1;
} else {
value = curEle.currentStyle[attr];
}
value = curEle.currentStyle[attr];//相容ie6~8
}
reg = /^-?\d+(\.\d+)?(px|pt|rem|em)?$/i;
reg.test(value) ? value = parseFloat(value) : null;
return value;
};
// =>setCss:給當前元素的某一個樣式屬性設定值
var setCss = function (curEle, attr, value) {
if (attr === 'opacity') {
curEle['style']['opacity'] = value;
curEle['style']['filter'] = 'alpha(opacity='+ value * 100 +')';
return;
}
!isNaN(value) && !/^(zIndex|zoom|lineHeight|fontWeight)/i.test(attr) ? value += "px" : null;
curEle['style'][attr] = value;
};
// =>setGroupCss:給當前元素批量設定樣式屬性值
var setGroupCss = function (curEle, options) {
// 呼叫object基類原型上的toString方法實現資料型別檢測,檢測資料物件
// ({}).toString.call(options) <=> Object.prototype.toString.call(options)
if(({}).toString.call(options) !== '[object Object]') return;
for (var attr in options) {
if (options.hasOwnProperty(attr)) {
setCss(curEle, sttr, options[attr]);
}
}
};
// =>css:整合設定樣式、獲取樣式、批量設定樣式於一身的綜合方法 類似jq實現css原理
var css = function () {
var len = arguments.length,
type = Object.prototype.toString.call(arguments[1]),
fn = getCss;
// if (len >= 3) {
// //=>設定樣式
// // setCss(arguments[0],arguments[1],arguments[2]);把類陣列的每一項值都傳遞給setCss()
// setCss.apply(this,arguments);
// return;
// }
// if (len === 2 && Object.prototype.toString.call(arguments[1])==='[object Object]') {
// // =>批量設定樣式
// setGroupCss.apply(this, arguments);
// return;
// }
// return getCss.apply(this, arguments);
// 優化以上方法
len >=3 ? fn = setCss : (len === 2 && type ==='[object Object]' ? fn = setGroupCss : null);
return fn.apply(this, arguments)
};
// =>offset:獲取當前元素距離body的偏移量,包括左偏移和上偏移
var offset = function (curEle) {
var l = curEle.offsetLeft,//獲取自己本身左偏移量
t = curEle.offsetTop,//獲取自己本身上偏移量
p = curEle.offsetParent;//獲取自己的父級參照物
// console.log(document.body.tagName);//=> 'BODY'
while (p.tagName !== 'BODY') {//父元素不是body繼續找當前父級參照物的父級參照物進行累加
if(!/MSIE 8/i.test(navigator.userAgent)){//標準ie8瀏覽器不需要加邊框
l += p.clientLeft;//父級參照物的左邊框
t += p.clientTop;//父級參照物的上邊框
}
l += p.offsetLeft;//父級參照物的左偏移
t += p.offsetTop;//父級參照物的上偏移
p = p.offsetParent;//獲取當前父級參照物的父級參照物
}
return {top: t, left: l};
};
return {
toArray: toArray,
toJSON: toJSON,
css: css,
offset: offset
}
})();
// utils.css(box,'padding')//=>獲取樣式
// utils.css(box,'padding','20')//=>設定樣式
// utils.css(box,{
// padding:30,
// margin:20
// })//=>批量設定樣式
複製程式碼
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>父級參照物及盒子的偏移量</title>
<style>
*{margin: 0; padding: 0;}
html,body{
height: 100%;
overflow: hidden;
}
.outer{
margin: 50px auto;
width: 260px;
height: 260px;
border: 20px solid green;
}
.inner{
margin: 20px auto;
width: 80px;
height: 80px;
border: 20px solid red;
}
.center{
margin: 10px auto;
width: 20px;
height: 20px;
border: 20px solid blue;
}
</style>
</head>
<body>
<div class="outer" id="outer">
<div class="inner" id="inner">
<div class="center" id="center"></div>
</div>
</div>
<script src="utils.js""></script>
<script>
// utils.css(inner,"position","relative")
// console.log(center.offsetParent);
// console.log(inner.offsetParent);
// console.log(outer.offsetParent);
var obj = utils.offset(center),
t = obj.top,
l = obj.left;
console.log(t, l);
</script>
</body>
</html>
複製程式碼
15、scrollLeft和scrollTop詳細解讀
scrollLeft:橫向滾動條捲去的寬度
scrollTop:豎向滾動條捲去的高度
console.log(document.documentElement.scrollTop || document.body.scrollTop);
存在最大值和最小值
最小值:0
最大值:scrollHeight - clientHeight 頁面真實高度減去一螢幕高度
前面講的js盒子模型屬性都是‘只讀屬性’只能通過屬性獲取值,不可以修改屬性的值(修改也不生效)
但是這兩個屬性是可讀寫屬性:不僅僅可以獲取值,還可以修改它的值
document.documentElement.scrollTo = 0 || document.body.scrollTop = 0;
utils.js
var utils = (function () {
// =>toArray:把類陣列轉換為陣列(相容所有瀏覽器的)
var toArray = function toArray(classAry) {
var ary = [];
try {
ary = Array.prototype.slice.call(classAry);
} catch (e) {
for (var i = 0; i < classAry.length; i++) {
ary[ary.length] = classAry[i];
}
}
return ary;
};
// =>toJSON:把JSON格式的字串轉換為JSON格式的物件
var toJSON = function toJSON(str) {
//JSON.parse()不相容的原因是因為window下沒有JSON這個屬性
return "JSON" in window ? JSON.parse(str) : eval('('+ str +')');
};
// =>getCss:獲取當前元素的某一個樣式屬性值
var getCss = function (curEle, attr) {
var value = null,
reg = null;
if (window.getComputedStyle) {
value = window.getComputedStyle(curEle,null)[attr];
}else{
if (attr === 'opacity') {
value = curEle.currentStyle['filter'];
reg = /^alpha\(opacity=(.+)\)$/i;
value = reg.test(value)?reg.exec(value)[1] / 100 : 1;
} else {
value = curEle.currentStyle[attr];
}
value = curEle.currentStyle[attr];//相容ie6~8
}
reg = /^-?\d+(\.\d+)?(px|pt|rem|em)?$/i;
reg.test(value) ? value = parseFloat(value) : null;
return value;
};
// =>setCss:給當前元素的某一個樣式屬性設定值
var setCss = function (curEle, attr, value) {
if (attr === 'opacity') {
curEle['style']['opacity'] = value;
curEle['style']['filter'] = 'alpha(opacity='+ value * 100 +')';
return;
}
!isNaN(value) && !/^(zIndex|zoom|lineHeight|fontWeight)/i.test(attr) ? value += "px" : null;
curEle['style'][attr] = value;
};
// =>setGroupCss:給當前元素批量設定樣式屬性值
var setGroupCss = function (curEle, options) {
// 呼叫object基類原型上的toString方法實現資料型別檢測,檢測資料物件
// ({}).toString.call(options) <=> Object.prototype.toString.call(options)
if(({}).toString.call(options) !== '[object Object]') return;
for (var attr in options) {
if (options.hasOwnProperty(attr)) {
setCss(curEle, sttr, options[attr]);
}
}
};
// =>css:整合設定樣式、獲取樣式、批量設定樣式於一身的綜合方法 類似jq實現css原理
var css = function () {
var len = arguments.length,
type = Object.prototype.toString.call(arguments[1]),
fn = getCss;
// if (len >= 3) {
// //=>設定樣式
// // setCss(arguments[0],arguments[1],arguments[2]);把類陣列的每一項值都傳遞給setCss()
// setCss.apply(this,arguments);
// return;
// }
// if (len === 2 && Object.prototype.toString.call(arguments[1])==='[object Object]') {
// // =>批量設定樣式
// setGroupCss.apply(this, arguments);
// return;
// }
// return getCss.apply(this, arguments);
// 優化以上方法
len >=3 ? fn = setCss : (len === 2 && type ==='[object Object]' ? fn = setGroupCss : null);
return fn.apply(this, arguments)
};
// =>offset:獲取當前元素距離body的偏移量,包括左偏移和上偏移
var offset = function (curEle) {
var l = curEle.offsetLeft,//獲取自己本身左偏移量
t = curEle.offsetTop,//獲取自己本身上偏移量
p = curEle.offsetParent;//獲取自己的父級參照物
// console.log(document.body.tagName);//=> 'BODY'
while (p.tagName !== 'BODY') {//父元素不是body繼續找當前父級參照物的父級參照物進行累加
if(!/MSIE 8/i.test(navigator.userAgent)){//標準ie8瀏覽器不需要加邊框
l += p.clientLeft;//父級參照物的左邊框
t += p.clientTop;//父級參照物的上邊框
}
l += p.offsetLeft;//父級參照物的左偏移
t += p.offsetTop;//父級參照物的上偏移
p = p.offsetParent;//獲取當前父級參照物的父級參照物
}
return {top: t, left: l};
};
// =>winBox:操作有關於瀏覽器的js盒子模型屬性,處理了相容性
var winBox = function (attr,value) {
if(typeof value !== 'undefined') {
document.documentElement[attr] = value;
document.body[attr] = value;
return;
}
return document.documentElement[attr] || document.body[attr];
};
// winBox('clientHeight')//獲取屬性值
// winBox('scrollTop',0)//設定屬性值
return {
toArray: toArray,
toJSON: toJSON,
css: css,
offset: offset,
winBox: winBox
}
})();
// utils.css(box,'padding')//=>獲取樣式
// utils.css(box,'padding','20')//=>設定樣式
// utils.css(box,{
// padding:30,
// margin:20
// })//=>批量設定樣式
複製程式碼
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>scrollLeft和scrollTop詳細解讀</title>
<style>
*{margin: 0; padding: 0;}
html,body{
height: 1000%;
/* css3新增加的;背景顏色的線型漸變 */
background: -webkit-linear-gradient(top left,lightcoral,lightblue,
lightgreen,lightcyan,lightgoldenrodyellow);
}
</style>
</head>
<body>
<script src="utils.js"></script>
<script>
console.log(utils.winBox('scrollTop'));//獲取屬性值
utils.winBox('scrollTop',3000);//設定屬性值
</script>
</body>
</html>
複製程式碼
16、綜合案列之回到頂部
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>回到頂部</title>
<style>
* {
margin: 0;
padding: 0;
}
html,
body {
height: 1000%;
/* css3新增加的;背景顏色的線型漸變 */
background: -webkit-linear-gradient(top left, lightcoral, lightblue,
lightgreen, lightcyan, lightgoldenrodyellow);
}
.link {
display: none;
/*開始隱藏,當瀏覽器捲去的高度超過一螢幕的時候再讓這個按鈕展示 */
position: fixed;
right: 20px;
bottom: 20px;
width: 50px;
height: 50px;
line-height: 50px;
text-align: center;
background: #999;
color: #fff;
border-radius: 5px;
}
</style>
</head>
<body>
<a href="javascript:;" class="link" id="link">頂部</a>
<script src="utils.js"></script>
<script>
// winow.onscroll:瀏覽器滾動條滾動事件(只要滾動條滾動了就會觸發這個事件)
// 1、數遍滾輪控制 或者 手動拖動滾動條
// 2、鍵盤按鍵控制
// 3、使用js程式碼控制
// ...
// 不管什麼方式,只要滾動條動了就會觸發這個事件
~function () {
var link = document.getElementById('link');
window.onscroll = function () {
// 獲取當前捲去的高度和一螢幕高度
var curTop = utils.winBox('scrollTop'),
curHeight = utils.winBox('clientHeight');
// 已經卷去的高度>=一螢幕的高度的時候,展示回到頂部按鈕,否則隱藏按鈕即可
utils.css(link, 'display', curTop >= curHeight ? 'block' : 'none');
};
link.onclick = function () {
// 讓瀏覽器的scrolltop設定為零
utils.winBox('scrollTop', 0);
};
}()
</script>
</body>
</html>
複製程式碼