金色小芝麻

vuePress-theme-reco 金色小芝麻    2021 - 2023
金色小芝麻 金色小芝麻

Choose mode

  • dark
  • auto
  • light
主页
分类
  • JavaScript
  • BUG复盘
  • SVG笔记
  • TypeScript
  • 个人总结
  • CSS笔记
  • 开发工具
  • 前端入门
  • Vue2.0
  • 性能优化
  • 架构学习
  • 每日一题
标签
时间轴
社交
  • 掘金 (opens new window)
author-avatar

金色小芝麻

83

文章

27

标签

主页
分类
  • JavaScript
  • BUG复盘
  • SVG笔记
  • TypeScript
  • 个人总结
  • CSS笔记
  • 开发工具
  • 前端入门
  • Vue2.0
  • 性能优化
  • 架构学习
  • 每日一题
标签
时间轴
社交
  • 掘金 (opens new window)
  • 前端入门

    • 博客搭建过程及相关配置
    • 数组中的16种常用方法
    • JS中的数据类型简析——基本数据类型值
    • JS中的数据类型object基础
    • JS中三种常见的判断
    • 数据类型之间的区别(堆内存Heap VS 栈内存Stack)
    • JS基础练习题及解析
    • 开关灯的小案例
    • JS中数据类型检测方法——typeof
    • 条件判断几个小练习
    • JS循环——for循环
    • 自定义属性实现选项卡小案例
    • 字符串中的12种常用方法
    • DOM操作的简单原理
    • JS实现隔行变色鼠标跟随小案例
    • JS中function的基础知识
    • JS中数组去重的三种方法
    • JS中时间格式化的三种方法
    • JS中URL参数处理的三种方法
    • JS小案例——获取随机验证码
    • DOM操作之——获取DOM标签的9种方式
    • DOM操作之——DOM节点类型及属性
    • DOM操作之——元素的增删改、样式修改、插入内容
    • JS中THIS相关问题梳理
    • JS中的变量提升机制
    • 在全局:私有上下文中:带VAR和不带VAR的区别
    • 作用域和作用域链查找机制
    • JS中堆栈内存的释放问题
    • JS中的闭包机制
    • ES3和ES6定义变量的区别
    • JS中的单例和工厂设计模式
    • JS中的面向对象OOP理论基础
    • 构造函数创建自定义类
    • JS中的原型和原型链
    • Math中常用的9种方法
    • 从一道阿里经典面试题剖析函数三种角色
    • 重写内置call
    • 重写一个内置new
    • 浏览器渲染页面的主体流程
    • 减少DOM的回流和重绘
    • JS中的多种继承方式
    • JS中数据类型检测四种方式的优缺点
    • JS中的正则表达式&&全面梳理
    • 非严格模式 🆚 严格模式的区别
    • 数组方法reduce、filter、flat
    • 获取数组中最大值/最小值的三种基础方法
    • 轮播图——渐隐渐显版
    • 深克隆 VS 浅克隆|深比较 VS 浅比较|回调函数
    • 轮播图——左右切换版
    • 事件及事件绑定、事件对象及事件传播
    • 从在地址栏输入网址到看到页面的过程&&AJAX基础
    • 想自学JS吗?想提升JS底层原理吗?76张脑图带你彻底搞懂原生JS
    • 面试手写API系列
    • 30张脑图带你从零开始学VUE
    • JS中的盒子模型
    • 初识JS-基础中的基础
    • 前端发展简史
    • JS中的三大类输出方式

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

vuePress-theme-reco 金色小芝麻    2021 - 2023

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

金色小芝麻 2020-05-08

虽然现在我们在开发中已经用不到自己操作DOM了,之前有JQ,现在更是有VUE、REACT两大框架供我们使用,但是我们也有必要了解下,关于原生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;
}
欢迎来到 金色小芝麻
看板娘