节点Nodes 与 Element节点 的区别
官方解释
在 HTML DOM (文档对象模型)中,每个部分都是节点:
- 文档本身是文档节点
- 所有 HTML 元素是元素节点
- 所有 HTML 属性是属性节点
- HTML 元素内的文本是文本节点 (包括回车符也是属于文本节点)
- 注释是注释节点
Element
对象可以拥有类型为元素节点、文本节点、注释节点的子节点。
NodeList
对象表示节点列表,比如 HTML 元素的子节点集合。
元素也可以拥有属性。属性是属性节点。
总结:元素是元素节点,是节点中的一种,但元素节点中可以包含很多的节点。
自己总结
Dom 文档是层级节点的合集,每个节点都可以有自己的父级/子级节点,节点是有类型的,分为文档节点、注释节点、元素节点、属性节点、文本节点。
所以 Element(元素)是节点的一种。可以吧Node节点看做基类,element 继承基类,具有Node的属性方法,同事拓展了许多自身特有的属性方法。
高频属性方法
常用的 Document 的方法
方法 | 描述 |
---|---|
createComment(data) | 用指定的字符串创建新的Comment节点 |
createElement(tagName[, options]) | 用指定的标记名创建新的Element节点 |
createTextNode(data) | 用指定的文本创建新的TextNode节点 |
getElementId(id) | 返回文档中具有指定id属性的Element节点 |
getElementByTagName(tagName) | 返回文档中具有指定标记名的所有Element节点 |
示例
// 通过ID获取元素
var elem = document.getElementById('id');
// 通过标签名获取元素
var allParas = document.getElementsByTagName("p");
// 创建元素
let newDiv = document.createElement("div");
// 注释节点
var comment = docu.createComment('这是注释内容');
newDiv.appendChild(comment);
// 文本节点
let newContent = document.createTextNode("Hi there and greetings!");
// 添加文本节点 到这个新的 div 元素
newDiv.appendChild(newContent);
复制代码
Node常用的属性和方法
属性 | 描述 |
---|---|
childNodes | 以Node[]的形式存放当前节点的子节点,如果没有节点,则返回空数组 |
firstChild | 以Node的形式返回当前节点的第一个节点,如果没有节点则返回NULL |
lastChild | 以Node的形式返回当前节点的最后一个节点,如果没有节点则返回NULL |
parentNode | 以Node的形式返回当前节点的父节点,如果没有节点则返回NULL |
nodeName | 节点的名字,Element节点则代表Element标记的名称 |
nodeType | 代表节点的类型 |
方法 | 描述 |
---|---|
appendChild(aChild) | 通过把一个节点增加到当前节点的childNode[]组,给文档树增加节点 |
cloneNode(deep) | 复制当前节点,或者复制当前节点以及它的所有子孙节点 |
hasChildNodes() | 如果当前节点拥有子结点,则返回true |
insertBefore(newNode, referenceNode) | 给文档树插入一个节点,位置在当前节点的指定位置之前,如果该节点已经存在,则删除之,然后再将节点插入到它的位置。 |
removeChild(child) | 从文档树中删除并返回指定的子结点 |
replaceChild(newChild, oldChild) | 从文档树中删除并返回指定的子结点,用另一个节点替代它。 |
示例
// 创建一个新的段落元素 <p>,然后添加到 <body> 的最尾部
var p = document.createElement("p");
document.body.appendChild(p);
var dupNode = node.cloneNode(deep);
// node
// 将要被克隆的节点
// dupNode
// 克隆生成的副本节点
// deep 可选
// 是否采用深度克隆,如果为true,则该节点的所有后代节点也都会被克隆,如果为false,则只克隆该节点本身.
var p = document.getElementById("para1"),
var p_prime = p.cloneNode(true);
// 如果id为foo的这个元素有子节点,则从dom树中删除它的第一个子节点
var foo = document.getElementById("foo");
if ( foo.hasChildNodes() ) {
foo.removeChild( foo.childNodes[0] );
}
var insertedNode = parentNode.insertBefore(newNode, referenceNode);
// insertedNode 被插入节点(newNode)
// parentNode 新插入节点的父节点
// newNode 用于插入的节点
// referenceNode newNode 将要插在这个节点之前
// 如果 referenceNode 为 null 则 newNode 将被插入到子节点的末尾。
let oldChild = node.removeChild(child);
parentNode.replaceChild(newChild, oldChild);
// newChild
// 用来替换 oldChild 的新节点。如果该节点已经存在于 DOM 树中,则它首先会被从原始位置删除。
// oldChild
// 被替换掉的原始节点。
复制代码
Element常用的属性和方法
属性 | 描述 |
---|---|
tagName | 以字符串形式返回指定属性的值 |
innerHTML | 返回该元素包含的HTML代码,可读写 |
className | 返回当前元素的class属性,可读写 |
style | 返回元素节点的行内样式,可读写 |
方法 | 描述 |
---|---|
addEventListener(type, listener, options) | 添加事件的回调函数 |
removeEventListener(type, listener[, options]) | 移除事件监听函数 |
dispatchEvent() | 触发事件 |
preventDefault() | 阻止默认的点击事件执行 |
setAttribute() | 把指定的属性设置为指定的字符串值,如果该属性不存在则添加一个新属性 |
浏览器事件捕获,冒泡
浏览器事件模型中的过程主要分为三个阶段:捕获阶段、目标阶段、冒泡阶段。
parent.addEventListener("click", function (e) {
// e.stopPropagation(); 不再派发事件。终止事件在传播过程的捕获、目标处理或起泡阶段进一步传播。调用该方法后,该节点上处理该事件的处理程序将被调用,事件不再被分派到其他节点。
// e.target.nodeName 指当前点击的元素, e.currentTarget.nodeName绑定监听事件的元素
console.log("parent 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);
复制代码
addEventListener(type, listener, options) 第三个参数
这里要注意addEventListener
的第三个参数, 如果为true
,就是代表在捕获阶段执行。如果为false
,就是在冒泡阶段进行。
阻止事件传播
- e.stopPropagation()
大家经常听到的可能是阻止冒泡,实际上这个方法不只能阻止冒泡,还能阻止捕获阶段的传播。
- stopImmediatePropagation()
如果有多个相同类型事件的事件监听函数绑定到同一个元素,当该类型的事件触发时,它们会按照被添加的顺序执行。如果其中某个监听函数执行了 event.stopImmediatePropagation() 方法,则当前元素剩下的监听函数将不会被执行。
阻止默认行为
- e.preventDefault()
可以阻止事件的默认行为发生,默认行为是指:点击a标签就转跳到其他页面、拖拽一个图片到浏览器会自动打开、点击表单的提交按钮会提交表单等等,因为有的时候我们并不希望发生这些事情,所以需要阻止默认行为
事件委托的方式
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
</ul>
</body>
<script type="text/javascript">
const ul = document.querySelector("ul");
ul.addEventListener('click', function (e) {
const target = e.target;
if (target.tagName.toLowerCase() === "li") {
const liList = this.querySelectorAll("li");
index = Array.prototype.indexOf.call(liList, target);
alert(`内容为${target.innerHTML}, 索引为${index}`);
}
})
</script>
</html>
复制代码
兼容性
attachEvent——兼容:IE7、IE8; 不支持第三个参数来控制在哪个阶段发生,默认是绑定在冒泡阶段 addEventListener——兼容:firefox、chrome、IE、safari、opera;
浏览器兼容的绑定事件函数
class BomEvent {
constructor(element) {
this.element = element;
}
addEvent(type, handler) {
if (this.element.addEventListener) {
//事件类型、需要执行的函数、是否捕捉
this.element.addEventListener(type, handler, false);
} else if (this.element.attachEvent) {
this.element.attachEvent('on' + type, function () {
handler.call(element);
});
} else {
this.element['on' + type] = handler;
}
}
removeEvent(type, handler) {
if (this.element.removeEnentListener) {
this.element.removeEnentListener(type, handler, false);
} else if (element.datachEvent) {
this.element.detachEvent('on' + type, handler);
} else {
this.element['on' + type] = null;
}
}
}
// 阻止事件 (主要是事件冒泡,因为IE不支持事件捕获)
function stopPropagation(ev) {
if (ev.stopPropagation) {
ev.stopPropagation(); // 标准w3c
} else {
ev.cancelBubble = true; // IE
}
}
// 取消事件的默认行为
function preventDefault(event) {
if (event.preventDefault) {
event.preventDefault(); // 标准w3c
} else {
event.returnValue = false; // IE
}
}
复制代码