DOM——Document Object Model 文档对象模型

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

一、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主要是这四个接口,要注意几个特点:
不管是新增还是替换节点,如果新增或替换的节点是原本存在页面上的,则其原来位置的节点将被移除,也就
是说同一个节点不能存在于页面的多个位置
节点本身绑定的事件会不会消失,会一直保留着
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值