DOM 指的是文档对象模型,它指的是把文档当做一个对象,这个对象主要定义了处理网页内容的方法和接口。
BOM 指的是浏览器对象模型,它指的是把浏览器当做一个对象来对待,这个对象主要定义了与浏览器进行交互的法和接口。BOM的核心是 window,而 window 对象具有双重角色,它既是通过 js 访问浏览器窗口的一个接口,又是一个 Global(全局)对象。这意味着在网页中定义的任何对象,变量和函数,都作为全局对象的一个属性或者方法存在。window 对象含有 location 对象、navigator 对象、screen 对象等子对象,并且 DOM 的最根本的对象 document 对象也是 BOM 的 window 对象的子对象。
思考:
console.log(window.window)//输出什么?
常见的DOM操作有哪些?
DOM 节点的获取
getElementById // 按照 id 查询
getElementsByTagName // 按照标签名查询
getElementsByClassName // 按照类名查询
querySelectorAll // 按照 css 选择器查询
// 按照 id 查询
var imooc = document.getElementById('imooc') // 查询到 id 为 imooc 的元素
// 按照标签名查询
var pList = document.getElementsByTagName('p') // 查询到标签为 p 的集合
console.log(divList.length)
console.log(divList[0])
// 按照类名查询
var moocList = document.getElementsByClassName('mooc') // 查询到类名为 mooc 的集合
// 按照 css 选择器查询
var pList = document.querySelectorAll('.mooc') // 查询到类名为 mooc 的集合
DOM 节点的创建并把它添加到指定节点的后面。 已知的 HTML 结构如下:
<html>
<head>
<title>DEMO</title>
</head>
<body>
<div id="container">
<h1 id="title">我是标题</h1>
</div>
</body>
</html>
要求添加一个有内容的 span 节点到 id 为 title 的节点后面,做法就是:
// 首先获取父节点
var container = document.getElementById('container')
// 创建新节点
var targetSpan = document.createElement('span')
// 设置 span 节点的内容
targetSpan.innerHTML = 'hello world'
// 把新创建的元素塞进父节点里去
container.appendChild(targetSpan)
DOM 节点删除已知的 HTML 结构如下:
<html>
<head>
<title>DEMO</title>
</head>
<body>
<div id="container">
<h1 id="title">我是标题</h1>
</div>
</body>
</html>
需要删除 id 为 title 的元素,做法是:
// 获取目标元素的父元素
var container = document.getElementById('container')
// 获取目标元素
var targetNode = document.getElementById('title')
// 删除目标元素
container.removeChild(targetNode)
或者通过子节点数组来完成删除:
// 获取目标元素的父元素var container = document.getElementById('container')// 获取目标元素var targetNode = container.childNodes[1]// 删除目标元素container.removeChild(targetNode)
修改 DOM 元素这个动作可以分很多维度,比如说移动 DOM 元素的位置,修改 DOM 元素的属性等。
将指定的两个 DOM 元素交换位置, 已知的 HTML 结构如下:
<html>
<head>
<title>DEMO</title>
</head>
<body>
<div id="container">
<h1 id="title">我是标题</h1>
<p id="content">我是内容</p>
</div>
</body>
</html>
现在需要调换 title 和 content 的位置,可以考虑 insertBefore 或者 appendChild:
// 获取父元素
var container = document.getElementById('container')
// 获取两个需要被交换的元素
var title = document.getElementById('title')
var content = document.getElementById('content')
// 交换两个元素,把 content 置于 title 前面
container.insertBefore(content, title)
常见的BOM操作有哪些?
screenLeft 返回浏览器窗口左上角相当于当前屏幕左上角的水平距离。
screenTop 返回浏览器窗口左上角相当于当前屏幕左上角的垂直距离。
不兼容FF浏览器。
screenX 功能同上。
screenY功能同上。
这两种功能兼容FF 。
innerWidth 返回网页在当前窗口中可见部分的宽度,包含滚动条。
innerHeight 返回网页在当前窗口中可见部分的高度,包含滚动条。
outerWidth 返回浏览器窗口宽度,包含浏览器菜单和边框 。
outerHeight 返回浏览器窗口高度,包含浏览器菜单和边框。
window.open():打开一个新的浏览器窗口,接收4个参数(URL/打开方式/窗口参数/布尔值)。
window.close():关闭新打开的窗口(仅限open()打开的窗口)。
screen功能:包含设备的信息 个别属性举例。
screen.height、screen.width返回设备的分辨率。
location对象 功能:保存当前文档信息、将URL解析为独立片段 属性:href 返回当前页面完整的URL 修改这个属性,即可跳转新页面 hash:返回URL中的hash host:返回服务器名称和端口号 port:返回服务器端口号 pathname:返回URL中的目录和文件名 hostname:返回不带端口号的服务器名称 protocol:返回页面使用的协议 search:返回URL的查询字符串,字符串以问号开头。
navigator对象 提供一系列属性用于检测浏览器 属性:onLine 检测是否联网 userAgent 浏览器嗅探 检测浏览器的类型。
history对象 功能:保存用户上网的历史记录。 方法属性:go()在用户历史记录任意跳转,接收一个参数,标签前后跳转页数的整数值 back()后退 foward()前进。
为什么说操作DOM是昂贵的?
操作DOM会进行线程上的切换,JS引擎然切换到GUI渲染引擎然后GUI渲染引擎再切换回JS引擎这一些的操作就会造成性能损耗,最主要的是操作DOM还有可能引发回流与重绘,比如修改DOM的边距、大小,添加删除元素、改变窗口大小等就会引发重排,设置背景色、修改文字颜色、改变 visibility属性值就会引发重绘,回流必然引发重绘但是重绘不一定引发回流,回流的性能开销要大于重绘。
重绘和回流(Repaint & Reflow),以及如何进行优化
重绘
由于节点的集合属性发生改变或者由于样式改变而不会影响布局的,称为重绘,例如 outline、visibility、color、background-color 等,重绘的代价是高昂的,因此浏览器必须验证DOM 树上其他节点元素的可见性。
回流
回流是布局或者几何属性需要改变就称为回流。回流是影响浏览器性能的关键因素,因为其变化涉及到部分页面(或是整个页面)的布局更新。一个元素的 回流可能会导致其素有子元素以及 DOM 中紧随其后的节点、祖先节点元素的随后 的回流。大部分的回流将导致页面的重新渲染。
浏览器优化
现代浏览器大多是通过队列机制来批量更新布局,浏览器会把修改操作放在 队列中,至少一个浏览器刷新(即 16.6ms)才会清空队列,但当你获取布局信 息的时候,队列中可能会有影响这些属性或方法返回值的操作,即使没有,浏览器也会强制清空队列,触发回流和重绘来确保返回正确的值。
但是会有一些属性会会强制渲染刷新队列我们应该避免这些属性:ffsetTop、clientTop、scrollTop、getComputedStyle()、width、height、getBoundingClientRect()。
代码优化
CSS
1.使用 transform 代替 top;
2.使用 visibility 替换 display: none,前者引起重绘,后者引发回流;
3.避免使用 table 布局;
4.尽可能在 DOM 树的最末端改变 class;
5.避免设置多层内联样式,CSS 选择符从右往左匹配查找,避免节点层级过多;
6.将动画效果应用到 position 属性为 absolute 或 fixed 的元素上,避免影响其他元素的布局;避免使用 CSS 表达式,可能会引发回流;
7.CSS 硬件加速;
JS
1.避免频繁操作样式,修改 class 最好;
2.避免频繁操作 DOM,合并多次修改为一次;
3.避免频繁读取会引发回流/重绘的属性,将结果缓存;
4.对具有复杂动画的元素使用绝对定位,使它脱离文档流;
opacity: 0、visibility: hidden、display: none 优劣和适用场景
1. display: none - 不占空间,不能点击,会引起回流,子元素不影响;
2. visibility: hidden - 占据空间,不能点击,引起重绘,子元素可设置 visible 进行显示;
3. opacity: 0 - 占据空间,可以点击,引起重绘,子元素不影响;