1.1-DOM节点介绍
- 1.什么是节点:在HTML文档中,一切皆节点(HTML文档本身、标签、属性、注释内容、文本)
- 2.什么是元素:元素在HTML中叫做标签,在JS的dom对象中称为元素(可以理解为标签的面向对象的叫法)
- 3.HTML标签属于节点的一种,叫做元素节点
- 4.节点三要素:
- 节点类型:标签、属性、注释、文本,nodeType
- 节点名称:p、div、class(属性名),nodeName
- 节点的值:one(属性的值),nodeValue
- 在JavaScript中,document这个对象大家一定很熟悉,哪怕是刚刚开始学习的新人,也会很快接触到这个对象。而document对象不仅仅是一个普通的JavaScript内置对象,它还是一个巨大API的核心对象,这个巨大的API就是DOM(Document Object Model),它将文档的内容呈现在JS面前,并赋予了JS操作文档的能力。
- DOM树体现着HTML页面的层级结构,学习中经常提到的父元素子元素的说法也是建立在树这种数据结构的基础之上的,而DOM文档树则包含文档中所有内容。
- HTML页面中的所有内容都会体现在DOM文档树中,要理解这种结构,对构成它的每个节点就要先有了解。下面是DOM节点的基本类别,以及各自类别基本属性的值及简单介绍:
1.2-元素节点与属性节点
-
1.元素节点
- 类型 nodeTypoe:1
- 名称 nodeName:标签名大写
- 值 nodeValue : null
-
2.属性节点
- 类型 nodeTypoe:2
- 名称 nodeName:属性名
- 值 nodeValue : 属性值
-
1.文本节点
- 类型 nodeTypoe:3
- 名称 nodeName:#text
- 值 nodeValue : 文本内容
-
2.注释节点
- 类型 nodeTypoe:8
- 名称 nodeName:#comment
- 值 nodeValue : 注释内容
-
3.文档节点
- 类型 nodeTypoe:9
- 名称 nodeName:#document
- 值 nodeValue : null
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>节点 - 网页一切皆节点</title>
</head>
<body>
<ul id="ul" class="item">
<li>一名保安1</li>
<li>一名保安2</li>
<li>一名保安3</li>
<!--
1. 注释: 注释节点
2. 文字: 文本节点(包括换行,和空格)
3. 标签: 标签节点
4. 标签里面的属性: 属性节点
5. document: 顶级文档节点
-->
</ul>
</body>
<script>
// 节点:node,网页一切皆节点
// 元素节点:针对标签
/*
节点必有三要素: (如果没有三要素说明不是节点)
nodeType: 类型,数字 元素为1
nodeName: 名字,字符串 元素为大写标签
nodeValue: 值,字符串 元素为null
*/
// 文档节点:document
console.log(document.nodeType, document.nodeName, document.nodeValue);
// 重点是:元素节点
const ul = document.querySelector("ul");
console.log(ul.nodeType, ul.nodeName, ul.nodeValue); // 1 'UL' null
// 属性节点:不要用元素.属性名 去操作 元素.属性名表示拿到的是值(字符串),就不是节点
// 元素.attributes
console.log(ul.attributes); // 所有属性的伪数组(对象)
// 取出来
const c = ul.attributes[1];
console.log(c);
console.log(c.nodeType, c.nodeName, c.nodeValue); // 2 'class' 'item'
</script>
</html>
1.3-获取子节点与子元素
- childNodes:获取子节点:(文本节点,注释节点,子元素节点)
- 细节:属性节点通过attribute来获取,一般用的不多
- 浏览器兼容问题:IE8及之前不包含非空文本
- children:获取子元素:(元素节点)
- 浏览器兼容问题: IE8及之前包含注释节点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>节点 - 寻找子节点</title>
</head>
<body>
<ul id="ul" class="item">
<!-- 里面写li标签 -->
<li>我是一名保安1</li>
<li>我是一名保安2</li>
<li>我是一名保安3</li>
<!--
1. 注释: 注释节点
2. 文字: 文本节点(包括换行,和空格)
3. 标签: 标签节点
4. 标签里面的属性: 属性节点
5. document: 顶级文档节点
-->
</ul>
</body>
<script>
// 找子节点: 必须要先找到父元素
const ul = document.querySelector("#ul");
// console.log(ul);
// 节点一般没用: 元素节点才有意义
// 没用的
// 1. 找所有子节点: 元素.childNodes
console.log(ul.childNodes); // 实际没用
// 3. 第一个子节点: firstChild
console.log(ul.firstChild); // 实际没用
// 5. 最后一个子节点: lastChild
console.log(ul.lastChild); // 实际没用
// 有用的
// 2. 找所有子元素: children
console.log(ul.children);
// 4. 第一个子元素: firstElementChild
console.log(ul.firstElementChild);
// 6. 最后一个子元素: lastElementChild
console.log(ul.lastElementChild);
// 总结
// 节点的寻找: 给开发者提供一种获取元素的便捷方式而已
// 顺带: 可以节省变量
</script>
</html>
1.4-兄弟节点与兄弟元素
本小节知识点:获取兄弟节点与兄弟元素
- nextSibling:获取下一个节点 previousSibling:获取上一个节点
- IE8及之前:文本(不包含非空)、注释、元素
- 其他浏览器:文本(包含非空)、注释、元素
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>节点 - 寻找兄弟节点</title>
</head>
<body>
<ul id="ul" class="item">
<!-- 里面写li标签 -->
<li>我是一名保安1</li>
<li class="current">我是一名保安2</li>
<li>我是一名保安3</li>
<!--
1. 注释: 注释节点
2. 文字: 文本节点(包括换行,和空格)
3. 标签: 标签节点
4. 标签里面的属性: 属性节点
5. document: 顶级文档节点
-->
</ul>
</body>
<script>
// 兄弟节点:sibling 前一个 :previous 后一个:next
const li = document.querySelector(".current");
// 1. 前一个: previousSibling 前一个兄弟元素: previousElementSibliing
console.log(li.previousSibling);
console.log(li.nextSibling);
// 2. 后一个: nextSibling 后一个兄弟元素: nextElementSibling
// 有意义的一定是元素
console.log(li.previousElementSibling);
console.log(li.nextElementSibling);
// 总结:方便找元素
</script>
</html>
1.8-获取父节点
parentNode:获取元素的父元素节点
- 细节:一个元素的父节点一定是一个元素,而不是(文本、注释、属性),只有元素才有子节点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>节点 - 寻找父节点</title>
</head>
<body>
<div class="box">我是一名保安</div>
</body>
<script>
// 父节点:parentNode 父元素:parentElement
const box = document.querySelector(".box");
// 访问
console.log(box.parentNode, box.parentElement);
// 区别:普通应用没有区别,区别在于顶级不一样
// parentNode 顶级是 document
// parentElement 顶级是 html(document.documentElement === html)
console.log(box.parentElement.parentElement.parentElement); // null
console.log(box.parentElement.parentElement); // html
// 总结
// 所有的节点(元素)查找:都是为了给开发者带来便捷
</script>
</html>
02 - dom增删改页面元素
语法 | 示例 | 描述 |
---|---|---|
document.createElement() | document.createElement(‘li’) | 创建空标签元素 |
父元素.appendChild(子元素) | ul.appendChild(li) | 添加子元素 |
父元素.insertBefore(子元素) | ul.insertBefore(元素A,元素B) | 将元素A插入到元素B的前面 |
父元素.replaceChild(子元素) | ul.replaceChild(元素A,元素B) | 元素A替换元素B |
父元素.removeChild(子元素) | ul.removeChild(li) | 移除子元素 |
1.1-创建元素三种方式介绍
- 1.document.write():慎用,可能会覆盖原本内容
- 解析字符串识别标签
- 2.innerHTML:创建元素过多时(100以内可以忽略),会损耗性能
- 解析字符串识别标签
- 直接赋值 元素.innerHTML 会替换原本内容,如果不想替换使用 += 拼接
- 3.document.createElement():dom推荐方式
- 动态创建一个dom对象(空标签,需要自己设置属性)在内存中
- 需要使用appendChild来添加到HTML
- document.write():慎用,因为可能会覆盖原本的内容
- 覆盖内容的原理了解即可:编译器从上往下解析HTML的时候会形成一个文档流,这个文档流会在文档所有的HTML标签解析后关闭。不会覆盖的情况:如果在关闭这个文档流之前调用document.write(),则不会覆盖会覆盖的情况:如果在关闭文档流之后调用document.write(),会开启一个新的文档流,此时会把上一个文档流中的内容覆盖
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>节点操作 - 创建元素</title>
</head>
<body></body>
<script>
// 创建元素:document.createElement('标签名')
// 创建元素的特点
// 1.只在内存有限(用户看不到)
// 2.可以进行元素的任何操作(类/样式/属性/事件)
const div = document.createElement("div");
console.log(div); // 只有内存有这个元素
// 是一个元素,可以做任何操作
div.id = "newElement"; // 属性操作
div.classList.add("current"); // 类操作
div.innerText = "我是一名保安"; // 文本操作
div.style.backgroundColor = "gold"; // 样式操作
div.onclick = function () {
alert("hello world");
};
// 所有操作都可以:但是只能在内存有效
// 想加入页面:需要结合其他DOM操作
// 父元素.appendChild(子元素)
document.body.appendChild(div);
</script>
</html>
1.2-添加子元素:appendChild()
- appendChild()添加元素有三种情况
- (1)如果是一个新的子元素,则默认会添加到最后
- (2)如果是一个已存在的子元素,相当于移动到最后面
- (3)如果添加的元素有子元素,子元素也会一起移动到最后面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>节点操作 - 追加子元素</title>
</head>
<body>
<ul class="item1">
<li>业主小丹1</li>
<li>业主小丹2</li>
<li>业主小丹3</li>
</ul>
<ul class="item2">
<li>物业老三1</li>
<li>物业老三2</li>
<li class="current">物业老三3</li>
</ul>
</body>
<script>
// 追加子元素:父元素.appendChild(子元素)
// 1.获取子元素
const ul1 = document.querySelector(".item1");
const ul2 = document.querySelector(".item2");
const li = document.querySelector(".current");
// appendChild(子元素): 子元素有很多由来(来源不同)
// 新元素: 创建的, document.CreateElement()
// 旧元素: 原来就有, document.querySelector() 查到的
// 2.新元素:document.createElement()
const newLi = document.createElement("li");
newLi.innerText = "隔壁新保安";
ul1.appendChild(newLi);
// 3.旧元素:特点:移动(原来的位置移动到别的父元素里面当最后一个孩子)
ul1.appendChild(li);
// 旧元素有自己的子元素
ul1.appendChild(ul2);
// 总结:
// 实际开发中:一般都是新增
</script>
</html>
1.3-插入子元素:inertBefore()
insertBefore:插入子元素到指定位置
- 语法:
父元素.insertBefore(要插入的标签,插入到哪一个标签前面)
- 特点:与appendChildNode一致
- (1)如果是新元素则插入到指定位置
- (2)如果是已存在元素则移动到指定位置
- (3)如果元素有子元素,则子元素随着它一起移动
- 如果想插入到某元素后面,没有直接的api,可以先获取该元素的下一个元素,然后插入到下一个元素前面即可
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>节点操作 - 插入子元素</title>
</head>
<body>
<ul class="item1">
<li>业主小丹1</li>
<li>业主小丹2</li>
<li>业主小丹3</li>
</ul>
<ul class="item2">
<li>物业老三1</li>
<li>物业老三2</li>
<li class="current">物业老三3</li>
</ul>
</body>
<script>
// 追加子元素:父元素.appendChild(子元素)
// 1.获取子元素
const ul1 = document.querySelector(".item1");
const ul2 = document.querySelector(".item2");
const li = document.querySelector(".current");
// insertBefore的效果 与 appendChild 一样:新元素/旧元素/旧元素带孩子
// 只是位置有区别
const newLi = document.createElement("li");
newLi.innerText = "我是新的";
// ul2.insertBefore(newLi, li);
// ul2.insertBefore(newLi, li.previousElementSibling);
ul2.insertBefore(newLi, li.parentElement.firstElementChild);
// 总结
// insertBefore解决插队问题
</script>
</html>
1.4-替换子元素:replaceChild()
- 替换子元素:replaceChild() 语法:
父元素.replaceChile(新元素,旧元素)
- 特点:
- 1.如果是新创建的元素,则直接替换
- 2.如果是已存在的元素(不论这个元素是自己的子元素还是别人的)会将新元素移动到旧元素位置,并且旧元素被移除
- 3.如果已存在的元素有子元素,则子元素会随着父元素一起替换
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>节点操作 - 替换子元素</title>
</head>
<body>
<ul class="item1">
<li>业主小丹1</li>
<li>业主小丹2</li>
<li>业主小丹3</li>
</ul>
<ul class="item2">
<li>物业老三1</li>
<li>物业老三2</li>
<li class="current">物业老三3</li>
</ul>
</body>
<script>
// 替换子元素: 父元素.replaceChild(新元素,旧元素)
// 1.获取子元素
const ul1 = document.querySelector(".item1");
const ul2 = document.querySelector(".item2");
const li = document.querySelector(".current");
// replaceChild的效果 与 appendChild一样: 新元素\旧元素\旧元素带孩子
// 只是覆盖已有元素
// 需求: 要求覆盖第一个元素
const newLi = document.createElement("li");
newLi.innerText = "我是新的";
ul2.replaceChild(newLi, ul2.firstElementChild);
</script>
</html>
1.5-删除元素:remove()
removeChild:移除子元素 语法:
父元素.removeChild(子元素)
- 1.不能自己移除自己(只能让爸爸干掉自己)
- 2.父元素只能移除自己的子元素,不能移除别人的子元素(只有亲爸爸才能干掉自己)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>节点操作 - 删除元素</title>
</head>
<body>
<ul class="item1">
<li>业主小丹1</li>
<li>业主小丹2</li>
<li>业主小丹3</li>
</ul>
<ul class="item2">
<li>物业老三1</li>
<li>物业老三2</li>
<li class="current">物业老三3</li>
</ul>
</body>
<script>
// 1.获取元素
const ul1 = document.querySelector(".item1");
const ul2 = document.querySelector(".item2");
const li = document.querySelector(".current");
// 父元素.removeChild(子元素)
ul2.removeChild(li);
// 子元素.remove() 删除自己
ul1.remove();
// 总结
// 删除元素会用到:元素.remove()效果要好一点(性能高一点)
</script>
</html>
1.6-克隆元素:cloneNode()
cloneNode:克隆元素 语法:
元素.cloneNode(布尔)
false:默认,浅克隆
true:深克隆
- 1.克隆目标元素
- 2.可能分为两种
- 浅克隆:只克隆元素本身,不包含子节点(文本、元素)
- 深克隆:克隆元素本身以及其子节点(文本、元素)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<ul class="item1">
<li>隔壁百里1</li>
<li>隔壁百里2</li>
<li>隔壁百里3</li>
</ul>
<ul class="item2">
<li>隔壁鲁班1</li>
<li>隔壁鲁班2</li>
<li class="current">隔壁鲁班3</li>
</ul>
<script>
// 1. 获取元素
const ul1 = document.querySelector(".item1");
const li = document.querySelector(".current");
// 需求: 希望将 鲁班3 复制一份, 放到ul.item1 中做最后一个孩子(appendChild)
// ul1.appendChild(li) // 移动效果(非复制)
// 先克隆: 元素.cloneNode() 得到一个新的元素
// const newLi = li.cloneNode() // 默认浅克隆: 只有当前元素自己的结构
// 深克隆: 元素.cloneNode(true)
const newLi = li.cloneNode(true);
ul1.appendChild(newLi);
// 总结
// 克隆的应用: 涉及复杂结构(被克隆元素有很多效果,还有很多子元素),采用克隆
</script>
</body>
</html>