DOM基础及深入

发布于 2021-01-24  95 次阅读 本文共6237个字


什么是DOM?

DOM 是Document Object Model 的缩写,是对XML文档的内容进行表示的模型。它把XML文档看做是一系列node节点间的关系,并且把每一个node都当做一个对象,所以叫文档对象模型。

DOM还提供了一系列的API,是允许添加、编辑、移动、删除DOM树种任意位置的节点的,从而创建了一个引用程序。

在网页中,我们可以把DOM理解为不仅是对网页中各个元素关系的描述(把每个元素或文本都视为一个节点,即node,关系是指每个节点之间是兄弟关系还是父子关系等等),并且还可以把每个网页元素或者一段文字,都当成一个可操作的对象。比如说:html元素和body元素是父节点与子节点的关系。body下的某个div和span又是什么关系等等。

获取DOM节点

1、通过document获取

API说明
getElementById通过元素ID获取节点:
document.getElementById(元素ID名)
getElementByName通过元素的name属性获取节点:
document.getElementByName(元素name属性)
getElementByTagName通过元素的标签名获取节点:
document.getElementByTagName(元素标签)
它返回的都nodeList对象
getElementByClassName通过类名获取节点:
getElementByClassName(元素类名) [IE6/7/8不支持]
querySelector获取一个DOM元素:
document.querySelector(任意选择器) [IE8及以上]
querySelectorAll获取一组DOM元素:
document.querySelectorAll(任意选择器)[IE8及以上]

2、通过节点指针获取

节点属性表:

API名称说明
Node节点DOM定义的node接口,js中所有的节点类型均继承自node类型
nodeValue节点值Text节点或document节点的文本内容,可进行读写操作
nodeName节点名称元素的标签名,以大写形式表示
nodeType节点类型表示该节点的类型
childNodes子节点每个节点都有childNodes属性,它是只读的类数组对象,实时动态的保存该节点的子节点
children子节点children只包含element元素,它的功能和childNodes类似,不同的是children是非标准属性,由IE提出的,在某些浏览器中不兼容
nodeList节点列表nodeList是类数组对象,用于动态的保存一组有序的节点
parentNode父节点该节点的父节点,但类似document这样的对象没有父节点,它的parentNode属性为null
previousSibling上一个兄弟节点该节点的兄弟节点中的上一个,和该节点具有相同的父节点
nextSibling下一个兄弟节点该节点的兄弟节点中的下一个,其中,具有相同的父节点的两个节点成为兄弟节点
firstChild第一个子节点该节点的子节点的第一个节点,该节点没有子节点则为null
lastChild最后一个节点该节点的子节点的最后一个节点,该机诶单没有子节点则为null

节点信息表:

API名称nodeTypenodeNamenodeValue
Element元素1元素的标签名null
Attribute属性2属性的名称属性值
Text文本3#text节点内包含的文本
Comment注释8#comment注释的内容
Document文档9#documentnull
Fragment文档碎片11#document-fragmentnull

操作DOM节点

1、创建节点

createElement()

此方法可创建元素节点,返回的是一个Element节点,具有指定的标签名。创建出来的新元素节点不会被自动添加到文档里,既然没有添加到文档里,说明它还是一个游离的状态,所以它也没有nodeParent属性。如果想把它添加到文档里,可使用appendChild() 或 insertBefore() 或 replaceChild() 方法。

document.createElement();
let oDiv = document.createElement('div');
document.body.appendChild(oDiv);

createAttribute() 和 createTextNode()

createAttribute()方法用于创建一个新的Attribute节点,给元素添加属性。createTextNode() 是用于创建一个文本节点,所以nodeType等于3,如下边的hello.nodeName将返回#text。和createElement()一样,用createTextNode() 创建的节点也不会自动添加到文档里。需要使用appendChild() 或 insertBefore() 方法或 replaceChild() 方法。它经常与createElement() 配合使用。

let oDiv = document.createElement('div');
oDiv.setAttribute('title', 'my demo');
document.body.appendChild(oDiv);

// 如果需要添加文字,则需要createTextNode()这个方法了
let hello = document.createTextNode('hello world');
let container = document.createElement('div');
container.appendChild(hello);
document.body.appendChild(container);

注意:一定要理解好元素节点与文本节点的区别。元素节点是没有nodeValue的,只有文本节点才有nodeValue。在IE9以下浏览器中,回车换行不算一个文本节点,但标准浏览器中这是个文本节点。

createFragment()

此方法用于创建文档片段,虽然不能把文档片段直接添加到文档中,但是它可以作为一个‘仓库’来使用,将可能需要添加到文档中的节点保存在这里,需要添加时可以一次性将需要添加的节点添加到文档中,避免浏览器的反复渲染,提高性能。

let oFragment = document.createDocumentFragment();
let ul = document.getElementById('list');
let oLi = null;
for(let i = 0; i < 10; i++) {
  oLi = document.createElement('li');
  oLi.appendChild(document.createTextNode('item' + (i + 1)));
  oFragment.appendChild(oLi);
};
ul.appendChild(oFragment);

2、插入节点

appendChild()

在指定元素节点的最后一个子节点之后添加节点,需要注意的是,该方法返回的是新的子节点。它经常跟createElement() 和 createTextNode()、cloneNode() 配合使用。另外,appendChild() 不仅可以用来追加新的元素,也可以挪动文档中现有的元素。

let container = document.createElement('div');
let text = document.createTextNode('hello world');
container.appendChild(text);
document.body.appendChild(container);
<div id="hello"> hello</div>
<div id="world">world</div>
<script>
  let hello = document.getElementById('hello');
  let world = document.getElementById('world');
  world.appendChild(hello)
  // 这时我们会发现hello 跑到 world 后边去了
</script>

insertBefore(newNode, oldNode)

在已有的子节点前插入一个新的子节点。使用该方法需要注意以下两点: 第二个参数是可选的,如果第二个参数不写,将默认添加到文档的最后,相当于appendChild(),此方法可返回新的子节点。

<div id="parent">
  <div id="hello">hello</div>
  <p id="world">world</p>
</div>
<script>
  let parent = document.getElementById('parent');
  let hello = document.getElementById('hello');
  let world = document.getElementById('world');
  parent.insertBefore(world, hello);
  // 这时我们会发现world插入到了hello前面
</script>

3、替换节点

replaceChild(newNode, oldNode)

该是删除一个子节点并用一个新的节点代替原来节点的位置,使用时需要注意:
1、该方法接受两个参数,第一个参数是新节点,第二个参数是需要被替代的节点;
2、被替换的节点没有消失,只是在文档树中被移除了,没有了它的位置,但还存在与文档中;
3、这个方法需要在父节点上调用,如果替换成功则返回被替换的节点,如果失败则返回null。

<div id="app">
  <div id="hello">hello</div>
</div>
<script>
  let app = document.getElementById('app');
  let hello = document.getElementById('hello');
  let world = document.createElement('p');
  app.replaceChild(world, hello);
  // 这时候你打开控制台Elements查看,会发现app下边的节点变成了p
</script>

4、克隆/复制节点

cloneNode(boolean)

此方法接受一个布尔值参数,用于复制节点操作,使用时需注意:
1、参数boolean为false时,表示执行浅复制,即只复制节点本身;
2、参数boolean为true时,表示执行深复制,即会复制节点本身及其整个子节点树;
3、复制后返回的节点没有指定的父节点,不会被自动插入到文档中,在文档中处于游离状态;
4、如果克隆后,id一样,不要忘记setAttribute('id', 'another_id'),去改变新的节点id。

let hello = document.createTextNode('hello');
let container = document.createElement('p');
container.appendChild(hello);
document.body.appendChild(container);
let cloneP = container.cloneNode(true); // true 和 false 区别
document.body.appendChild(cloneP)

5、删除节点

removeChild(node)

该方法可以从子节点列表中删除某个节点。若删除成功,则此方法返回被删除的节点,若删除失败则返回null。如果你想把某个节点从一个地方移动到另一个地方,不必使用removeChild(),可以使用前面的appendChild() 和 insertBefore(),他们都会自动先删除节点,然后移动到你指定的地方。

<div id="app">
  <p id="hello">hello</p>
  <p id="world">world</p>
</div>
<script>
  let app = document.getElementById('app');
  let world = document.getElementById('world');
  app.removeChild(world); // 这个方法也是由父元素来调用
</script>

如果不知道要删除的节点的父节点是什么,可以使用parentNode 属性。

<div id="app">
  <p id="hello">hello</p>
  <p id="world">world</p>
</div>
<script>
  let world = document.getElementById('world');
  let parent = world.parentNode;
  parent.removeChild(world);
</script>

6、判断节点

hasChildNodes()

此方法可判断指定节点是否存在子节点,若存在一个或多个子节点,则返回值为true,否则返回值为false。

<div id="app">
  <p id="hello">hello</p>
  <p id="world">world</p>
</div>
<script>
  let app = document.getElementById('app');
  if (app.hasChildNodes) {
    alert(app.childNodes.length);
  }
</script>

节点属性操作

1、获取属性、设置属性、删除属性

getAttribute()

该方法用于获取节点的属性,获取的时候,如果属性不存在,则返回空,注意IE和Firefox返回不同,返回虽然不同,但是可以用一个方法来判断:if(app.getAttribute('title'))

<div id="app"></div>
<script>
  let app = document.getElementById('app');
  let getAttr = app.getAttribute('title');
  console.log(getAttr);
</script>

setAttribute()

该方法用于设置节点属性

let p = document.createElement('p');
p.setAttribute('title', 'my demo');

removeAttribute()

该方法用于移除节点的属性

<div id="app"></div>
<script>
  let app = document.getElementById('app');
  let getAttr = app.getAttribute('title');
  console.log(getAttr);
  let removeAttr = getAttr.removeAttribute('title');
  console.log(removeAttr);
</script>

判断属性

hasAttribute()

该方法用于判断一个元素是否具有指定的属性,如果当前元素节点拥有指定属性,则返回true,否则返回false,但是不返回那个属性的值。若文档中明确设置了指定的属性,或者是文档类型声明为该属性设置了默认值,则hasAttribute() 方法都返回true。


努力,只为遇见更好的自己!