day-029-twenty-nine-20230317-js盒子模型-getBoundingClientRect-图片懒加载
js盒子模型
-
JavaScript盒子模型的13个属性
-
offsetParent:当前DOM元素中设置了定位的最近直系祖先级DOM元素- 或者
最近的table元素,最近的td元素,最近的th元素,最近的body元素。 offsetParent不一定是当前DOM元素的父元素offsetParent的根元素是body元素body元素的offsetParent是null,而不是document.documentElement
- 或者
-
offsetTop:当前DOM元素距离最近直系祖先定位元素的上内边距距离 -
offsetLeft:当前DOM元素距离最近直系祖先定位元素的左内边距距离-
得到
当前DOM元素到文档顶端的高度<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> *{ margin:0; padding:0; } #outer{ height:500px; width:500px; background-color: blue; margin:100px; border:10px solid red; position: relative; } #inner{ height:300px; width:300px; background-color: aquamarine; margin:100px; border:10px solid red; position: relative; } #box{ height:100px; width:100px; background-color:coral; margin:100px; border:10px solid red; } </style> </head> <body> <div id="outer"> <div id="inner"> <div id="box"></div> </div> </div> <script> let t1=box.offsetTop; console.log(t1);//100 let p1=box.offsetParent; console.log(p1);//inner let w1=p1.clientTop; let t2=p1.offsetTop; console.log(t2);//100 let p2=p1.offsetParent; console.log(p2);//outer let w2=p2.clientTop; let t3=p2.offsetTop; console.log(t3);//100 let p3=p2.offsetParent; console.log(p3);//body console.log(p3.offsetParent);//null console.log(t1+w1+t2+w2+t3); </script> </body> </html>
-
-
clientTop:当前DOM元素的上边框宽度 -
clientLeft:当前DOM元素的左边框宽度<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> #box{ height:100px; width:100px; background-color:coral; margin:100px; border-top:10px solid red; border-left:20px solid red; } </style> </head> <body> <div id="box"></div> <script> console.log(box.clientTop);//10 console.log(box.clientLeft);//20 </script> </body> </html>-
拿到
当前元素到body的上边框的高度-
以及
当前元素到body的左边框的宽度<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> *{ margin:0; padding:0; } #outer{ height:500px; width:500px; background-color: blue; margin:100px; border:10px solid red; position: relative; } #inner{ height:300px; width:300px; background-color: aquamarine; margin:100px; border:10px solid red; position: relative; } #box{ height:100px; width:100px; background-color:coral; margin:100px; border:10px solid red; } </style> </head> <body> <div id="outer"> <div id="inner"> <div id="box"></div> </div> </div> <script> function offset(ele){//ele-->box let top=ele.offsetTop;//初始值(t1) let left=ele.offsetLeft; let parent=ele.offsetParent;//初始父级(inner/p1) while(parent){//1.(inner/p1--true) //2.(outer/p2) //3.(body) //4.null(false) //1. top=t1+p1.offsetTop+p1.clientTop==>t1+t2+w1 //2. top= t1+t2+w1 + p2.offsetTop + p2.clientTop===》t1+t2+w1+t3+w2 //3. top= t1+t2+w1+t3+w2 + body.offsetTop(0)+body.clientTop(0)===》t1+t2+w1+t3+w2 top=top+parent.offsetTop+parent.clientTop; left=left+parent.offsetLeft+parent.clientLeft; //1.parent=p1.offsetParent===》(outer/2) //2.parent=p2.offsetParent===》(body) //3.parent=body.offsetParent==》null parent=parent.offsetParent; } return { top:top, left:left } } console.log(offset(box).top)//320 console.log(offset(inner).left)//210 </script> </body> </html>
-
-
-
offsetWidth:
内容宽度content+左内边距宽度padding-left+右内边距宽度padding-right+左边框宽度border-left+右边框宽度border-right- 标签盒模型:
内容宽度content=width - IE怪异盒模型:
内容宽度content=width-:左内边距宽度padding-left-:右内边距宽度padding-right
- 标签盒模型:
-
offsetHeight:
内容高度contentHeight+上内边距宽度padding-top+下内边距宽度padding-bottom+上边框宽度border-top+下边框宽度border-bottom -
clientWidth
内容content宽度+左右padding-纵向滚动条占用的宽度- 不同浏览器滚动条宽度不太一样
-
clientHeight
内容content高度+上下padding-横向滚动条占用的高度 -
scrollWidth
当前DOM元素的滚动条总宽度- 如果滚动内容未超出盒子,scrollWidth=clientWidth
- 如果滚动内容超出盒子,实际内容就是多少scrollWidth就是多少
-
scrollHeight
当前DOM元素的滚动条总高度<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ margin:0; padding:0; } #box{ height:200px; width:100px; background-color:coral; margin:100px; padding:20px; border:10px solid red; overflow: auto; } </style> </head> <body> <pre id="box"> #box{ height:200px; width:100px; background-color:coral; margin:100px; padding:20px; border:10px solid red; overflow: auto; } </pre> <script> //标准盒模型 content--->width/height //IE盒子模型 content---》content // (11) // offsetWidth:content+左右padding+左右border // offsetHeight:contet+上下padding+上下border // clientWidth:content+左右padding(-滚动条) // clientHeight:contet+上下padding(-滚动条) // scrollWidth:如果滚动内容未超出盒子scrollWidth=clientWidth // 如果滚动内容超出盒子,实际内容是多少scrollWidth就是多少 // scrollHeight:如果滚动内容未超出盒子scrollHeight=clientHeight // 如果滚动内容超出盒子,实际内容是多少scrollHeight就是多少 console.log(box.offsetWidth);//160//100+40+20 console.log(box.offsetHeight);//260//200+40+20 console.log(box.clientWidth);//123//100+40-(纵向滚动条占用的宽度) console.log(box.clientHeight);//223//200+40-(横向滚动条占用的高度) console.log(box.scrollWidth);//285//横向滚动内容超出盒子后的实际宽度 console.log(box.scrollHeight);//310//纵向滚动内容超出盒子后的实际高度 </script> </body> </html> -
scrollTop 滚动条
滚动过去的上下距离-
文档的已滚动高度
-
(document.documentElement||document.body).scrollTop-
一般浏览器用document.documentElement,页面滚动条就在它里面IE可能用document.body,IE没document.documentElement
-
一般浏览器也有document.body,但页面滚动条不在它里面 -
document.documentElement要放前面
-
-
-
-
scrollLeft 滚动条
滚动过去的左右距离<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> *{ margin:0; padding:0; } body{ height:3000px; background-image: linear-gradient(to bottom,red,blue,green); } #box{ height:100px; width:100px; background-color:coral; margin:100px; padding:20px; border:10px solid red; overflow: auto; position: fixed; right:50px; bottom: 50px; /* display: none; */ opacity:0; transition: all 1s; } </style> </head> <body> <div id="box"> 返回顶部 </div> <script> // scrollTop:滚动过去的距离(上下滚动) // scrollLeft:滚动过去的距离(左右滚动) let html=document.documentElement||document.body; box.onclick=function(){ html.scrollTop=0 } //window/document //滚动事件 scroll window.onscroll=function(){ if(html.scrollTop>=150){//滚动距离大于150,显示盒子 box.style.opacity=1 }else{//滚动距离小于150,隐藏盒子 box.style.opacity=0 } } </script> </body> </html>
-
-
对象中,key和value一致,可以省略一个- 即
键值对中属性名与作为属性值的变量名一致,那么可以省略为一个
- 即
-
getBoundingClientRect()-
当前DOM元素与可视窗口的信息ES6新增
-
返回值
DOMRect{}对象-
.getBoundingClientRect().x- 值可以是负数
-
.getBoundingClientRect().y -
.getBoundingClientRect().width -
.getBoundingClientRect().height -
.getBoundingClientRect().top:元素上边到视窗上边的距离; -
.getBoundingClientRect().right:元素右边到视窗左边的距离; -
.getBoundingClientRect().bottom:元素下边到视窗上边的距离; -
.getBoundingClientRect().left:元素左边到视窗左边的距离
-
-
数值之间的关系
DOM元素对象.getBoundingClientRect().right===DOM元素对象.getBoundingClientRect().left+DOM元素对象.getBoundingClientRect().width//trueDOM元素对象.getBoundingClientRect().bottom===DOM元素对象.getBoundingClientRect().top+DOM元素对象.getBoundingClientRect().height//trueDOM元素对象.getBoundingClientRect().top===DOM元素对象.getBoundingClientRect().y//trueDOM元素对象.getBoundingClientRect().left===DOM元素对象.getBoundingClientRect().x//true
-
-
滚动事件
- 页面目标对象 window、document
- window.onscroll
-
获取样式
-
DOM元素对象.style.xxx
- 通过DOM元素对象.style.xxx只能获取行内样式
-
window.getComputedStyle(DOM元素对象)
-
获取元素的任何形式的计算后的样式,返回一个CSSStyleDeclaration对象
-
中括号语法的适用范围要比点语法更广
- 中括号语法中的属性名可以用
驼峰命名法,也能使用-连接符命名式 - 点语法一般只能用
驼峰命名法来访问对象成员 - 方法封装中,一般能用中括号语法,就不要使用点语法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>复习</title> <style> .box { background-color: blue; } </style> </head> <body> <div style="color: red" class="box">12345</div> </body> </html> <script> // 通过DOM元素对象.style.xxx只能获取行内样式 let box = document.querySelector(".box"); console.log(box.style.color); console.log(box.style.backgroundColor); //获取元素的任何形式的样式 // 样式是计算后的 // []中括号语法的适用范围更广 console.log(getComputedStyle(box).color); console.log(window.getComputedStyle(box).backgroundColor); console.log(window.getComputedStyle(box)["backgroundColor"]); //中括号语法可以用驼峰命名法 console.log(window.getComputedStyle(box)["background-color"]); //中括号语法也可以使用-分隔符连接法 // IE获取元素的任何计算后的样式 // console.log(box.currentStyle("background-color"));//一般用于兼容IE,但2023年应该不用兼容了 // 封装获取样式 function getCss(element, styleName) { return window.getComputedStyle(element)[styleName]; } console.log(getCss(box, "background-color")); //封装设置样式 const setCss = function setCss(element, styleObject) { for (let key in styleObject) { element.style[key] = styleObject[key]; } }; let obj = { fontSize: "50px", border: "10px solid red", borderRadius: "50%", }; setCss(box, obj); </script> - 中括号语法中的属性名可以用
-
-
-
设置样式
-
使用DOM元素的style属性,直接设置元素的内联样式
const element = document.getElementById('my-element'); element.style.color = 'red'; -
使用DOM元素的classList属性,通过添加/移除类名的方式来设置样式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>设置css样式</title> <style> .active{ color: red; font-size: 16px; } </style> <body> <div id="my-element"> 555 </div> </body> <script> const element = document.getElementById('my-element'); element.classList.add('active'); </script> </html> -
使用setAttribute()方法,通过设置元素的style属性来添加CSS样式
const element = document.getElementById('my-element'); element.setAttribute('style', 'color: red; font-size: 16px;'); -
动态创建一个style元素,将CSS样式插入到其中
const style = document.createElement('style'); style.innerHTML = ` #my-element { color: red; font-size: 16px; } `; document.head.appendChild(style);
-
-
封装获取样式方法
// 封装获取样式 function getCss(element, styleName) { return window.getComputedStyle(element)[styleName]; } console.log(getCss(document.body, "background-color")); -
封装设置样式
//封装设置样式 const setCss = function setCss(element, styleObject) { for (let key in styleObject) { element.style[key] = styleObject[key]; } }; let obj = { fontSize: "50px", border: "10px solid red", borderRadius: "50%", }; setCss(document.body, obj);
图片懒加载
-
总体思路
-
不立刻给src赋值,到达某个条件后再加载。
- 因为只是给图片标签的src属性赋值,图片就会立即加载,占用带宽。
-
先设置一个
自定义属性如data-src存储真实的图片地址 -
设置一个
父级盒子给图片占位置,父级盒子设置背景颜色或图片,未来存放图片 -
隐藏裂掉的图片
img[src=""]{ display: none; } -
时机到了之后,将自定义属data-src的属性值赋值给src
-
时机举例
-
页面内容都加载完毕后,最后加载图片—window.onload事件
console.log(document.querySelector('body')) window.onload=function(){ console.log(document.querySelector('body')) } -
点击图片所在格子后加载
-
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>9.图片懒加载1</title> <style> * { margin: 0; padding: 0; } .img-box { width: 300px; height: 400px; background-color: #ccc; background-image: url(""); } .img-box img { width: 300px; height: 400px; } img[src=""] { display: none; } </style> </head> <body> <div class="box"></div> <!-- 1. 因为只是给图片的src属性赋值,图片就会立即加载,占用带宽。 故而不立刻给src赋值,到达某个条件后再加载。 2. 先设置一个自定义属性如 data-src 存储真实的图片地址 3. 设置一个盒子,给图片占位置(设置背景颜色或图片),未来存放图片 4. 隐藏裂掉的图片 img[src=""]{ display: none; } 5. 时机到了之后,将自定义属data-src的属性值赋值给src (如时机:页面内容都加载完毕后,最后加载图片---window.onload事件) (如时机:点击页面时加载) --> <!-- <img src="https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/458adc268050c17312da7c12328395e8.jpg" alt=""> --> <!-- <img src data-src="https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/458adc268050c17312da7c12328395e8.jpg" alt=""> --> <div class="img-box"> <img src data-src="https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/458adc268050c17312da7c12328395e8.jpg" alt="" /> </div> <h1>h1标签</h1> </body> </html> <script> const getImage = () => { let img = document.querySelector(".img-box img"); var data = img.getAttribute("data-src"); console.log(data); // img.setAttribute("src", data);//核心DOM操作-无兼容问题,繁琐 img.src = data; //HTML DOM操作,可能有兼容问题,2023目前暂时无了,操作简单 img.removeAttribute("data-src"); }; window.onload = function () { getImage(); }; /* let imgBox = document.querySelector(".img-box"); imgBox.onclick = () => { getImage(); }; */ </script> -
-
升级图片懒加载
-
如果data-src的图片路径是错误的,后面不再执行。
-
判断图片路径是对的
-
先创建一个新的img元素对象,利用新的img元素对象的src属性进行测试,之后利用img元素对象的onload事件。
- 图片的onload事件,图片路径正确并请求完图片才会执行。
-
-
判断图片路径是图片路径错误的
-
先创建一个新的img元素对象,利用新的img元素对象的src属性进行测试,之后利用img元素对象的onerror事件。
let newImage = document.createElement('img') // 图片的onload事件,图片路径正确并请求完图片才会执行。 newImage.onload=()=>{ console.log('图片路径正确') } newImage.onerror=()=>{ console.log('图片路径错误') } newImage.src = '//www.baidu.com/img/flexible/logo/pc/result@2.png'let newImage = document.createElement('img') newImage.onload=function(){ console.log('图片路径正确') newImage=null } newImage.onerror=function(e,e1){ console.log('图片路径错误',e,this,e1,newImage.src)//可以在这把图片的路径报告给后端 newImage=null } newImage.src = '//www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png1'<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> .imgbox{ width:300px; height:400px; background: #ccc url(img/default.gif) center no-repeat; } .imgbox img{ width:300px; height:400px; } img[src=""]{ display: none; } </style> </head> <body> <div class="imgbox"> <img src="" data-src="img/1.jpg" alt=""> </div> <script> //升级,如果data-src的图片路径是错误的,后面不在执行 //怎么判断图片路径是对的那? //先创建一个新的img,利用新的img 的src属性测试(探兵) // var newimg=document.createElement("img"); // newimg.src="img/1.jpg"//图片路径正确,继续执行代码 //路径错误报错,不在执行 // //图片的onload 的事件,图片路径正确才会执行 // newimg.οnlοad=function(){ // console.log("图片路径正确") // } var img=document.querySelector(".imgbox img"); window.onload=function(){ var dataSrc=img.getAttribute("data-src"); var newimg=new Image(); newimg.src=dataSrc; newimg.onload=function(){ img.src=dataSrc; img.removeAttribute("data-src"); newimg=null; } } </script> </body> </html>
-
-
-
升级图片懒加载
-
视口底部超过当前元素后再懒加载
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> *{ margin:0; padding:0; } body{ height:3000px; } .imgbox{ width:300px; height:400px; margin-top:1300px; margin-left:100px; background: #ccc url(img/default.gif) center no-repeat; } .imgbox img{ width:300px; height:400px; } img[src=""]{ display: none; } </style> </head> <body> <div class="imgbox"> <img src="" data-src="img/1.jpg" alt=""> </div> <script> var html=document.documentElement||document.body; var imgbox=document.querySelector(".imgbox"); var img=document.querySelector(".imgbox img"); window.onscroll=function(){ var ch=html.clientHeight; var boxh=imgbox.getBoundingClientRect().bottom; if(ch>=boxh){//加载图片 //加载图片之前,判断一下是否有flag 属性,值为true //说明图片已将加载成功了,不需要再加载 if(img.flag){return} showimg() } } function showimg(){ console.log("111"); var dataSrc=img.getAttribute("data-src"); var newimg=new Image(); newimg.src=dataSrc; newimg.onload=function(){ img.src=dataSrc; img.removeAttribute("data-src"); newimg=null; img.flag=true;//如果第一设置上图片后,给img设置一个自定义的属性flag=true } } </script> </body> </html>
-