一、DOM介绍
DOM的全拼是:Document Object Model,叫做文档对象模型。
就是使用对象结构操作html文档。例如,改变标签的背景颜色,让标签移动产生动画。。。。
DOM中的顶级对象是document,言外之意,DOM其实是属于BOM的。
二、html基本结构操作
在控制台显示
1.显示body - document.body
console.log(document.body)
2.显示html - document.documentElement
console.log(document.documentElement)
3.显示head - document.head
console.log(document.head);
4.显示和设置title - document.title
显示:console.log(document.title);
设置:console.log(document.title='文档');
三、获取标签
在js中,标签的id名,可以当做是变量,直接就能代表这个标签元素,但是,id名可以随便定义,但是变量名不能随便定义,所以使用id名代表标签是有风险的。所以需要通过方法来获取到标签元素,自己定义给变量,可以避免这种风险。
1.使用css选择器获取元素
(1)语法:document.querySelector('css选择器')
(2)获取满足css选择器的第一个元素 - 在控制台显示 - 是一个对象
(3)用console.log只能看到标签 ---- 想看到对象使用console.dir
<head>
<style>
.box {
width: 100px;
height: 100px;
background-color: red;
}
[a='b'] {
width: 200px;
height: 200px;
background-color: blue;
}
</style>
</head>
<body>
<div class="box">我是盒子1</div>
<div a='b'>我是盒子2</div>
</body>
<script>
// 第一种
var oDiv = document.querySelector('div')
// console.log(oDiv)
// 第二种 - 获取盒子2
var oDiv = document.querySelector("[a='b']")
// console.log(oDiv)
// 第三种
var oDiv = document.querySelector('body div')
// console.log(oDiv)
// 第四种
var oDiv = document.querySelector('body div:first-child')
console.log(oDiv)
</script>
2.获取集合
(1)语法:document.querySelectorAll('css选择器')
(2)满足css选择器的所有元素都选中 - 是一个伪数组
(3)可以遍历、取下标、可以有长度,就是不能使用数组方法
<body>
<div class="box">我是盒子1</div>
<div a='b'>我是盒子2</div>
</body>
<script>
var oDivs = document.querySelectorAll('div') // 是伪数组
console.log(oDivs); // dom中元素的特性:console.log输出的时候都是标签的样子,不是对象的样子
console.log(oDivs[0]);
console.log(oDivs.length); //有下标有长度可以遍历
oDivs.push(666); // 不能使用数组方法
</script>
3.dom中所有能代表标签的变量,他们的数据类型一定是object
(1)dom中元素的特性:console.log输出的时候都是标签的样子,不是对象的样子
(2)第一种 - 看类型的方式
console.log(typeof oDivs); ---------- object
第二种 - 看类型的方式
console.dir(oDivs); ---------- object ---- 看前面有个小箭头所以就是object类型
console.log(console); --------- 看对象里面包含的有哪些东西
4.标签选择器
(1)语法:getElementsByTagName('css的选择器')
var oDivs = document.getElementsByTagName('div')
console.log(oDivs); // 只能获取到集合
5.类名选择器
(1)语法:getElementsByClassName('css的选择器')
var oDivs = document.getElementsByClassName('box')
console.log(oDivs);
6.name属性选择器
(1)语法:getElementsByName('css的选择器')
var oDivs = document.getElementsByName('mybox')
console.log(oDivs);
7.id选择器
(1)语法:getElementById('css的选择器')
var oDiv = document.getElementById('myid')
console.log(oDiv);
注意:上述4种获取标签的方法,除了通过id可以准确获取到元素,别的方法都是只能获取到元素的集合(类数组)
四、操作内容
1.双标签 - 纯文本 - 可设置/可获取
(1)获取内容
(1-1)只能获取到纯文本内容 - 标签(伪元素).innerText
var oDiv = document.querySelector('div') -------- 获取所有内容
console.log(oDiv)
console.log(oDiv.innerText)
(1-2)获取带有标签的内容 - 标签.innerHTML
var oDiv = document.querySelector('div') --------- 获取所有内容
console.log(oDiv)
console.log(oDiv.innerHTML)
(2)设置内容
var oDiv = document.querySelector('div')
console.log(oDiv);
oDiv.innerText = '我是文本本本' -------- 设置div里的文本内容
oDiv.innerHTML = '<b>909090</b>' -------- 设置div里的带有标签的内容
2.表单标签 - 内容操作使用 - 表单标签.value - 可设置/可获取
(1)获取内容
oInput = document.querySelector('input') --------- 获取所有内容
console.log(oInput.value);
(2)设置内容
oInput.value = '内容不能为空'
3.易混点
坑1:操作内容,必须是 具体的 标签.属性 来操作,不能是 集合.属性 操作
坑2:不管是设置文本内容还是带有标签的内容,原本的内容就不见了,被覆盖掉了
五、操作属性
1.样式是div{样式} ------ 属性是body写在行内
2.标签属性 ----- <标签 键=值> ------ 长在标签上的键值对
<table width="500" height="300" border="1">
<tr>
<td>姓名</td>
<td>性别</td>
<td>年龄</td>
</tr>
</table>
(1)获取属性值 - 标签.getAttribute('属性名') - 返回是属性的值
var oTable = document.querySelector('table') //获取所有内容
var h = oTable.getAttribute('height')
console.log(h)
(2)设置属性值 - 标签.setAttribute('属性名','属性值')
oTable.setAttribute('cellspacing','0')
(3)删除属性 - 标签.removeAttrribute('属性名')
oTable.removeAttribute('border')
3.对象属性 ----- 元素.属性名 = 值;
console.log(元素.属性名);
4.H5的自定义属性操作
当给标签添加属性以data-XXX
开头时,H5提供了一个快速操作属性的api:
标签.dataset.XXX // 获取属性的值
六、样式操作
1.设置样式 ----- 标签.style.css的键 = 'css的值' ------ 设置在行内
var oDiv = document.querySelector('div') //无论获取什么条件,都要先获取他老大
oDiv.style['background-color'] = 'red'
oDiv.style.backgroundColor = 'red'
(1)如果键中包含连字符,就使用['键']或小驼峰书写
(2)重复的找到规律了- 键=值 键=值 键=值
(3)循环如何处理 - 就将这个3个键值对放在一个对象中 - 遍历对象
var obj = {
width: '100px',
height: '50px',
backgroundColor: '#0f0'
}
for(var key in obj) {
oDiv.style[key] = obj[key]
}
(4)封装批量设置标签样式的函数
function setStyle(ele, obj) {
for (var key in obj) {
ele.style[key] = obj[key]
}
}
setStyle(oDiv, {
width: '200px',
height: '100px',
backgroundColor: '#f00',
border: '1px solid #000'
})
2.获取样式 ----- window.getComputedStyle(标签) ------ 返回(获取)一个用所有css键值对组成的对象
console.log(getComputedStyle(oDiv));
console.log( getComputedStyle(oDiv).width );
(1)点击div小盒让宽度渐变加到500
var oDiv = document.querySelector('div')
oDiv.style.width = '100px'
oDiv.style.height = '100px'
oDiv.style.backgroundColor = '#f00'
console.log(getComputedStyle(oDiv))
console.log(getComputedStyle(oDiv).width)
oDiv.onclick = function(){
// 变大 - 设置定时器
var time = setInterval(
function(){
// 获取原来的值
var obj = getComputedStyle(oDiv);
var width = obj.width
width = parseInt(width)
// 加大
width += 2
// 限定最大值
if(width>=500){
width=500
clearInterval(time)
}
// 给div加宽 - 重新设置宽度样式,值比原来的大
oDiv.style.width = width +'px'
console.log(width)
},16)
}
七、类名操作
1.直接操作class属性
(1)获取标签类名 - 语法:标签.className
(2)设置标签类名 - 语法:标签.className = 值
(3)清空所有标签类名 - 语法:标签.className = ' '
var oDiv = document.querySelector('div')
document.querySelector('button').onclick = function () {
// (1)获取标签类名
// 语法:标签.className
var cname = oDiv.className + ' border'
oDiv.className = cname
// (2)设置类名
// 语法:标签.className = 值
oDiv.className = 'border'
// (3)清空所有类名
oDiv.className = ''
}
2.利用方法
语法:标签.classList --- 包含所有类名操作方法的对象
(1)添加类名 - oDiv.classList.add(新类名)
(2)删除类名 - oDiv.classList.remove(被删除的类名)
(3)让一个类名在添加和删除之间切换 - 标签.classList.toggle(类名)
(4)控制台判断某个类名是否存在 - 标签.classList.contains(类名)
var oDiv = document.querySelector('div')
document.querySelector('button').onclick = function () {
console.log(oDiv.classList);
// (1)添加类名 - oDiv.classList.add(新类名)
oDiv.classList.add('border')
// (2)删除类名 - oDiv.classList.remove(被删除的类名)
oDiv.classList.remove('box')
// (3)让一个类名在添加和删除之间切换 - 标签.classList.toggle(类名)
oDiv.classList.toggle('box')
// (4)控制台判断某个类名是否存在 - 标签.classList.contains(类名)
console.log( oDiv.classList.contains('box') );
console.log( oDiv.classList.contains('border') );
}
八、页面卷去的距离
1.适用于有文档声明的时候:var t = document.documentElement.scrollTop
2.当没有文档的时候,使用另外一种获取方法:var t = document.body.scrollTop ------ <!DOCTYPE html>
3.兼容写法:不管有没有文档声明都可以获取到的方式 --- 能获取能赋值
var t = document.documentElement.scrollTop || document.body.scrollTop
九、短路运算
1.语法:var 变量 = 数据1 && 数据2
(1)当数据1为true,不能决定整个条件的结果,还需要进行到数据2,所以此时会将
数据2赋值给变量。
(2)当数据1为false,就已经知道整个条件的结果了,就没有必要进行到数据2了,所
以此时会将数据1赋值给变量
2.语法:var 变量 = 数据1 || 数据2
(1)当数据1为true,就已经能决定整个条件的结果了,就没有必要进行数据2了,此
时就将数据1赋值给变量
(2)当数1为false,还不能决定整个条件的结果,需要进行到数据2,此时就会将数据2
赋值给变量
3.利用逻辑运算中的&&
和||
让赋值操作变得更灵活,并带有选择性。
4.可以用于赋值 - 看代码是否能进行到最后(符号的右边),如果能进行到右边就将右边的值赋值给变量,如果只进行到左边就将左边的值赋值给变量
(1)var a = true || false ---- a的值是左边的值
(2)var a = false || true ---- a的值是右边的值
(3)var a = true && false ---- a的值是右边的值
(4)vafr a = false && true ---- a的值是左边的值
如果值不是布尔值,就转成布尔值
5.利用逻辑运算,查看左边的结果能否决定整体的结果
练习:
var a = 1 && 2 //左边为ture不够,也要右边为ture,所以执行到右边
console.log(a)
var a = null || 666; //左边为false还不够 - || 或者运算符 - 有一边为真才可以得到结果
console.log(a)
var a = false && 8
console.log(a)
function cb(fn){
fn&&fn() //左边为undefined - 为false,所以整个为假,不用进行后面了,所以fn没调用,
// 直接显示666
alert(666)
}
cb()
function cb(fn){
fn&&fn() //只左边为真还不够 - 所以执行到了右边,最终输出右边的结果888,后又输出左边
// 结果666
alert(666)
}
cb(function(){
alert(888)
})
案例:
-
随机点名
-
实时显示当前时间
-
全选全不选案例
十、节点操作
DOM 就是我们 html 结构中一个一个的节点构成的。不光我们的标签是一个节点,我们写的文本内容也是一个节点,注释,包括空格都是节点。
DOM节点分三种:元素节点、文本节点、属性节点。元素节点就是我们获取到的标签元素;标签里面的文本就是文本节点、标签上的属性就是属性节点。
1.根据标签之间的关系获取标签
(1)获取所有儿子 - 父.children
var ul = document.querySelector('ul')
console.log(ul.children);
(2)获取第一个儿子 - 父.firstElementChild
var ul = document.querySelector('ul')
var first = ul.firstElementChild
console.log(ul.firstElementChild);
(3)获取最后一个儿子 - 父.lastElementChild
var ul = document.querySelector('ul')
var last = ul.lastElementChild
console.log(ul.lastElementChild);
(4)获取父标签 - 子.parentElement
var ul = document.querySelector('ul')
var last = ul.lastElementChild // 借助最后一个儿子
console.log(last.parentElement);
(5)获取哥哥 - 弟弟.previousElementSibling
var ul = document.querySelector('ul')
console.log(ul.children);
var first = ul.firstElementChild
var last = ul.lastElementChild
console.log( last.previousElementSibling );
(6)获取弟弟 - 哥哥.nextElementSibling
var ul = document.querySelector('ul')
console.log(ul.children);
var first = ul.firstElementChild
var last = ul.lastElementChild
console.log( first.nextElementSibling );
2.创建标签
(1)语法:document.createElement('标签名字符串')
var strong = document.createElement('strong')
strong.innerText = '加粗文本'
console.log(strong)
3.插入节点
(1)给父追加一个子 - 将这个标签作为某个父标签的最后一个儿子
语法:父.appendChild()
var ul = document.querySelector('ul')
var a = document.createElement('a')
ul.appendChild(a)
(2)将标签放在某个父标签的某个子标签的前面
语法:父.insertBefore(新的子, 旧的子)
var ul = document.querySelector('ul')
var a = document.createElement('a')
a.innerText = '我是a标签'
ul.appendChild(a)
var i = document.createElement('i')
i.innerText = '文本倾斜'
ul.insertBefore(i,a)
4.替换标签
语法:父.replaceChild(新, 旧)
var ul = document.querySelector('ul')
var a = document.createElement('a')
a.innerText = '我是a标签'
ul.appendChild(a)
var u = document.createElement('u')
u.innerText = '下划线'
ul.replaceChild(u,a)
5.复制(克隆)节点
(1)复制空壳 --- 语法:标签.cloneNode()
var u = document.createElement('u')
u.innerText = '下划线'
console.log(u)
var newU = u.cloneNode()
console.log(newU)
(2)带内容的复制 --- 语法: 标签.cloneNode(true)
var u = document.createElement('u')
u.innerText = '下划线'
console.log(u)
var newU = u.cloneNode(true)
console.log(newU)
6.删除节点
语法:父.removeChild(子)
var ul = document.querySelector('ul')
var p = document.createElement('p')
p.innerText = '我是p标签'
ul.appendChild(p)
ul.removeChild(p)
删除标签案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<table border=1 width="500">
<thead>
<tr>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>成名绝技</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</body>
<script>
var arr = [
{
name:"令狐冲",
age:20,
sex:"男",
skill:"独孤九剑"
},
{
name:"东方不败",
age:50,
sex:"女",
skill:"葵花宝典"
},
{
name:"任我行",
age:55,
sex:"男",
skill:"吸星大法"
}
];
// 创建表格
var tbody = document.querySelector('tbody')
renderHTML()
function renderHTML() {
var str = ''
for(var a = 0; a < arr.length; a++) {
str += '<tr>'
var obj = arr[a]
for(var key in obj) {
str += '<td>'+obj[key]+'</td>'
}
str += '<td>删除</td>'
str += '</tr>'
}
tbody.innerHTML = str
}
// 获取所有的删除td
bindEvent()
function bindEvent() {
var tds = document.querySelectorAll('td:last-child')
for(var b = 0; b < tds.length; b++) {
(function(b) {
tds[b].onclick = function() {
tds[b].parentElement.parentElement.removeChild(tds[b].parentElement)
}
})(b)
}
}
</script>
</html>
十一、获取标签大小(尺寸)
1.包含边框大小
<head>
<style>
*{
padding: 0;
margin: 0;
}
div{
width: 100px;
height: 150px;
padding: 10px;
border: 16px solid #000;
margin: 20px;
}
</style>
</head>
<script>
var div = document.querySelector('div')
</script>
(1)标签.offsetWidth
(2)标签.offsetHeight
var w1 = div.clientWidth
var h1 = div.clientHeight
console.log(w1,h1);
2.不包含边框大小
(1)标签.clientWidth
(2)标签.clientHeight
var w2 = div.offsetWidth
var h2 = div.offsetHeight
console.log(w2,h2);
返回纯数字
十二、获取标签位置
1.标签.offsetLeft
2.标签.offsetTop
<head>
<style>
.box>div>div{
width: 100px;
height: 100px;
background-color: #f00;
margin: 50px;
}
.box{
width: 500px;
height: 500px;
border: 1px solid #000;
position: relative;
}
.box2{
width: 300px;
height: 300px;
background-color: #0f0;
}
</style>
</head>
<body>
<div class="box">
<div class="box2">
<div></div>
</div>
</div>
</body>
<script>
var div = document.querySelector('.box div div')
// 位置获取 标签.offsetLeft 标签.offsetTop
var l = div.offsetLeft
var t = div.offsetTop
console.log(l, t);
// 参考设置过定位的祖宗标签,如果祖宗没有定位,就参考html标签
</script>
获取的是相对于设置过定位的父标签的左边距和上边距离,返回纯数字。
十三、获取标签的边框厚度
1.标签.clientLeft - 获取左边框厚度
2.标签.clientTop - 获取上边框厚度
<head>
<style>
*{
padding: 0;
margin: 0;
}
div{
width: 100px;
height: 100px;
padding: 10px;
border-left: 10px solid #000;
border-top: 20px solid #0f0;
border-right: 30px solid #00f;
border-bottom: 40px solid #f00;
margin: 20px;
}
</style>
</head>
<body>
<div></div>
</body>
<script>
var div = document.querySelector('div')
// 标签.clientLeft 标签.clientTop -- 获取左边框和上边框厚度
console.log( div.clientLeft );
console.log( div.clientTop );
// 标签.tagName -- 大写的标签名
console.log(div.tagName);
</script>
获取到的是上边框和左边框的厚度,纯数字。
十四、获取标签名
标签.tagName ---- 大写的标签名(控制台) ----------- ↑↑↑(看十三)
十五、回流/重排 和 重绘
我们在做案例的时候,通常一个标签要设置很多样式。为了方便我们批量设置样式,可以封装一个批量设置样式的函数:
function setStyle(ele, styleObj) {
for(var key in styleObj) {
ele.style[key] = styleObj[key]
}
}
这个函数在批量设置样式的时候,每遍历一次,设置一次样式,每次设置样式都设置在了行内,这样会造成多次回流,影响页面性能。
1.浏览器渲染过程
(1)解析html生成DOM树,解析css,生成CSSOM树,将DOM树和CSSOM树结合,生成渲染树;
(2)根据渲染树,浏览器可以计算出网页中有哪些节点,各节点的CSS以及从属关系 - 回流
(3)根据渲染树以及回流得到的节点信息,计算出每个节点在屏幕中的位置 - 重绘
(4)最后将得到的节点位置信息交给浏览器的图形处理程序,让浏览器中显示页面
如图:
(1)解析html ---- 成dom树
(2)解析css ---- 成样式规则
渲染树 ----- 布局 ----- 样式 ----- 规则
2.回流
(1)回流:英文叫reflow,指的是当渲染树中的节点信息发生了大小、边距等问题,需要重新计算各节点和css具体的大小和位置。当网页需要重新布局的时候,就造成了回流
例:在css中对一个div修饰的样式中,修饰了宽度、高度等样式,浏览器需要重新计算标签大小,这个计算的过程,就是回流的过程。
容易造成回流的操作:
-
布局流相关操作
-
盒模型的相关操作会触发重新布局
-
定位相关操作会触发重新布局
-
浮动相关操作会触发重新布局
-
-
节点操作
改变节点的结构或其中的文本结构会触发重新布局。
对标签进行下面这些属性或方法操作的时候,会强行回流:
-
offsetTop
-
offsetLeft
-
offsetWidth
-
offsetHeight
-
scrollTop
-
scrollLeft
-
scrollWidth
-
scrollHeight
-
clientTop
-
clientLeft
-
clientWidth
-
clientHeight
-
getComputedStyle
-
-
css
-
width
-
height
-
padding
-
border
-
margin
-
position
-
top
-
left
-
bottom
-
right
-
float
-
clear
-
text-align
-
vertical-align
-
line-height
-
font-weight
-
font-size
-
font-family
-
overflow
-
white-space
-
3.重绘
(1)重绘:英文叫repaint,当节点的部分属性发生变化,但不影响布局,只需要重新计算节点在屏幕中的绝对位置并渲染的过程,就叫重绘。比如:改变元素的背景颜色、字体颜色等操作会造成重绘。 当网页需要重新绘画的时候就造成了重绘
(2)回流的过程在重绘的过程前面,所以回流一定会重绘,但重绘不一定会引起回流。
容易造成重绘操作的css:
-
color
-
border-style
-
border-radius
-
text-decoration
-
box-shadow
-
outline
-
background
4. 优化
不管是回流还是重绘,都会对浏览器的渲染造成影响,所以我们在项目中,尽量避免回流。
4-1:样式合并修改
减少造成回流的次数,如果要给一个节点操作多个css属性,而每一个都会造成回流的话,尽量将多次操作合并成一个,例:
var oDiv = document.querySelector('.box');
oDiv.style.padding = '5px';
oDiv.style.border = '1px solid #000';
oDiv.style.margin = '5px';
操作div的3个css属性,分别是padding、border、margin,此时就可以考虑将多次操作合并为一次。
方法1:使用style的cssText - 只回流一次
<body>
<div></div>
</body>
<script>
var div = document.querySelector('div')
div.style.cssText = 'width: 100px;height: 100px;border: 10px solid #f00;position: absolute;left: 20px;top:50px;'
</script>
方法二:将这几个样式定义给一个类名,然后给标签添加类名 - 只回流一次
<body>
<div></div>
</body>
<script>
var div = document.querySelector('div')
setStyle(div, {
width: '100px',
height: '100px',
border: '10px solid #f00',
position: 'absolute',
left: '20px',
top: '50px'
})
function setStyle(ele, obj) {
var str = ''
for(var key in obj) {
str += key + ':' + obj[key] + ';'
}
console.log(str);
ele.style.cssText = str
}
</script>
(1)标签.style.cssText
(2)标签.setAttribute('style', '')
(3)标签.className = ''
4-2:批量操作dom
当对DOM有多次操作的时候,需要使用一些特殊处理减少触发回流,其实就是对DOM的多次操作,在脱离标准流后,对元素进行的多次操作,不会触发回流,等操作完成后,再将元素放回标准流
举例:
<body>
<ul></ul>
</body>
<script>
for(var a = 0; a < 10; a++){
var li = document.createElement('li')
li.innerText = a+1
ul.appendChild(li)
} // 造成十次回流 - 这样每次给ul中新增一个li的操作,每次都会触发回流。
</script>
方法一:隐藏ul后,给ul添加节点,添加完成后再将ul显示
<body>
<ul></ul>
</body>
<script>
var ul = document.querySelector('ul')
ul.style.display = none // 隐藏后的操作不会造成回流
for(var a = 0; a < 10; a++){
var li = document.createElement('li')
li.innerText = a+1
ul.appendChild(li)
}
ul.style.display = 'block' // 显示操作后的ul
</script>
此时,在隐藏ul和显示ul的时候,触发了两次回流,给ul添加每个li的时候没有触发回流。
方法二:创建文档碎片,将所有li先放在文档碎片中,等都放进去以后,再将文档碎片放在ul中
<body>
<ul></ul>
</body>
<script>
var fg = document.createDocumentFragment()
for(var a = 0; a < 10; a++){
var li = document.createElement('li')
li.innerText = a+1
fg.appendChild(li) // 此时没有造成回流,因为我在内存玩,和页面没有关系
}
ul.appendChild(fg) // 想让文档碎片里的东西在ul里显示,所以把文档碎片放进小括号内,此时
// 文档碎片自己玩了一招金蝉脱壳,把碎片里面的东西倒给了小括号,也就是ul
</script>
文档碎片就是一个虚拟的DOM节点。不会在页面中使用,跟真的标签操作起来是一样的,对文档碎片操作不会造成回流。触发了一次回流
方法三:将ul拷贝一份,将所有li放在拷贝中,等都放进去以后,使用拷贝替换掉ul
<body>
<ul></ul>
</body>
<script>
var newUl = ul.cloneNode(true)
for(var a = 0; a < 10; a++) {
var li = document.createElement('li')
li.innerText = a + 1
newUl.appendChild(li) // 此时页面中没有造成回流
}
ul.parentElement.replaceChild(newUl, ul)
</script>
触发了一次回流
知识点补充:创建一个div带有滚动条的
<body>
<div style="width: 20px;">
选正是学校后勤上的一名干事,我上世纪80年代在商中上学时就认识他。那时,我们班的玻璃烂了,选正
老师就用右臂夹着大块玻璃,左手拿着玻璃刀、尺子和玻璃泥等,趁课间很快就将破烂的玻璃换掉,安上
新玻璃。他换玻璃很细致,先量窗框,再裁玻璃,然后将玻璃泥揉成条状,然后装上一寸不多一寸不少的
新玻璃,
</div>
<button>按钮</button>
</body>
<script>
document.querySelector('button').onclick = function() {
var t = document.documentElement.scrollTop || document.body.scrollTop // 放在这个
// 位置,提前获取,就从800次回流优化到现在的400次回流
var timer = setInterval(function() {
// 获取卷去的距离 - 获取
// var t = document.documentElement.scrollTop || document.body.scrollTop // 获
// 取800次回流,每次获取都要回流
// 减小
t -= 20
console.log(t);
// 让滚动条走起来 - 设置
document.documentElement.scrollTop = document.body.scrollTop = t
if(t <= 0) {
clearTimeout(timer)
}
}, 20)
}
</script>