DOM(三):节点操作——获取父子兄节点(查)、添加和删除元素节点

article/2025/10/26 21:17:38

在这里插入图片描述

一、节点之间的层级:父子兄

节点主要 有父子兄关系

1.父节点操作

语法:子节点.parentNode,得到的是一个元素不是集合
比如我选了一个类名叫zzy的元素

var zzy = document.querySelector('.zzy');

那么要获取zzy 的父节点,只需要zzy.parentNode

console.log(zzy.parentNode);

注意,得到的时离该元素最近的父节点(亲爹),如果找不到父节点,就返回null

2.子节点操作

(1)父节点.childNodes(目测用的不多)

这个得到的是所有的子节点,除了我们想要的元素节点,还有换行、空格等文本节点,所以要想拿到元素,就要循环遍历,因为元素节点nodeType是1,属性2,文本3。这个真的是麻烦的一塌糊涂
在这里插入图片描述

(2)父节点.children(这个才是常用的)

这个只返回子元素节点,其他的都滚蛋,不错

3.获取第一个子元素和最后一个子元素

父节点.firstChild和父节点,lastChild,和父节点.childNodes差不多,返回的是所有类型节点中的第一个和最后一个,所以这两个用的不多,真正带劲的是:
父节点.firstElementChild和父节点.lastElementChild,这俩都是返回的第一个和最后一个元素节点,不错
但是!这个不错的方法,只有IE9以上支持。

这可咋办!

不要怕,在实际开发中,我们都会用父元素.children[i],既没有兼容问题,又能返回首尾元素节点
比如这里有这么几个东西

<ul><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li>
</ul>

那么首尾元素分别是:

var ul = document.querySelector('ul');
console.log(ul.children[0]);
console.log(ul.children[ul.children.length - 1]);

案例:下拉菜单

下拉菜单的常用布局:头部放个ul,ul里有几个li,每个li里面上边a,下边放ul包几个li
先放html和css

* {margin: 0;padding: 0;box-sizing: border-box;
}li {list-style: none;
}a {color: black;text-decoration: none;
}.box {margin: 100px auto;width: 400px;height: 50px;
}.box>li {float: left;/* position: relative; */width: 100px;height: 50px;line-height: 50px;text-align: center;
}.box>li a {display: inline-block;width: 100px;height: 50px;
}.box>li a:hover {background-color: #ccc;
}.box ul {display: none;/* position: absolute; */left: 0;top: 50px;border-left: 1px solid red;border-right: 1px solid red;
}.box ul li {border-bottom: 1px solid red;
}.box li ul li:hover {background-color: rgb(247, 149, 149);
}
   <ul class="box"><li><a href="#">微博</a><ul><li>私信</li><li>评论</li><li>@我</li></ul></li><li><a href="#">微博</a><ul><li>私信</li><li>评论</li><li>@我</li></ul></li><li><a href="#">微博</a><ul><li>私信</li><li>评论</li><li>@我</li></ul></li><li><a href="#">微博</a><ul><li>私信</li><li>评论</li><li>@我</li></ul></li></ul>

然后是JavaScript,其实这部分代码比较好理解,就是我第一步获取元素老写错

   var box = document.querySelector('.box'); //这个地方老写错……var lis = box.children;  //得到4个lifor (var i = 0; i < lis.length; i++) {lis[i].onmouseover = function () {//鼠标放上去,这个li的第二个孩子(ul)显示this.children[1].style.display = 'block';}lis[i].onmouseout = function () {this.children[1].style.display = 'none';}}

4.获取兄弟节点

和父子一样,有个获取下一个(全部中的下一个)节点和上一个节点的方法,没什么p用
在这里插入图片描述
真正有用的是下面这个,但是又有兼容性问题
在这里插入图片描述
那咋办呢?实际上兄弟节点用的少,了解下就行了
在这里插入图片描述

二、节点的增删

1.创建和添加元素节点

先创建,再添加
比如我要创建一个li的元素节点

var myli = document.createElement('li');

(1)父元素.appendChild(要添加的元素)

先获取它的父元素,然后把我创建的li添加进去,默认是添加到父元素的尾部

var ul = document.querySelector('ul');
//把我创建的li放到ul里面去,默认添加到尾部
ul.appendChild(myli);

(2)父元素.insertBefore(要添加的元素节点,添加到谁前面)

下面这个代码就是在ul的第一个孩子前添加我创建的li

ul.insertBefore(myli, ul.children[0]);

(3)简单添加留言案例

<textarea name="" id="content" cols="30" rows="10"></textarea> <button>发布</button>
<ul class="my"><li></li>
</ul>

注意获取textarea和input里面的值是.value

//简单留言案例var content = document.querySelector('textarea');//获取文本域var my = document.querySelector('.my');  //获取ulvar btn = document.querySelector('button');  //获取button//点击按钮就生成一个li,添加到ul里btn.onclick = function () {if (content.value == '') {alert('您没有输入任何内容');} else {var li = document.createElement('li');li.innerHTML = content.value;// my.appendChild(li);my.insertBefore(li, my.children[0]);}}

2.删除元素节点

(1)使用父元素.removeChild(子元素)

<button>删除</button>
<ul><li>zzy</li><li>aoaoao</li><li>3213</li>
</ul>
	var ul = document.querySelector('ul');var btn = document.querySelector('button');btn.onclick = function () {if (ul.children.length != 0) {ul.removeChild(ul.children[0]);} else {//如果删完了就禁用按钮this.disabled = true;}}

(2)添加留言和删除留言(上面案例的升级版)

这里遇到个问题就是删除留言的代码要放到btn.onclick里面,要不然会先执行下面这段(注意代码的执行顺序),等点击btn的时候才添加a标签,那样先获取的as就是空了

//简单添加删除留言案例
var content = document.querySelector('textarea');//获取文本域
var my = document.querySelector('.my');  //获取ul
var btn = document.querySelector('button');  //获取button
//1.添加留言:点击按钮就生成一个li,添加到ul里
btn.onclick = function () {if (content.value == '') {alert('您没有输入任何内容');} else {var li = document.createElement('li');//把textarea里面的内容取过来,然后再添加一个a标签li.innerHTML = content.value + "<a href='javascript:;'>删除</a>";//卧槽,还能这么写// my.appendChild(li);my.insertBefore(li, my.children[0]);}//2.删除留言//先获取a标签//这段代码要放到btn.onclick里面,要不然会先执行下面这段,等点击btn的时候才添加a标签,那样as就是空了var as = document.querySelectorAll('a');for (var i = 0; i < as.length; i++) {as[i].onclick = function () {my.removeChild(this.parentNode);}}
}

3.复制元素节点

(1)语法:node.cloneNode()

<ul><li>1</li><li>2</li><li>3</li>
</ul>

把ul里的第一个孩子复制过来,放到ul的尾部

	var ul = document.querySelector('ul');var li1 = ul.children[0].cloneNode();ul.appendChild(li1);

(2)浅拷贝和深拷贝

node.cloneNode()括号里默认是false,也就是浅拷贝,只copy元素不copy内容
node.cloneNode(true),如果括号里是true就是深拷贝,copy元素和内容

三、动态生成表格

创建html和css

table {width: 400px;margin: 100px auto;text-align: center;border-collapse: collapse;
}th,
td {border: 1px solid #333;
}thead tr {height: 40px;background-color: #ccc;
}tbody tr {height: 30px;
}
<table cellspacing="0"><thead><tr><th>姓名</th><th>科目</th><th>成绩</th><th>操作</th></tr></thead><tbody></tbody>

1.先准备好学生的数据,以对象形式存储在数组中

var datas = [{names: '彭于晏',subject: 'javascript',score: 87},{names: '小婷',subject: 'javascript',score: 100}, {names: '张大仙',subject: 'javascript',score: 99}, {names: '刘亦菲',subject: 'javascript',score: 60}
]

2.创建行tr

var tbody = document.querySelector('tbody');
for (var i = 0; i < datas.length; i++) {//先创建,再添加,二者要绑定在一起var tr = document.createElement('tr');tbody.appendChild(tr);
}

3.创建行里面的单元格td

var tbody = document.querySelector('tbody');
for (var i = 0; i < datas.length; i++) {//先创建,再添加,二者要绑定在一起var tr = document.createElement('tr');tbody.appendChild(tr);//3.行里面创建单元格tdfor (var k in datas[i]) {  //遍历对象,k是属性的个数,有几个属性就循环几次var td = document.createElement('td');tr.appendChild(td);
}

4.添加td里面的数据

每个单元格的数据可以用对象里的datas[i][k]来获取
我的写法:
我一开始想获取所有的td元素数组,然后设置一个flag来获取相应的td,但是我发现这样的话因为每次循环td个数都在增加,所以td的数组也在变化,所以intd[flag]并不能添加每一行的数据,每次添加都是添加到第一行,除非flag=3*i。后来想了个办法,可以使用tr.children[flag],这样就可以实现给每行的每个单元格添加相应的数据

var tbody = document.querySelector('tbody');
for (var i = 0; i < datas.length; i++) {//先创建,再添加,二者要绑定在一起var tr = document.createElement('tr');tbody.appendChild(tr);//3.行里面创建单元格tdvar flag = 0;for (var k in datas[i]) {  //遍历对象,k是属性的个数,有几个属性就循环几次var td = document.createElement('td');tr.appendChild(td);// var intd = document.getElementsByTagName('td'); //这是获取所有的td,包括前几行,不对// intd[flag].innerHTML = datas[i][k];tr.children[flag].innerHTML = datas[i][k];flag++;}
}

看了老师的写法,我才知道我想多了……
其实只需要每次添加完td后,直接往td塞数据,然后再添加到tr里就行

var tbody = document.querySelector('tbody');
for (var i = 0; i < datas.length; i++) {//先创建,再添加,二者要绑定在一起var tr = document.createElement('tr');tbody.appendChild(tr);//3.行里面创建单元格tdfor (var k in datas[i]) {  //遍历对象,k是属性的个数,有几个属性就循环几次var td = document.createElement('td');//给每个单元格塞数据td.innerHTML = datas[i][k];tr.appendChild(td);}
}

5.添加删除操作的链接

var tbody = document.querySelector('tbody');
for (var i = 0; i < datas.length; i++) {//先创建,再添加,二者要绑定在一起var tr = document.createElement('tr');tbody.appendChild(tr);//3.行里面创建单元格tdfor (var k in datas[i]) {  //遍历对象,k是属性的个数,有几个属性就循环几次var td = document.createElement('td');//4.给每个单元格先塞数据,再放到tr里td.innerHTML = datas[i][k];tr.appendChild(td);}//5.添加删除操作的链接var tdend = document.createElement('td');tdend.innerHTML = "<a href='javascript:;'>删除</a>";tr.appendChild(tdend);
}

6.最后一步,给删除操作添加删除事件

//2.先创建行tr,有几个人就创建几行
var tbody = document.querySelector('tbody');
for (var i = 0; i < datas.length; i++) {//先创建,再添加,二者要绑定在一起var tr = document.createElement('tr');tbody.appendChild(tr);//3.行里面创建单元格tdfor (var k in datas[i]) {  //遍历对象,k是属性的个数,有几个属性就循环几次var td = document.createElement('td');//4.给每个单元格先塞数据,再放到tr里td.innerHTML = datas[i][k];tr.appendChild(td);}//5.添加删除操作的链接var tdend = document.createElement('td');tdend.innerHTML = "<a href='javascript:;'>删除</a>";tr.appendChild(tdend);
}//6.给删除按钮添加事件
var as = document.querySelectorAll('a'); //这里一定要是All
for (var i = 0; i < as.length; i++) {as[i].onclick = function () {tbody.removeChild(this.parentNode.parentNode);}
}

四、innerHTML和createElement创建元素谁效率更高?

在这里插入图片描述
如果innerHTML是拼接字符串标签的话,拼1000个要用3000ms,但是如果采用数组形式拼接,只用7ms
如果用createElement创建1000个同样的元素,大概18ms


http://chatgpt.dhexx.cn/article/3YFlvhIO.shtml

相关文章

节点操作 ------------- 父节点

在获取元素时我们可以利用DOM提供的一系列方法获取&#xff0c;但是这些方法过于繁琐&#xff0c;不简练。所以我们学习节点操作&#xff0c;页面中所有内容都是节点&#xff0c;有文档节点&#xff0c;元素节点&#xff0c;属性节点等&#xff0c;我们主要针对研究的是元素节点…

dom获取节点(子节点、兄弟节点、父节点)

今天在做一个项目拿兄弟节点的事&#xff0c;刚开始拿不到&#xff0c;后来网上查了一下&#xff0c;于是 便找到方法了&#xff0c;下面把我的问题写出来&#xff0c;话不多说直接上问题&#xff0c; 遇到的问题是我要通过点击删除按钮删除这一行数据&#xff0c;后端给的接口…

# 如何获取父节点和子节点

文章目录 一、获取父级节点二、获取子节点1、获取子节点2、获取指定子节点 三、总结 一、获取父级节点 node.parentNode 代码如下&#xff08;示例&#xff09;&#xff1a; <!DOCTYPE html> <head>父节点操作</head> <body><div class"box&q…

JS节点操作(1) - 父节点,子节点,兄弟节点

节点操作的作用 获取元素通常使用的两种方式&#xff1a; 1. 利用DOM提供的方法获取元素 document.getElementById()document.getElementsByTagName()document.querySelector() 等等逻辑性不强&#xff0c;繁琐 2. 利用节点层级关系获取元素 利用父子兄弟节点关系获取元素…

树中的重要概念

1 基本术语及定义 1.1 根节点 根节点&#xff1a;是树中唯一没有入边的节点。 1.2 父节点 父节点&#xff1a;一个节点是其所有子节点的父节点 1.3 子节点 子节点&#xff1a;一个节点通过出边与子节点相连 1.4 兄弟节点 兄弟节点&#xff1a;具有同一个父节点的节点称…

VScode 代码注释

MAC&#xff1a; 单行注释/取消注释&#xff1a; command/ 多行注释/取消注释&#xff1a; 1.选中要注释代码块command/ 2.optionshifta 3.JsDOc注释&#xff1a;/tab** 如下图所示 常用于给方法写注释&#xff0c;写在方法上时会自动带上此方法的参数&#xff0c;而且会车自…

说说代码中的注释

*what&#xff1a; 注释&#xff0c;也是解释&#xff0c;标记。代码中的注释不会被执行&#xff01; *why&#xff1a; 方便提醒自己&#xff0c;这代码代表的是什么功能&#xff1f;当代码量很大的时候&#xff0c;非常有用。 当然&#xff0c;平时写代码就得规范&#x…

3、代码注释与编码规范

目录 一、代码注释 &#xff08;1&#xff09;单行注释 &#xff08;2&#xff09;多行注释 &#xff08;3&#xff09;文档注释 2. 编码规范 一、代码注释 &#xff08;1&#xff09;单行注释 “//”为单行注释标记&#xff0c;从符号“//”开始直到换行为止的所有内容…

关于如何优雅的做好代码注释

问题思考 作为研发同学&#xff0c;对于代码“注释”其实并不陌生。它往往作为我们代码文档的特殊补充而存在。 其实在代码文档中&#xff0c;起主要作用的因素并非注释&#xff0c;而是好的编程风格。 编程风格包括&#xff1a;良好的程序结构、易于理解的方法、有意义的变量…

VS Code - 自动生成代码注释

目录 1. 代码注释 2. 插件安装 3. 使用示例 1. 代码注释 代码注释在软件的迭代过程中举足轻重&#xff0c;所以一个规范化的代码注释也非常重要&#xff0c;在用 VS Code 中则可以使用插件来规范化代码注释。 autoDocstring: VSCode Python Docstring Generator GitHub - N…

python中如何注释代码

1、python中通过#来注释单行不需要运行的代码&#xff0c;如&#xff1a; 此时&#xff0c;被注释代码变灰色了&#xff0c;那么在执行程序时&#xff0c;该行代码就不会被运行了 2、注释多行代码用xxxxx或者"""xxxx"""来注释&#xff0c;作用同…

python 代码注释

文章目录 写在前面使用方法plainEpytextGoogleNumpyreStructuredText相关程序包其他 写在前面 如果说高效率的算法是一个项目的内核&#xff0c;那么完备的文档注释、API 接口则是项目的外壳&#xff0c;直接与客户交互。 pycharm 提供了 5 种 代码注释格式。 分别是 plain, e…

谈代码注释

只要写代码&#xff0c;就会遇到代码注释的问题。在不同的公司&#xff0c;不同的项目组&#xff0c;不同的项目中&#xff0c;可能会有不同的注释标准。有些标准让我们感觉很受益&#xff0c;有些则让我们感觉很反感。而对于没有明确标准的项目&#xff0c;我们往往会遇到“百…

教你写好代码注释

前言 相信大家都会遇到这种情况&#xff1a;一周前自己写的代码&#xff0c;现在再拿出来看&#xff0c;发现读不懂了&#xff0c;“ 这代码是我写的&#xff1f;&#xff1f;&#xff1f;”。这时候&#xff0c;代码注释就可以发挥它的作用了——提高晦涩难懂的代码的可读性&…

关于代码的注释的几种方法

注释就是对代码的解释和说明&#xff0c;其目的是让人们能够更加轻松地了解代码。注释是编写程序时&#xff0c;写程序的人给一个语句、程序段、函数等的解释或提示&#xff0c;能提高程序代码的可读性。注释只是为了提高可读性&#xff0c;不会被计算机编译。 注释一般分为行注…

C++设计模式之观察者模式和发布订阅模式

在软件工程中&#xff0c;设计模式&#xff08;Design Pattern&#xff09;是对软件设计普遍存在&#xff08;反复出现&#xff09;的各种问题&#xff0c;锁提出的解决防范。根据模式的目的来划分的话&#xff0c;GoF&#xff08;Gang of Four&#xff09; 设计模式可以分为以…

Redis发布订阅模式实现原理

前言 发布订阅系统在我们日常的工作中经常会使用到&#xff0c;这种场景大部分情况我们都是使用消息队列&#xff0c;常用的消息队列有 Kafka&#xff0c;RocketMQ&#xff0c;RabbitMQ&#xff0c;每一种消息队列都有其特性&#xff0c;很多时候我们可能不需要独立部署相应的消…

RabbitMQ入门案例之发布订阅模式

前言 本文章主要介绍RabbitMQ的发布订阅模式&#xff0c;该模式下&#xff0c;消息为广播形式&#xff0c;一经发布则会进入交换机绑定的队列中&#xff0c;详细介绍可以阅读官方文档。 官网文档地址&#xff1a;https://rabbitmq.com/getstarted.html 什么是发布与订阅模式 …

浅谈JS发布订阅模式

&#x1f3c6;分享博主自用牛客网&#x1f3c6;&#xff1a;一个非常全面的面试刷题求职网站&#xff0c;真的超级好用&#x1f36c; 文章目录 前言一、发布订阅模式是什么&#xff1f;二、使用步骤1.创建调度中心2.实际操作3. React中的应用 总结 前言 在使用前端各大框架时&…

React 中的发布订阅模式

1、react 通信 react的数据流是单向的, react 通信有以下几种方式&#xff1a; 单向数据流&#xff1a;指当前组件的 state 以 props 的形式流动时只能流向组件树中比自己层级更低的组件 父向子通信&#xff1a;父组件提供state&#xff0c;并且内部设置好数据&#xff0c;子组…