什么是DOM
当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)
DOM即文档对象模型,是W3C1制定的标准接口规范,是一种处理HTML和XML文件的标准API。
DOM提供了对整个文档的访问模型,将文档作为一个树形结构,树的每个结点表示了一个HTML标签或标签内的文本项。DOM树结构精确地描述了HTML文档中标签间的相互关联性。将HTML或XML文档转化为DOM树的过程称为解析(parse)。HTML文档被解析后,转化为DOM树,因此对HTML文档的处理可以通过对DOM树的操作实现。DOM模型不仅描述了文档的结构,还定义了结点对象的行为,利用对象的方法和属性,可以方便地访问、修改、添加和删除DOM树的结点和内容。
其中style属性没有放进DOM树中,因为css样式有它该有的归宿----CSSOM树
CSSOM:(简介)2
CSSOM是一组允许JavaScript操作CSS的API。它非常类似于DOM,但是用于CSS而不是HTML。它允许用户动态读取和修改CSS样式。
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="style.css" rel="stylesheet">
<title>Critical Path</title>
</head>
<body>
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg"></div>
</body>
</html>
// style.css
body { font-size: 16px }
p { font-weight: bold }
span { color: red }
p span { display: none }
img { float: right }
这是一个非常简单的Web页面,“包含了一些文本和一幅图片”,浏览器处理这个页面的过程:
对于Web的样式,其处理HTML有点类似,需要将收到的CSS规则转换成某种浏览器能够理解和处理的东西。因此,我们会重复HTML过程,只不过是为CSS而不是HTML:
CSS字节转换成字符,接着转换成令牌和节点,最后链接到一个CSSOM的树结构中:
是不是看上去和DOM结构树类似呀。那么CSSOM为何具有树结构呢?为页面上的任何对象计算最后一组样式时,浏览器都会先从适用于该节点的最通用规则开始,比如,如果该节点是body元素的子元素,则应用所有body样式,然后通过应用更具体的规则(这里将会运用CSS层级相关的管理规则)以递归方式优化计算的样式。
注意,上图显示的树并非是一颗完整的CSSOM树,它只显示了我们决定在样式表中替换的样式。
既然说了DOM、CSSOM就顺带提提:渲染树render tree
HTML 经过解析生成 DOM树; CSS经过解析生成 Style Rules。 二者一结合生成了Render Tree。 通过layout计算出DOM要显示的宽高、位置、颜色。 最后渲染在界面上,用户就看到了
(CSSOM树和DOM树连接在一起形成一个render tree,渲染树用来计算可见元素的布局并且作为将像素渲染到屏幕上的过程的输入。)
Node节点
HTML中的所有内容都可以用节点(Node)来描述
节点共有12种类型,常见的节点类型有
元素节点 elementNode
属性节点 attributeNode
文本节点 textNode 访问Node节点
通过操作DOM树,JS可以实现:
改变页面中任意的HTML元素
改变页面中任意的HTML属性
改变页面中任意的CSS样式
删除页面中任意的HTML元素和属性
添加任意的HTML元素和属性到页面中
对页面中任意的事件做出响应
对页面中的任意元素添加事件
访问Node节点
每个Node节点包括如下属性
节点类型 NodeType
节点名 NodeName
节点值 NodeValue
访问节点文本内容的方法
innerHTML (会返回所有的内部内容,包括子元素的标签)
innerText
textContent
示例:使用innerText获取div中的文本
<div id="divid">div元素</div>
<script>
var div = document.getElementById("divid");
var text = div.innerText;
alert(text);//弹窗显示:div元素
</script>
通过层级关系访问节点
使用以上方法时要注意换行符、空白符等也是一个节点
在操作一个DOM节点前,我们需要通过各种方式先拿到这个DOM节点。最常用的方法是document.getElementById()和document.getElementsByTagName(),以及CSS选择器document.getElementsByClassName()。
由于ID在HTML文档中是唯一的,所以document.getElementById()可以直接定位唯一的一个DOM节点。document.getElementsByTagName()和document.getElementsByClassName()总是返回一组DOM节点。要精确地选择DOM,可以先定位父节点,再从父节点开始选择,以缩小范围。
例如:
// 返回ID为'test'的节点:
var test = document.getElementById('test');
// 先定位ID为'test-table'的节点,再返回其内部所有tr节点:
var trs = document.getElementById('test-table').getElementsByTagName('tr');
// 先定位ID为'test-div'的节点,再返回其内部所有class包含red的节点:
var reds = document.getElementById('test-div').getElementsByClassName('red');
// 获取节点test下的所有直属子节点:
var cs = test.children;
// 获取节点test下第一个、最后一个子节点:
var first = test.firstElementChild;
var last = test.lastElementChild;
第二种方法是使用querySelector()和querySelectorAll(),需要了解selector语法,然后使用条件来获取节点,更加方便:
// 通过querySelector获取ID为q1的节点:
var q1 = document.querySelector('#q1');
// 通过querySelectorAll获取q1节点内的符合条件的所有节点:
var ps = q1.querySelectorAll('div.highlighted > p');
注意:低版本的IE<8不支持querySelector和querySelectorAll。IE8仅有限支持。
严格地讲,我们这里的DOM节点是指Element,但是DOM节点实际上是Node,在HTML中,Node包括Element、Comment、CDATA_SECTION等很多种,以及根节点Document类型,但是,绝大多数时候我们只关心Element,也就是实际控制页面结构的Node,其他类型的Node忽略即可。根节点Document已经自动绑定为全局变量document。
访问元素属性
通过element.属性名访问
或通过element[属性名]访问(可使用变量)
使用getElement系列方法可以访问指定元素
querySelector(): 通过CSS选择器的方式查找指定元素,返回满足条件的第一个元素
querySelectorAll(): 通过CSS选择器的方式查找指定元素,返回满足条件的所有元素
注意querySelector提供的选择功能更强大,但性能及稳定性相对较低*