1、BOM介绍
BOM是三个单词的首拼--Browser Object Model,即浏览器对象模型。
-
navigator 存储浏览器信息
-
history
-
操作浏览器的历史记录
-
back()
- 后退一个页面
history.back(); # 返回到上一个页面,相当于浏览器的后退按钮 -
forward()
- 前进一个页面
history.forward(); # 前进到下一个页面(下一个页面必须是点击以后的页面),相当于浏览器的前进按钮 -
go()
- 前进或后退多个页面
history.go()- 正数是前进 - 负数是后退 - 前进后退几个页面,就看数字是几
-
-
-
location
-
操作地址栏url
-
href
-
设置完整的地址
- location.href = 新地址
-
获取完整的地址
- location.href
-
-
search
-
设置地址栏参数
- location.search = ?键=值&键=值
-
获取地址栏参数
- location.search
-
-
hash
-
设置锚点
- location.hash = #单词
-
获取锚点
- location.hash
-
-
-
-
窗口大小
- innerWidth
- innerHeight
var w = window.innerWidth; console.log(w); var h = window.innerHeight; console.log(h); -
事件
-
window.onload
- 当所有资源加载完成后,触发执行
window.onload = function(){ console.log("当网页中所有资源加载完成才打印"); } -
window.onresize
- 当浏览器窗口大小发生改变,触发执行
window.onresize = function(){ // 当浏览器的窗口大小发生改变的时候触发这个事件 } -
window.onscroll
- 当浏览器卷去的距离发生改变,触发执行
window.onscroll = function () { console.log('浏览器滚动了') }
-
-
方法
-
弹出层
- alert
- confirm
- prompt
-
全局定义的函数,都属于window的方法
-
全局定义的变量,都属于window的属性
-
定时器
-
setInterval(函数, 毫秒数)
- 让函数每隔毫秒数,就执行一次,会不停的执行下去
var timerId = setTimeout(function () { console.log('我执行了') }, 1000) console.log(timerId) // 1 -
setTimeout(函数, 毫秒数)
- 让函数延迟毫秒数执行一次,就这一次
var timerId = setInterval(function () { console.log('我执行了') }, 1000) -
关闭定时器
- clearTimeout(timerId); // 关闭延迟执行的定时器
- clearInterval(timerId); // 关闭间隔执行的定时器
- (可以互用)
-
-
打开新的标签页
- window.open(url)
-
设置卷去的距离
- window.scrollTo(x, y)
-
关闭窗口
- window.close()
-
DOM
-
概念
-
document object model
-
文档对象模型
- 由对象组成的结构操作html文档
-
-
-
获取标签
-
document.querySelector(css选择器)
-
获取满足css选择器的第一个 标签
- 返回一个标签
-
-
document.querySelectorAll(css选择器)
-
获取所有满足css选择器的标签
- 返回一个集合
-
-
document.getElementById()
-
document.getElementsByClassName()
-
document.getElementsByTagName()
-
document.getElementsByName()
document.getElementById("标签id名"); // 通过标签的id名获取标签 document.getElementsByTagName("标签名"); // 通过标签名获取标签 document.getElementsByClassName("标签类名"); // 通类名获取标签 document.getElementsByName("标签的name属性的值"); // 通过标签的name属性获取标签 // 上述4种获取标签的方法,除了通过id可以准确获取到元素,别的方法都是只能获取到元素的集合(类数组) -
-
获取html基本结构标签
-
HTML
- document.documentElement 可以获取html元素及其所有内容
-
body
- document.body body比较常用, 并且在页面中是唯一的, 因此可以使用document.body直接获取
-
head
- document.head 可以直接获取head元素
-
网页标题
-
document.title
- 可获取标题
- 可设置标题
-
-
-
获取标签名
- 标签.tagName
-
操作内容
-
双标签
-
文本内容
-
设置
- 标签.innerText = 值
-
获取
- 标签.innerText
-
-
带标签的内容
-
设置
- 标签.innerHTML = 值
-
获取
- 标签.innerHTML
-
-
-
表单
-
设置
- 标签.value = 值
-
获取
- 标签.value
<body> <div id="box" introduce="区域"><p>我是盒子</p></div> </body> <script type="text/javascript"> document.getElementById("box").innerText = "今天你要嫁给我"; var text = document.getElementById("box").innerText; document.write(text); document.getElementById("box").innerHTML = "<a href='http://www.baidu.com'>百度</a>"; var content = document.getElementById("box").innerHTML; console.log(content);
-
-
-
操作属性
-
设置属性
- 标签.setAttribute(属性名, 值)
-
获取属性
- 标签.getAttribute(属性名)
-
删除属性
- 标签.removeAttribute(属性名)
-
-
样式操作
-
获取样式
-
getComputedStyle(标签)
- 返回由所有css键值对组成的对象
-
-
设置样式
-
标签.style.css键 = 值
- 设置到行内
-
-
-
类名操作
-
直接操作class属性值
- 标签.className = 值
- 标签.className
-
classList
-
add()
- 添加一个类名
list.add('border') -
remove()
- 删除一个类名
list.remove('green') -
contains()
- 判断是否有这个类名
console.log(list.contains('green')) -
toggle()
- 让类名在删除和添加之间切换
-
-
-
获取卷去的距离
-
有文档声明
- document.documentElement.scrollTop
-
没有文档声明
- document.body.scrollTop
-
-
短路运算
-
使用逻辑运算符 && 和 || 给变量进行赋值
- var 变量 = 值1 && 值2
- 如果左边为true,就会将右边的值赋值给变量 - 如果左边为false,就会将左边的值赋值给变量- var 变量 = 值1 || 值
- 如果左边为true,就会将左边的值赋值给变量 - 如果左边为false,就会将右边的值赋值给变量 -
-
this在事件函数中,代表触发事件的标签
-
节点操作
-
创建标签
- document.createElement(标签名)
-
插入标签
-
父.appendChild(子)
-
父.insertBefore(新, 旧)
- 将新的子标签放在旧的子标签前面
-
-
替换标签
- 父.replaceChild(新, 旧)
-
复制标签
- 标签.cloneNode(true)
-
删除标签
-
父.removeChild(子)
- 子.parentElement.removeChild(子)
-
-
获取标签
-
所有子
- 父.children
-
第一个子
- 父.firstElementChild
-
最后一个子
- 父.lastElementChild
-
父
- 子.parentElement
-
上一个兄弟
- 标签.previousElementSibling
-
下一个兄弟
- 标签.nextElementSibling
-
-
-
标签大小
-
带边框
- 标签.offsetWidth
- 标签.offsetHeight
-
不带边框
- 标签.clientWidth
- 标签.clientHeight
-
-
标签位置
- 标签.offsetLeft
- 标签.offsetTop
获取标签的位置 --- 数字
参照设置过定位的直系祖宗标签
-
边框厚度
- 标签.clientLeft
- 标签.clientTop
-
不包含滚动条的窗口大小
- document.documentElement.clientWidth
- document.documentElement.clientHeight
-
回流和重绘
-
浏览器的渲染过程
-
解析html成DOM树,同时解析css成样式规则
-
合并成渲染树
-
布局
- 计算标签大小、关系、位置
-
喷绘
- 绘制颜色
-
浏览器显示
-
-
回流:英文叫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
-
-
重绘:英文叫repaint,当节点的部分属性发生变化,但不影响布局,只需要重新计算节点 在屏幕中的绝对位置并渲染的过程,就叫重绘。比如:改变元素的背景颜色、字体颜色等操作会造成重绘。 回流的过程在重绘的过程前面,所以回流一定会重绘,但重绘不一定会引起回流。
容易造成重绘操作的css:
- color - border-style - border-radius - text-decoration - box-shadow - outline - background
优化
不管是回流还是重绘,都会对浏览器的渲染造成影响,所以我们在项目中,尽量避免回流。
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
oDiv.style.cssText = 'padding:5px; border:1px solid #000; margin:5px;';
方法二:将这几个样式定义给一个类名,然后给标签添加类名:
<style>
.pbm{
padding:5px;
border:1px solid #000;
margin:5px;
}
</style>
<script>
var oDiv = document.querySelector('.box');
oDiv.classList.add('pbm');
</script>
2、批量操作DOM
当对DOM有多次操作的时候,需要使用一些特殊处理减少触发回流,其实就是对DOM的多次操作,在脱离标准流后,对元素进行的多次操作,不会触发回流,等操作完成后,再将元素放回标准流。
例:
var data = [
{
id:1,
name:"商品1",
},
{
id:2,
name:"商品1",
},
{
id:3,
name:"商品1",
},
{
id:4,
name:"商品1",
},
// 假设后面还有很多
];
var oUl = document.querySelector("ul");
for(var i=0;i<data.length;i++){
var oLi = document.createElement("li");
oLi.innerText = data[i].name;
oUl.appendChild(oLi);
}
这样每次给ul中新增一个li的操作,每次都会触发回流。
方法1:方法一:隐藏ul后,给ul添加节点,添加完成后再将ul显示
oUl.style.display = 'none';
for(var i=0;i<data.length;i++){
var oLi = document.createElement("li");
oLi.innerText = data[i].name;
oUl.appendChild(oLi);
}
oUl.style.display = 'block';
此时,在隐藏ul和显示ul的时候,触发了两次回流,给ul添加每个li的时候没有触发回流。
方法二:创建文档碎片,将所有li先放在文档碎片中,等都放进去以后,再将文档碎片放在ul中
var fragment = document.createDocumentFragment();
for(var i=0;i<data.length;i++){
var oLi = document.createElement("li");
oLi.innerText = data[i].name;
fragment.appendChild(oLi);
}
oUl.appendChild(fragment);
文档碎片就是一个虚拟的DOM节点。对文档碎片操作不会造成回流。
方法三:将ul拷贝一份,将所有li放在拷贝中,等都放进去以后,使用拷贝替换掉ul
var newUL = oUl.cloneNode(true);
for(var i=0;i<data.length;i++){
var oLi = document.createElement("li");
oLi.innerText = data[i].name;
newUL.appendChild(oLi);
}
oUl.parentElement.replaceChild(newUl, oUl);
3、避免多次触发布局
如下回到顶部的操作:
goBack.onclick = function(){
setInterval(function(){
var t = document.documentElement.scrollTop || document.body.scrollTop;
t += 10;
document.documentElement.scrollTop = document.body.scrollTop = t;
},20)
}
每隔20毫秒都会重新获取滚动过的距离,每次都会触发回流,代码优化如下:
goBack.onclick = function(){
var t = document.documentElement.scrollTop || document.body.scrollTop;
setInterval(function(){
t += 10;
document.documentElement.scrollTop = document.body.scrollTop = t;
},20)
}
只获取一次,每次都让数字递增,避免每次都获取滚动过的距离。
对于页面中比较复杂的动画,尽量将元素设置为绝对定位,操作元素的定位属性,这样只有这一个元素会回流,如果不是定位的话,容易引起其父元素以及子元素的回流。
4、修改批量设置样式函数
function setStyle(ele, styleObj) {
var cssText = ''
for(var key in styleObj) {
var cssProp = key
for(var a = 0; a < cssProp.length; a++) {
var charCode = cssProp.charCodeAt(a)
if(charCode >= 65 && charCode <= 90) {
cssProp = cssProp.slice(0, a) + '-' + cssProp[a].toLowerCase() + cssProp.slice(a+1)
}
}
cssText += cssProp + ':' + styleObj[key] + ';'
}
ele.style.cssText = cssText
}