BOM:Browser Object Model - 浏览器对象模型
浏览器对象模型:操作浏览器的 一套 用对象组成的结构
历史记录操作 - history
console.log(window.history);
返回到上一个页面,相当于浏览器的后退按钮
window.history.back()
2.前进到下一个页面(下一个页面必须是点击以后的页面),相当于浏览器的前进按钮
window.history.forward()
3.后退多个页面
window.history.go(-2)
go可前进可后退多个页面,具体是几个页面,就看数字是几,前进正数,后退负数
案例:

地址栏操作 -- location
操作地址栏使用 window.location
在操作的时候可以省略window
console.log(location);
1.href - 获取整个地址url或设置整个地址url(跳转)
console.log( location.href );
我们获取到的是经过url编码的数据 - 默认情况下,地址栏中的url会自动进行url编码
解码 - decodeURI(被编码的数据)
编码 - encodeURI(要编码的数据)
location.href = 'http://baidu.com' // 跳转地址
2.search - 获取/设置 整个url中的数据部分
console.log( location.search );
// location.search = '?name=zhangsan'
// btn.onclick = function() {
// location.search = '?age=18'
// }
3.hash - 获取/设置 - 整个地址中的锚点
console.log( location.hash ); -- 获取整个地址栏的锚点
location.hash = '#666' ; -- 设置整个地址栏的锚点
4.跳转页面 -- assign , replace
btn.onclick = function() {
location.assign('http://qq.com') -- 跳转页面
location.replace('http://music.163.com') -- 用新地址把旧地址替换掉
5. 刷新页面 -- reload
location.reload()
总结:
location.href - 整个地址
location.search - url中的数据部分
location.hash - url中的锚点部分
浏览器的弹出窗口(可以省略window)
window.alert("恭喜你!");
window.prompt("请输入数字:",1);
window.confirm("你确定要删除吗?")
window代表的是浏览器窗口 - 大小
window.innerWidth - 浏览器窗口的宽度

window.innerHeight - 浏览器窗口的高度(window可省略)

浏览器的事件
1.window.onload - 当网页中的所有资源都加在完成之后执行这个事件

2.window.onscroll - 当滚动条动了,就会触发执行的事件

3.window.onresize - 当浏览器大小发生改变,就会触发执行的事件

窗口控制
window.open(目标地址) - 打开新窗口
window.close() - 关闭当前窗口
window.scrollTo(x, y) - 控制窗口滚动 - 设置卷去的距离

定时器(异步代码)
让一个函数每隔一段时间就执行一次,会不停的执行
语法:window.setInterval(函数代码, 毫秒数) - 返回一个数字,代表当前页面中第几个定时器


停止定时器 - clearInterval(返回值)

2.让一个函数延迟一段时间执行,只能执行一次
语法:setTimeout(函数代码, 毫秒数) - 返回的数字,当前页面中的第几个定时器

在代码还没执行的时候点击停止会终止运行,不输出

同步和异步
定时器是我们学过的第一个异步代码(效率更高) --- 两段代码执行的时间差一秒

js和异步的关系
js是单线程语言
进程:为了让一个软件/服务能正常运行 而 分配的内存空间
线程:进程会造成内存浪费,所以就有更小的内存空间 - 线程
js只有一个内存空间在运行代码 - 同一时间只能运行一个代码,不能运行多个代码
js是如何实现异步代码的?
js在执行代码的时候,碰到了同步代码,就开始执行,碰到了异步代码,就将异步代码交给浏览器去处理
浏览器为什们能帮js处理异步代码?浏览器是多线程软件 - 同一时间做多件事情
浏览器在替js等待定时器的时间 - 如果时间到了,浏览器会将需要执行的函数,放在一个队列中排队等待
当js将所有的同步代码都执行结束后,再去队列中,依次执行排队的代码

总结
1.定时器给的时间不精准
2.异步代码一定会在所有同步代码执行结束后才会执行
DOM:document object model - 文档对象模型
顶级对象 document window.document
用来操作文档 - html文档
DOM操作html基本结构
1.body:document.body
console.log(document.body);
2.html:document.documentElement
console.log( document.documentElement );
3.console.log(document);
document-代表整个文档
4.head:document.head
console.log(document.head);
5. 操作文档标题 - document.title
console.log(document.title); // 获取标题
获取标签
css选择器
css选择器:类选择器,id选择器,标签选择器,后代选择器,子元素选择器,兄弟选择器,伪类选择器,群组选择器,通配符选择器,属性选择器-- 语法[属性名=属性值](和类名选择器的权重一样高)
1.语法:document.querySelector('css选择器') -- 选择满足css选择器的第一个元素

2.语法:document.querySelectorAll('css选择器') -- 满足css选择器的所有元素都选中

dom中所有能代表标签的变量,他们的数据类型一定是object(只要是标签,它就是对象)

dom中元素的特性:console.log输出的时候都是标签的样子,不是对象的样子
console.dir(oDiv) //可以把一些数据原本的样子展示出来
可以遍历

总结:
获取标签
document.querySelector('css选择器') - 获取一个
document.querySelectorAll('css选择器') - 获取多个
获取到的标签 - 是一个对象 - console.log只能看到标签 - 想看到对象使用console.dir
获取到的集合 - 是一个伪数组,可以遍历、取下标、可以有长度,就是不能使用数组方法
其他获取标签的方式(一般不用)

操作标签内容
(双标签)
获取标签
var oDiv = document.querySelector('div')
console.log(oDiv);
获取内容
标签.innerText - 只能获取到文本内容(避免使用集合)
console.dir(oDiv)
console.log(oDiv.innerText);
获取带有标签的内容 - 标签.innerHTML
console.log(oDiv.innerHTML);
设置内容
oDiv.innerText = 'div标签' --- 只能识别文本
oDiv.innerHTML = '<b>div标签</b>'
表单标签
<input type="text" value = "请输入一段文字">
获取标签
var oInput = document.querySelector('input')
// 表单标签 - 内容操作使用 表单标签.value
console.log(oInput.value); // 请输入一段文字
设置内容
oInput.value = '内容不能为空' //把请输入一段文字换成 内容不能为空
总结:
双标签内容
文本内容
标签.innerText - 可以获取文本内容/设置文本内容
带标签内容
标签.innerHTML - 可以获取带标签的内容/设置带标签的内容
表单标签内容
表单标签.value - 可以设置/可获取
坑1:操作内容,必须是 具体的 标签.属性 来操作,不能是 集合.属性 操作
坑2:不管是设置文本内容还是带有标签的内容,原本的内容就不见了,被覆盖掉了
属性操作
操作标签的属性
标签的属性-<标签 键=值> - 长在标签上的键值对
获取属性
标签.getAttribute('属性名') -- 返回是属性的值
设置属性
标签.getAttribute('属性名','属性值')
删除属性
标签.removeAttribute('属性名')
样式操作
设置样式
标签.style.css的键 = 'css的值' --- 设置在行内了 (JS中为了方便设置样式(如果css的键里面有连字符)那就换成小驼峰命名法)
例:oDiv.style.backgroundColor = '#0f0'

获取样式
window.getComputedStyle(标签) - 返回一个有所有样式键值对组成的一个对象
案例:
<style>
.box {
width: 100px;
height: 100px;
background-color: yellow;
}
</style>
<body>
<div class="box">盒子</div>
</body>
<script>
var oDiv = document.querySelector('div')
//点击div让宽度加大到500
oDiv.onclick = function () {
//(1.)变大 - 设置定时器
var timer = setInterval(function () {
//(3.)获取原来的值
var obj = getComputedStyle(oDiv)
var width = obj.width
// console.log(width);
width = parseInt(width)
//(4.)加大
width += 2
// console.log(width);
//只能加到500,限定最大值
if (width >= 500) {
width = 500
//把定时器停下来
clearInterval(timer)
}
//(2.) 给div加宽 - 重新设置宽度样式,值比原来的大
oDiv.style.width = width + 'px'
//输出一个值,看定时器什么时候停下来
console.log(width)
}, 16)
}
</script>
类名操作
获取/设置类名
标签.className
清空所有类名 (赋值为空)
oDiv.className = ' '
添加类名
标签.classList.add(类名)
删除类名
标签.classList.remove(类名)
让类名再添加和删除之间切换
标签.classList.toggle(类名)
不在会添加,在的话会删除
判断类名是否存在(返回布尔值)
标签.classList.contains(类名)
切换背景颜色案例
<style>
.box{
width: 200px;
height: 200px;
border: 1px solid #999;
}
.box>div{
width: 100px;
height: 100px;
float: left;
}
.box>div:nth-child(1){
background-color: red;
}
.box>div:nth-child(2){
background-color: yellow;
}
.box>div:nth-child(3){
background-color: skyblue;
}
.box>div:nth-child(4){
background-color: palegreen;
}
</style>
<body>
<div class="box">
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</body>
<script>
var divs = document.querySelectorAll('.box div')
// console.log(divs);
for(var a = 0; a < divs.length; a++){
(function(a) {
divs[a].onclick = function(){
// console.log(a)
var color = getComputedStyle(divs[a])['background-color']
console.log(color)
//给当前网页设置背景颜色
document.body.style.backgroundColor = color
}
})(a)
}
</script>
页面卷去的距离
有文档声明的时候
document.documentElement.scrollTop
没有文档声明的时候
document.body.scrollTop
兼容写法
document.documentElement.scrollTop || document.body.scrollTop
短路运算
短路运算通常使用 || 和 &&
可以用于赋值 -- 看看代码是否能进行到最后(符号的右边),如果能进行到右边,就会将右边的值赋值给
变量;如果进行不到右边,就将左边的值赋值给变量.
利用逻辑运算,查看左边的结果是否能决定整体的结果
节点操作
根据标签之间的关系获取标签
获取子标签
获取所有的子标签节点 -- 父.children
eg: var ul = document.querySelect('ul')
console.log(ul.children)
获取第一个子标签节点-- 父.firstElementChild
console.log(ul.fristElementChild)
获取最后一个子标签节点 -- 父.lastElementChild
console.log(ul.lastElementChild)
获取父标签 -- 子.parentElement
var last = ul.lastElementChild (把最后一个子标签存在last里面)
console.log(last.parentElement)
获取上一个兄弟标签节点
标签.previousElementSibling
获取下一个兄弟标签节点
标签.nextElementSibling
创建标签
document.createElement('标签名字符串')
把标签插入到文档中
1.给父追加一个子 - 将这个标签作为某个父标签的最后一个儿子
语法:父.appendChild(子)
2.将标签放在某个父标签的某个子标签的前面
语法:父.insertBefore(新的子, 旧的子)
替换标签
使用新的子标签替换掉旧的子标签:
语法:父.replaceChild(新, 旧)
删除
父标签将指定的子标签删除:
语法:父.removeChild(子)
复制
将一个标签复制一份出来:
语法:标签.cloneNode() - 返回一个标签对象,这样只能复制一个空的标签,没有内容
带内容的复制 -- 返回一个标签对象,这样可以将标签中的内容也复制出来。
语法: 标签.cloneNode(true)
获取标签尺寸
包含标签边框的尺寸:
标签.offsetWidth
标签.offsetHeight
不包含边框的尺寸
标签.clientWidth
标签.clientHeight
获取元素位置
获取的是相对于设置过定位的父标签的左边距和上边距离,返回纯数字。
标签.offsetLeft
标签.offsetTop
参考设置过定位的祖宗标签,如果祖宗没有定位,就参考html标签
获取边框厚度
获取到的是上边框和左边框的厚度,纯数字。
标签.clientTop
标签.clientLeft
获取标签名
标签.tagName -- 大写的标签名
回流和重绘
浏览器的渲染过程
html结构和css代码同时开始解析,html结构最终被解析成一棵dom树,css代码被解析成一个样式规则 ,dom树和样式规则合并成一颗渲染树. 渲染树开始进行布局(计算标签的大小和位置); 布局完成以后开始绘画(涂颜色),最后将页面显示出来.
如果重新需要布局,那就造成回流了
如果重新绘画,那就造成重绘了
不管是回流还是重绘,都对浏览器渲染造成了性能的影响,为了优化这个性能,我们可以有三个优化手段
样式的合并
减少dom的一些操作
定时器中减少回流
容易造成回流的操作:
布局流相关操作
节点操作
css
优化
合并样式修改
1.使用style的cssText
oDiv.style.cssText = 'padding:5px; border:1px solid #000; margin:5px;';
2.将这几个样式定义给一个类名,然后给标签添加类名
<style>
.pbm{
padding:5px;
border:1px solid #000;
margin:5px;
}
</style>
<script>
var oDiv = document.querySelector('.box');
oDiv.classList.add('pbm');
</script>
批量操作DOM
方法一:隐藏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中
文档碎片 - 虚拟标签,不会在页面中显示的,跟真的标签操作起来是一样的
varfragment=document.createDocumentFragment(); --- 创建文档碎片
for(var a = 0; a < 10; a++) {
var li = document.createElement('li')
li.innerText = a + 1
// ul.appendChild(li)
fg.appendChild(li)
}
ul.appendChild(fg)
ul.style.display = 'block'
文档碎片就是一个虚拟的DOM节点。对文档碎片操作不会造成回流。
方法三:将ul拷贝一份,将所有li放在拷贝中,等都放进去以后,使用拷贝替换掉ul
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)