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>