JavaScript DOM 文档对象模型详解

一些定义和说明

  1. 节点及其类型:
    1). 元素节点:html标签
    2). 属性节点: 元素的属性, 可以直接通过属性的方式来操作.
    3). 文本节点: 是元素节点的子节点, 其内容为文本.

在 html 文档的什么位置编写 js 代码?

  1. 直接在 html 页面中书写代码.
    Click Me!
    缺点:
    ①. js 和 html 强耦合, 不利用代码的维护
    ②. 若 click 相应函数是比较复杂的, 则需要先定义一个函数, 然后再在 onclick 属性中完成对函数的引用, 比较麻烦
  2. . 一般地, 不能在 body 节点之前来直接获取 body 内的节点, 因为此时 html 文档树还没有加载完成,
    获取不到指定的节点:
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<title>Untitled Document</title>
		<script type="text/javascript">
			var cityNode = document.getElementById("city");
			//打印结果为 null.
			alert(cityNode);
		</script>
	</head>
	<body>
  1. . 可以在整个 html 文档的最后编写类似代码, 但这不符合习惯
  2. . 一般地, 在 body 节点之前编写 js 代码, 但需要利用 window.onload 事件, 
    该事件在当前文档完全加载之后被触发, 所以其中的代码可以获取到当前文档的任何节点.
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Untitled Document</title>
  <script type="text/javascript">
      window.onload = function () {
          var cityNode = document.getElementById("city");
          alert(cityNode);
      };
  </script>
</head>
<body>

获取标签(元素)节点:

  1. document.getElementById: 根据 id 属性获取对应的单个节点

  2. document.getElementsByTagName: 根据标签名获取指定节点名字的数组, 数组对象 length 属性可以获取数组的长度

  3. document.getElementsByName: 根据节点的 name 属性获取符合条件的节点伪数组, 但 ie 的实现方式和 W3C 标准有差别: 在 html 文档中若某节点(li)没有 name 属性, 则 ie 使用 getElementsByName 不能获取到节点数组, 但火狐可以.

  4. document.getElementsByClassName:根据节点的类名获取标签的伪数组 ,ie8不支持,他是h5标准

  5. document.querySelector("#id名"):获取指定id的标签节点

  6. document.querySelectorAll(".类名"):获取指定选择器的节点


节点(Node)

1.节点的属性:

(1)nodeName: 代表当前节点的名字,只读属性.,如果给定节点是一个文本节点, nodeName 属性将返回内容为 #text 的字符串
(2)nodeType:返回一个整数, 这个数值代表着给定节点的类型. 只读属性. 1 -- 元素节点, 2 -- 属性节点, 3 -- 文本节点3)
(3)nodeValue:返回给定节点的当前值(字符串). 可读写的属性

2. 获取节点

(1)获取节点的父节点:dom对象.parentNode //可联级获取dom对象.parentNode.parentNode上帝节点为document。
(2)获取节点的父元素:dom对象.parentElement
(3)获取子结点:dom对象.childNodes // 获取当前对象的所有子结点
(4)获取子元素:dom对象.children
(5)获取标签/元素的属性结点:dom对象.getAttributeNode("属性名")
(6)获取第一个子节点:dom对象.firstChild
(7)获取第一个子元素:dom对象.firstElementChild
(8)获取最后一个子节点:dom对象.lastChild
(9)获取最后一个子元素:dom对象.ElementChild
(10)获取前一个兄弟节点:dom对象.previousSibling
(11)获取的前一个兄弟元素:dom对象.previousElementSibling;
(12)获取的后一个兄弟节点:dom对象.nextSibling;
(13)获取的后一个兄弟元素:dom对象.nextElementSibling;
注意:[6 - 13]这段代码在IE8中有兼容性问题: 在元素标签与元素标签之间没有文本的前提下,凡是获取节点的,都变成了获取元素,凡是获取元素的,都不支持(undefined)


3. 创建结点:

(1)document.write(“html文档”); //事件调用会出现覆盖,正常页面加载不覆盖。
(2)dom对象.innerHTML= "html文档“; //如果dom对象有子标签,则会被覆盖。如果要追加可以innerHTML += "追加的html文档";
(3)createElement(“标签名称”): 新元素节点不会自动添加到文档里,需要配合父dom对象.appendChild(“新建的元素对象”)方式追加到父dom对象的子元素末尾。

  1. 为元素节点添加子节点配合createElement(“标签名称”)使用:
    (1) dom对象.appendChild():给定子节点 newChild 将成为给定元素节点 element 的最后一个子节点
    (2) dom对象.insertBefore(newNode,targetNode) : 把一个给定节点插入到一个给定元素节点的给定子节点的前面
// 将 newChild 插入到 refChild 的后边
function insertAfter(newChild, refChild){
	var refParentNode = refChild.parentNode;
	//判断 refChild 是否存在父节点
	if(refParentNode){
		//判断 refChild 节点是否为其父节点的最后一个子节点
		if(refChild == refParentNode.lastChild){
			refParentNode.appendChild(newChild);
		}else{
			refParentNode.insertBefore(newChild, refChild.nextSibling);
		}	
	}
}
  1. 节点的替换:
    1). replaceChild(): 把一个给定父元素里的一个子节点替换为另外一个子节点
    var reference = element.replaceChild(newChild,oldChild);
    返回值是一个指向已被替换的那个子节点的引用指针
    2). 该节点除了替换功能以外还有移动的功能.
    3). 该方法只能完成单向替换, 若需要使用双向替换, 需要自定义函数:
/**
 * 互换 aNode 和 bNode
 */
function replaceEach(aNode, bNode){
	if(aNode == bNode){
		return;
	}
	var aParentNode = aNode.parentNode;
	//若 aNode 有父节点
	if(aParentNode){
		var bParentNode = bNode.parentNode;
		//若 bNode 有父节点	
		if(bParentNode){
			var tempNode = aNode.cloneNode(true);
			bParentNode.replaceChild(tempNode, bNode);
			aParentNode.replaceChild(bNode, aNode);	
		}
	}
}   
  1. 删除节点:
    1). 父级dom对象.removeChild(): 删除指定的节点

事件

事件的绑定与解绑

  1. 绑定:dom对象.on事件名 = 事件处理函数名 // 此方法只能添加一个事件处理函数。

  2. 解绑:只需要把事件处理函数的赋值改为null即可dom对象.on事件名 = null

  3. 绑定: dom对象.addEventListener("没有on的事件名称", 事件处理函数名, false) ; 此方式可以叠加绑定事件,一个标签绑定多个事件函数。

  4. 解绑:dom对象.removeEventListener("没有on的事件名称", 要解绑的事件处理函数名, false) ; //此方法不能解绑匿名函数。尾部的布尔参数:指定事件是否在捕获或冒泡阶段执行。详细请看下文。

  5. 绑定:dom对象.attachEvent("带on的事件名称", 事件处理函数,) ; 仅仅ie8支持,此方法不能解绑匿名函数

  6. 解绑:dom对象.detachEvent("带on的事件名称", 事件处理函数,) ;

给节点赋事件的注意:

<button id = "ax"></button>
<script>
    function f1() {
        alert("弹窗");
    }
  
    var eleObj = document.getElementById("ax");
    eleObj.onclick = f1;  // 注意:此处把f1这个函数给eleObj标签的属性onclick,当按钮被点击时才会触发函数,而不是f1()
                          // 如果写f1(); 这表明直接调用了,而不是点击触发弹窗
</script>

不同绑定方式的区别

相同点:都可以为元素绑定事件
不同点:
1.方法名不一样
2.参数个数不一样addEventL istener三个参数,attachEvent两个参数
3. addEventListener谷歌,火狐,IE11支持,IE8不支持
attachEvent谷歌火狐不支持,IE11不支持,IE8支持
4. this不同,addEventListener中的this 是当前绑定事件的对象
attachEvent中的this是window
5. addEventListener中事件的类型(事件的名字)没有on
attachEvent中的事件的类型(事件的名字)有on


事件冒泡

  1. 说明:事件冒泡是指,触发子标签的事件的同时会触发父标签的事件(如果父标签有事件的话)
  2. 屏蔽事件冒泡:
document.getElementsByTagName("div")[0].onclick = function (e) {
        console.log(e);
        e.stopPropagation(); //ie不支持
        window.event.cancelBubble = true; //ie、谷歌支持 火狐不支持
    }

事件的三个阶段

1.事件捕获阶段: 从外向内 dom对象.addEventListener("没有on的事件名称", 事件处理函数名, true);
2.事件目标阶段: 最开始选择的那个
3.事件冒泡阶段: 从里向外 dom对象.addEventListener("没有on的事件名称", 事件处理函数名, false);
4. 获取阶段:e. eventPhase属性会得到值 {1,2,3 }; 1 表示捕获阶段,3表示冒泡阶段,2表示当前阶段。

为同一个元素绑定多个不同的事件,指向相同的事件处理函数

var bu = document.querySelector(".bu");
bu.onclick = f1;
bu.onmouseover = f1;
bu.onmouseout = f1;

function f1(e) {
    switch (e.type) {
       case "click":  
              alert("aaaa"); 
              break;
          case "mouseover": 
              this.style.backgroundColor = "red"; 
              break;
          case "mouseout": 
              this.style.backgroundColor = "purple"; 
              break;
    }
}

兼容代码

  1. 获取指定元素的第一个结点,并兼容ie8
function getFirstEleChile(ele) {
    if (ele.firstElementChild) { //判断是否是能用.firstElementChild获取浏览器属性
        return ele.firstElementChild;
    }else{ //如果不能,执行兼容代码
        var node = ele.firstChild; //获取第一个子结点
        while (node && node.nodeType !== "1") {   //如果这个结点不存在,或者不是标签,则向下找,判断node是不是undefined是防止死循环
            node = node.nextSibling;
        }
        return node; //
    }
}
  1. 事件绑定与解绑的兼容代码
//绑定
function addEventListener(element, type, fun) {
   if (element.addEventListener) { //判断这个函数是否兼容浏览器,注意:判断的是函数的变量没有()
        element.addEventListener(type, fun, false);
    }else if (element.attachEvent) {  //此方法已经被弃用,仅仅ie8支持
        element.attachEvent("on" + type, fun);
    }else {
        element.["on"+type] = fun;  //如果上边的两个都不支持,则用最原始的方式赋事件
    }
}

//解绑
function removeEventListener(element, type, fun) {
    if (element.removeEventListener) {
        element.removeEventListener(type, fun, false);
    }else if (element.detachEvent) {
        element.detachEvent("on" + type, fun);
    }else {
        element.["on"+type] = null;
    }
}

发布了51 篇原创文章 · 获赞 20 · 访问量 1536

猜你喜欢

转载自blog.csdn.net/qq_39711439/article/details/102522957