一、DOM简介
DOM:document object model 文档对象模型
文档:整个HTML页面
对象:网页的每一个部分
模型:表示对象之间的关系,方便我们获取对象
节点(Node):
文档节点:整个html文档
元素节点:html文档中的标签
属性节点:元素的属性
文本节点:html中文本内容
浏览器已经提供文档节点对象 对象这个对象时window属性
可以在页面中直接使用 文档节点代表的是整个网页
二、通过DOM来操作CSS样式
通过JS修改元素样式:
语法:元素.style.样式名 = 样式值
通过style属性设置的样式都是内联样式!!!
内联样式由较高的优先级 通过js修改后立即生效
如果在样式中使用了!important 则此时样式会有较高的优先级
使用JS修改时样式会失效 所以尽量不要使用!important
如果CSS样式中含有- 则在JS中不合法的
需要将这种样式名修改为驼峰命名法
第二个单词首字母大写
例:
box1.style.width = "300px";
box1.style.height = "300px";
box1.style.backgroundColor = "#bfa";
通过style属性读取到元素的属性
语法:元素.style.样式名
它读取到的都是内联样式!!!!
三、DOM查询
- 通过具体的元素节点来查询
- 元素.getElementsByTagName()
- 通过标签名查询当前元素的指定后代元素,返回数组
- 元素.childNodes
- 获取当前元素的所有子节点
- 会获取到空白的文本子节点
- childNodes属性会获取包括文本节点在呢的所有节点
- 根据DOM标签标签间空白也会当成文本节点
- 注意:在IE8及以下的浏览器中,不会将空白文本当成子节点
- 元素.children
- 获取当前元素的所有子元素
- 元素.firstChild
- 获取当前元素的第一个子节点(包括空白文本节点)
- 元素.lastChild
- 获取当前元素的最后一个子节点
- 元素.parentNode
- 获取当前元素的父元素
- 元素.firstElementChild获取当前元素的第一个子元素
- firstElementChild不支持IE8及以下的浏览器
- 元素.previousSibling
- 获取当前元素的前一个兄弟节点
- 元素.nextSibling
- 获取当前元素的后一个兄弟节点
innerHTML和innerText
- 这两个属性并没有在DOM标准定义,但是大部分浏览器都支持这两个属性
- 两个属性作用类似,都可以获取到标签内部的内容,
- 不同是innerHTML会获取到html标签,而innerText会自动去除标签
- 如果使用这两个属性来设置标签内部的内容时,没有任何区别的
- innerHTML用于获取元素内部的HTML代码的
- 对于自结束标签,这个属性没有意义
读取标签内部的文本内容
<h1>h1中的文本内容</h1>
元素.firstChild.nodeValue
- document对象的其他的属性和方法
document.all
- 获取页面中的所有元素,相当于document.getElementsByTagName("*");
document.documentElement
- 获取页面中html根元素
document.body
- 获取页面中的body元素
document.getElementsByClassName()
- 根据元素的class属性值查询一组元素节点对象
- 这个方法不支持IE8及以下的浏览器
document.querySelector()
- 根据CSS选择器去页面中查询一个元素
- 如果匹配到的元素有多个,则它会返回查询到的第一个元素
- 需要一个选择器的字符串作为参数,可以根据一个CSS选择器来查询一个元素节点对象
IE8支持此方法!!!!
如果满足条件的元素有多个,
使用该方法总会返回唯一一个元素
document.querySelectorAll()
- 根据CSS选择器去页面中查询一组元素
- 会将匹配到所有元素封装到一个数组中返回,即使只匹配到一个
文本框.value
-读取文本框的value属性值
如果需要读取元素节点属性
直接使用 元素.属性名
例子:元素.id 元素.name 元素.value
注意:class属性不能采用这种方式,
读取class属性时需要使用 元素.className
四、DOM增删改
1.节点创建:
1.1 createElement
createElement通过传入指定的一个标签名来创建一个元素,如果传入的标签名是一个未知的,则会创建一个
自定义的标签,注意:IE8以下浏览器不支持自定义标签
var div = document.createElement("div");
使用createElement要注意:通过createElement创建的元素并不属于html文档,它只是创建出来,并未
添加到html文档中,要调用appendChild或insertBefore等方法将其添加到HTML文档树中;
1.2 createTextNode
createTextNode用来创建一个文本节点,用法如下
var textNode = document.createTextNode("一个TextNode");
createTextNode接收一个参数,这个参数就是文本节点中的文本,和createElement一样,创建后的文本
节点也只是独立的一个节点,同样需要append Child将其添加到HTML文档树中
例:
// 创建li元素节点对象
/*
document.createElement()
创建元素节点对象
他需要一个标签名作为参数
并将创建好的对象作为返回值返回
*/
var li = document.createElement("li");
/*
document.createTextNode()
创建文本节点对象
需要一个文本内容作为参数 将会根据内容创建文本节点
并将新的节点返回
*/
var gzText = document.createTextNode("广州");
// 将gzText设置为li的子节点
/*
appendChild()向一个父节点中添加一个子节点
父节点.appendChild(子节点);
*/
li.appendChild(gzText);
1.3 cloneNode
cloneNode是用来返回调用方法的节点的一个副本,它接收一个bool参数,用来表示是否复制子元素,使用如
下:
var parent = document.getElementById("parentElement");
var parent2 = parent.cloneNode(true);// 传入true
parent2.id = "parent2";
这段代码通过cloneNode复制了一份parent元素,其中cloneNode的参数为true,表示parent的子节点也
被复制,如果传入false,则表示只复制了parent节点
<body>
<div id="parent">
我是父元素的文本
<br/>
<span>
我是子元素
</span>
</div>
<button id="btnCopy">复制</button>
<script>
var parent = document.getElementById("parent");
//点击id="btnCopy"点击执行执行函数(函数内是一个元素的拷贝)
document.getElementById("btnCopy").onclick = function(){
var parent2 = parent.cloneNode(true);
parent2.id = "parent2";
document.body.appendChild(parent2);
}
</script>
</body>
这段代码很简单,主要是绑定button事件,事件内容是复制了一个parent,修改其id,然后添加到文档中
这里有几点要注意:
和createElement一样,cloneNode创建的节点只是游离有html文档外的节点,要调用appendChild方法才
能添加到文档树中
如果复制的元素有id,则其副本同样会包含该id,由于id具有唯一性,所以在复制节点后必须要修改其id
调用接收的bool参数最好传入,如果不传入该参数,不同浏览器对其默认值的处理可能不同
除此之外,我们还有一个需要注意的点:
如果被复制的节点绑定了事件,则副本也会跟着绑定该事件吗?这里要分情况讨论:
如果是通过addEventListener或者比如onclick进行绑定事件,则副本节点不会绑定该事件
如果是内联方式绑定比如
<div onclick="showParent()"></div>
这样的话,副本节点同样会触发事件
1.4 createDocumentFragment
createDocumentFragment方法用来创建一个DocumentFragment。在前面我们说到DocumentFragment
表示一种轻量级的文档,它的作用主要是存储临时的节点用来准备添加到文档中
createDocumentFragment方法主要是用于添加大量节点到文档中时会使用到。假设要循环一组数据,然后
创建多个节点添加到文档中
<ul id="list"></ul>
<input type="button" value="添加多项" id="btnAdd" />
document.getElementById("btnAdd").onclick = function(){
var list = document.getElementById("list");
for(var i = 0;i < 100; i++){
var li = document.createElement("li");
li.textContent = i;
list.appendChild(li);
}
}
这段代码将按钮绑定了一个事件,这个事件创建了100个li节点,然后依次将其添加HTML文档中。这样做有一个
缺点:每次一创建一个新的元素,然后添加到文档树中,这个过程会造成浏览器的回流。所谓回流简单说就是
指元素大小和位置会被重新计算,如果添加的元素太多,会造成性能问题。
这个时候,就是使用createDocumentFragment了DocumentFragment不是文档树的一部分,它是保存在内
存中的,所以不会造成回流问题。我们修改上面的代码如下
document.getElementById("btnAdd").onclick = function(){
var list = document.getElementById("list");
var fragment = document.createDocumentFragment();
for(var i = 0;i < 100; i++){
var li = document.createElement("li");
li.textContent = i;
fragment.appendChild(li);
}
list.appendChild(fragment);
}
优化后的代码主要是创建了一个fragment,每次生成的li节点先添加到fragment,最后一次性添加到list
2.节点修改
2.1 appendChild
appendChild我们在前面已经用到多次,就是将指定的节点添加到调用该方法的节点的子元素的末尾。调用
方法如下:
parent.appendChild(child);
child节点将会作为parent节点的最后一个子节点
appendChild这个方法很简单,但是还有有一点需要注意:如果被添加的节点是一个页面中存在的节点,则
执行后这个节点将会添加到指定位置,其原本所在的位置将移除该节点,也就是说不会同时存在两个该节点在
页面上,相当于把这个节点移动到另一个地方
<div id="child">
要被添加的节点
</div>
<br/>
<br/>
<br/>
<div id="parent">
要移动的位置
</div>
<input id="btnMove" type="button" value="移动节点" />
<script>
document.getElementById("btnMove").onclick = function(){
var child = document.getElementById("child");
document.getElementById("parent").appendChild(child);
}
</script>
这段代码主要是获取页面上的child节点,然后添加到指定位置,可以看到原本的child节点被移动到parent
中了。
这里还有一个要注意的点:如果child绑定了事件,被移动时,它依然绑定着该事件
2.2 insertBefore
insertBefore用来添加一个节点到一个参照节点之前,用法如下
parentNode.insertBefore(newNode,refNode);
parentNode表示新节点被添加后的父节点
newNode表示要添加的节点
refNode表示参照节点,新节点会添加到这个节点之前
<div id="parent">
父节点
<div id="child">子元素</div>
</div>
<input type="button" id="insertNode" value="插入节点" />
<script>
var parent = document.getElementById("parent");
var child = document.getElementById("child");
document.getElementById("insertNode").onclick = function(){
var newNode = document.createElement("div");
newNode.textContent = "新节点"
parent.insertBefore(newNode,child);
}
</script>
这段代码创建了一个新节点,然后添加到child节点之前
和appendChild一样,如果插入的节点是页面上的节点,则会移动该节点到指定位置,并且保留其绑定的事件。
关于第二个参数参照节点还有几个注意的地方:
refNode是必传的,如果不传该参数会报错,如果refNode是undefined或null,则insertBefore会将节点添加到子元素的末尾
2.3 removeChild
let oldChild = node.removeChild(child);
//OR
element.removeChild(child);
child 是要移除的那个子节点.
node 是child的父节点.
oldChild保存对删除的子节点的引用. oldChild === child.
被移除的这个子节点仍然存在于内存中,只是没有添加到当前文档的DOM树中,因此,你还可以把这个节点重新
添加回文档中,当然,实现要用另外一个变量比如上例中的oldChild来保存这个节点的引用. 如果使用上述语
法中的第二种方法, 即没有使用 oldChild 来保存对这个节点的引用, 则认为被移除的节点已经是无用的,
在短时间内将会被内存管理回收.
如果上例中的child节点不是node节点的子节点,则该方法会抛出异常.
// 先定位父节点,然后删除其子节点
var d = document.getElementById("top");
var d_nested = document.getElementById("nested");
var throwawayNode = d.removeChild(d_nested);
// 无须定位父节点,通过parentNode属性直接删除自身
var node = document.getElementById("nested");
if (node.parentNode) {
node.parentNode.removeChild(node);
}
// 移除一个元素节点的所有子节点
var element = document.getElementById("top");
while (element.firstChild) {
element.removeChild(element.firstChild);
}
第二种删除子节点的方法:子节点.parentNode.removeChild(子节点);
2.4 replaceChild
replaceChild用于使用一个节点替换另一个节点,用法如下
parent.replaceChild(newChild,oldChild);
newChild是替换的节点,可以是新的节点,也可以是页面上的节点,如果是页面上的节点,则其将被转移到
新的位置
oldChild是被替换的节点
2.5 页面修改型API总结
页面修改型api主要是这四个接口,要注意几个特点:
不管是新增还是替换节点,如果新增或替换的节点是原本存在页面上的,则其原来位置的节点将被移除,也就
是说同一个节点不能存在于页面的多个位置
节点本身绑定的事件会不会消失,会一直保留着

本文介绍了DOM的基本概念,包括如何通过DOM操作CSS样式,以及DOM查询、增删改节点的方法,如createElement、appendChild、removeChild等,帮助理解DOM在网页动态更新中的作用。
1807

被折叠的 条评论
为什么被折叠?



