DOM操作之——DOM节点类型及属性

3,551 阅读5分钟

虽然现在我们在开发中已经用不到自己操作DOM了,之前有JQ,现在更是有VUEREACT两大框架供我们使用,但是我们也有必要了解下,关于原生JS中的DOM操作问题。

  • 这次我们介绍一下DOM节点类型及获取节点的方法

我们认为在页面中所有呈现的内容,都是DOM文档中的一个节点(node),例如:元素标签是元素节点、注释的内容是注释节点、文本内容是文本节点、document是文档节点...

一、节点类型

1、文档节点

  • document
  • 重点记忆属性:
    • nodeType(节点类型):9
    • nodeName(节点名字):“#document”
    • nodeValue(节点文本内容):null

2、元素节点

  • 所有元素标签
  • 重点记忆属性:
    • nodeType(节点类型):1
    • nodeName(节点名字):“大写标签名”
    • nodeValue(节点文本内容):null

3、文本节点

  • 文字、标签之间的空格和换行也被当作文本节点
  • 重点记忆属性:
    • nodeType(节点类型):3
    • nodeName(节点名字):“#text”
    • nodeValue(节点文本内容):文本内容

4、注释节点

  • 注释内容
  • 重点记忆属性:
    • nodeType(节点类型):8
    • nodeName(节点名字):“#comment”
    • nodeValue(节点文本内容):注释内容

二、获取节点的方式

描述节点和节点之间的关系属性,基于这些属性可以获取到指定的节点

1、获取所有子节点——节点集合

  • 语法:[CONTAINER].childNodes
  • 获取当前容器中所有的子节点
  • 包含各种类型的节点
  • 获取到的是一个节点集合,包含容器中的所有类型节点(空格换行是文本节点)

2、获取元素子节点——元素集合

  • 语法:[CONTAINER].children
  • 获取当前容器中所有的元素子节点
  • 获取的是一个元素集合,只有元素节点
  • 只有元素标签的,在IE低版本浏览器中,也会把注释当作元素节点

3、获取父节点

  • 语法:[NODE].parentNode
  • 获取某一个节点的父节点

4、获取一个哥哥节点

  • 语法:[NODE].previousSibling
  • 获取某一个节点的上一个哥哥节点

5、获取一个哥哥元素节点

  • 语法:[NODE].previousElementSibling
  • 获取某一个节点的上一个哥哥元素节点(不兼容IE低版本浏览器)

6、获取一个弟弟节点

  • 语法:[CONTAINER].nextSibling
  • 获取某一个节点的下一个弟弟节点

7、获取一个弟弟元素节点

  • 语法:[CONTAINER].nextElementSibling
  • 获取某一个节点的下一个弟弟元素节点(不兼容IE低版本)

8、获取第一个子节点

  • 语法:[CONTAINER].firstChild
  • 获取容器中第一个子节点

9、获取第一个元素子节点

  • 语法:[CONTAINER].firstElementChild
  • 获取容器中第一个元素子节点(不兼容IE低版本)

10、获取最后一个字节点

  • 语法:[CONTAINER].lastChild
  • 获取容器中最后一个字节点

11、获取最后一个元素子节点

  • 语法:[CONTAINER].lastElementChild
  • 获取容器中最后一个元素子节点(不兼容IE低版本)

所有方法和属性,都是为了快速获取到我们想要操作的DOM元素或者节点的

思维导图

三、需求练习

1、封装一个方法:获取指定容器CONTAINER中的所有元素子节点,需要兼容所有的浏览器

function children(container) {
	// 获取所有的子节点,遍历这些节点,所有NODETYPE===1的就是我们想要的元素子节点
	var nodeList = container.childNodes,
		result = [];
	for (var i = 0; i < nodeList.length; i++) {
		var itemNode = nodeList[i];
		if (itemNode.nodeType === 1) {
			// 元素节点
			result.push(itemNode);
		}
	}
	return result;
}

var arr = children(box);
console.log(arr);

2、获取当前节点的所有元素哥哥节点(兼容所有的浏览器)

JQ中的prevAll这个方法就是干这个的,我们自己封装一个

方法一:循环当前元素父亲的子节点方法

//=> 已知:previousElementSibling是获取上一个哥哥元素节点(兼容性)  previousSibling获取上一个哥哥节点(没有兼容性的)

function prevAll(node) {
	let result = [];
	// 获取它爹
	let parent = node.parentNode;
	// 获取它爹中的儿子(自己和他所有的兄弟)
	let nodeList = parent.childNodes;
	// 循环所有节点,元素类型的是我们想要的,并且找到当前节点后就不在循环了
	for (let i = 0; i < nodeList.length; i++) {
		let item = nodeList[i];
		if (item === node) {
			// 找到的是自己
			break;
		}
		// 找的不是自己,我们把元素节点存储起来
		if (item.nodeType === 1) {
			result.push(item);
		}
	}
	return result;
}

方法二:获取当前节点的哥哥节点,再获取哥哥节点的哥哥节点...一直找到没有哥哥节点为止(没有哥哥节点,结果为NULL); 再查找的过程中,把所有找到的元素节点存储起来即可;

//=> 循环不知道具体次数(不知道找多少次) =>while循环

function prevAll(node) {
	let prev = node.previousSibling,
		result = [];
	// 循环找他的哥哥,一直到没有哥哥了为止
	while (prev !== null) {
		// 把找到的哥哥中是元素节点的存储起来
		if (prev.nodeType === 1) {
			result.unshift(prev);
		}
		prev = prev.previousSibling;
	}
	return result;
}

3、 获取所有的弟弟元素节点(兼容所有的浏览器)

同上题一样,我们同样写两种方法

方法一:

function nextAll(node) {
	// 获取其父亲中所有的儿子
	let nodeList = node.parentNode.childNodes,
		result = [];
	// 倒着从最后一项开始循环
	for (let i = nodeList.length - 1; i >= 0; i--) {
		let item = nodeList[i];
		if (item === node) break;
		item.nodeType === 1 ? result.unshift(item) : null;
	}
	return result;
}

方法二:

function nextAll(node) {
	let result = [],
		next = node.nextSibling;
	while (next !== null) {
		next.nodeType === 1 ? result.push(next) : null;
		next = next.nextSibling;
	}
	return result;
}

4、获取所有的兄弟元素节点:所有的哥哥+所有的弟弟

方法一:

function siblings(node) {
	// 所有的儿子中一定包含了,我和我的兄弟们
	let nodeList = node.parentNode.childNodes,
		result = [];
	// 依次遍历每一个节点,把非元素和我本身除外,其余的存储起来
	for (let i = 0; i < nodeList.length; i++) {
		let item = nodeList[i];
		if (item.nodeType === 1 && item !== node) {
			result.push(item);
		}
		
		// 上面的 if 判断条件也可改写为下面的
		// if (item.nodeType !== 1 || item === node) {
		// 	continue;
		// }
		// result.push(item);
	}
	return result;
}

方法二:利用上面两题我们封装好的方法

function siblings(node) {
	// 分别调用两个方法获取所有的哥哥和所有的弟弟,就是所有的兄弟
	return prevAll(node).concat(nextAll(node));
}

5、获取当前节点的索引:他在所有兄弟中的排行

function index(node) {
	// 它有几个哥哥,那么它的索引就是几
	return prevAll(node).length;
}