在HTML DOM中,所有事物都是节点,DOM是被视为节点树的HTML。
节点
根据W3C的HTML DOM标准,HTML文档中的所有内容都是节点。
- 整个文档是一个文档节点
- 每个HTML元素是元素节点
- HTML元素内的文本是文本节点
- 每个HTML属性是属性节点
- 注释是注释节点
节点属性
- 使用
nodeType
获取节点类型,属性值为数字- 1 表示元素节点
- 2 表示属性节点
- 3 表示文本节点
- 8 表示注释节点
- 9 表示文档节点
获取属性节点,要通过元素.attributes
来获取到集合,再通过下标获取想要的属性节点。
var div = document.createElement("div");
div.id = "box";
var text = document.createTextNode("hello");
var comment = document.createComment("我是一个注释");
console.log(div.nodeType); // 1 元素节点
console.log(div.attributes[0].nodeType); // 2 属性节点
console.log(text.nodeType); // 3 文本节点
console.log(comment.nodeType); // 8 注释节点
console.log(document.nodeType); // 9 文档节点
- 使用
nodeName
获取节点名称,属性值为字符串- 元素节点的名称为
大写的标签名
- 属性节点的名称为
属性名
- 文本节点的名称为
#text
- 注释节点的名称为
#comment
- 文档节点的名称为
#document
- 元素节点的名称为
console.log(div.nodeName); // DIV
console.log(div.attributes[0].nodeName); // id
console.log(text.nodeName); // #text
console.log(comment.nodeName); // #comment
console.log(document.nodeName); // #document
- 使用
nodeValue
获取节点值- 元素节点没有节点值
null
- 属性节点的节点值就是
属性值
- 文本节点的节点值就是
文本内容
- 注释节点的节点值就是
注释内容
- 文档节点没有节点值
null
- 元素节点没有节点值
console.log(div.nodeValue); // null
console.log(div.attributes[0].nodeValue); // box
console.log(text.nodeValue); // hello
console.log(comment.nodeValue); // 我是一个注释
console.log(document.nodeValue); // null
汇总
- | nodeType | nodeName | nodeValue |
---|---|---|---|
元素节点 | 1 | 大写标签名 | null |
属性节点 | 2 | 属性名 | 属性值 |
文本节点 | 3 | #text | 文本内容 |
注释节点 | 8 | #comment | 注释内容 |
文档节点 | 9 | #document | null |
节点的关系
节点之间有两种关系:父子关系、兄弟(同胞)关系。
- 在节点树中,顶端节点被称为
根
(root) - 每个节点都有父节点、除了根(根没有父节点)
- 一个节点可以拥有任意数量的子
- 兄弟(同胞)是拥有相同父节点的节点
下面图片展示节点树的一部分,以及节点之间的关系:
父子关系
- 父找子
childNodes
——获取某一个节点下所有的子一级节点children
——获取某一节点下所有的子一级元素节点firstChild
——获取某一节点下子一级的第一个节点firstElementChild
——获取某一节点下子一级第一个元素节点lastChild
——获取某一节点下子一级的最后一个节点lastElementChild
——获取某一节点下子一级最后一个元素节点
- 子找父
parentNode
——获取某一个节点的父节点
兄弟(同胞)关系
nextSibling
——获取某一个节点的下一个兄弟节点nextElementSibling
——获取某一个节点的下一个元素节点previousSibling
——获取某一个节点的上一个兄弟节点previousElementSibling
——获取某一个节点的上一个元素节点
<html>
<head>
<title>标题</title>
</head>
<body>
<h1>一级标题</h1>
<p>Hello world!</p>
</body>
</html>
上述代码中:
<html>
节点没有父节点;它是根节点<head>
和<body>
的父节点是<html>
节点- 文本节点
"Hello world!"
的父节点是<p>
节点
并且:
<html>
节点拥有两个子节点:<head>
和<body>
<head>
节点拥有一个子节点:<title>
节点<title>
节点也拥有一个子节点:文本节点"标题"
<h1>
和<p>
节点是兄弟(同胞)节点,同时也是<body>
的子节点
并且:
<head>
元素是<html>
元素的首个子节点<body>
元素是<html>
元素的最后一个子节点<h1>
元素是<body>
元素的首个子节点<p>
元素是<body>
元素的最后一个子节点
示例:
<div id="box1">
<p id="p1">box1段落1</p>
<p id="p2">box1段落2</p>
</div>
<script>
var box1 = document.getElementById("box1");
var p1 = document.getElementById("p1");
var p2 = document.getElementById("p2");
console.log(box1.childNodes); // NodeList(5) [text, p#p1, text, p#p2, text]
console.log(box1.children); // HTMLCollection(2) [p#p1, p#p2, p1: p#p1, p2: p#p2]
console.log(box1.firstChild); // #text
console.log(box1.firstElementChild); // <p id="p1">box1段落1</p>
console.log(box1.lastChild); // #text
console.log(box1.lastElementChild); // <p id="p2">box1段落2</p>
console.log(p1.parentNode); // <div id="box1">...</div>
console.log(p1.nextSibling); // #text
console.log(p1.nextElementSibling); // <p id="p2">box1段落2</p>
console.log(p2.previousSibling); // #text
console.log(p2.previousElementSibling); // <p id="p1">box1段落1</p>
console.log(box1.attributes); // NamedNodeMap {0: id, 1: class, id: id, class: class, length: 2}
</script>
节点操作
创建节点
- 创建元素节点
var div = document.createElement("div");
- 创建文本节点
var textNode = document.createTextNode("hello");
- 创建注释节点
var comment = document.createComment("这是一条注释");
- 创建文档碎片
var fragment = document.createDocumentFragment();
追加节点
父元素.appendChild(子元素)
子元素会被追加到父元素的最后,作为lastChild节点
<div id="box">
<p id="child1">段落1</p>
<p id="child2">段落2</p>
<p id="child3">段落3</p>
<p id="child4">段落4</p>
</div>
<script>
var box = document.getElementById("box");
var child1 = document.getElementById("child1");
var child2 = document.getElementById("child2");
var child3 = document.getElementById("child3");
var child4 = document.getElementById("child4");
</script>
var demo1 = document.createElement("p");
demo1.innerHTML = "这是追加进来的节点";
box.appendChild(demo1);
插入节点
父元素.insertBefore(newChild, oldChild)
newChild是新元素
oldChild是父元素的已有元素
newChild会插入到oldChild的前一个位置
var demo2 = document.createElement("p");
demo2.innerHTML = "这是插入进来的节点";
box.insertBefore(demo2, child3);
替换节点
父元素.replaceChild(newChild, oldChild)
newChild是替换上的元素
oldChild是被替换的元素
var demo3 = document.createElement("p");
demo3.innerHTML = "这是替换进来的节点";
box.replaceChild(demo3, child2);
克隆节点
元素.cloneNode(boolean)
boolean是一个布尔值 ,决定是否克隆子元素。如果为真则克隆子元素,否则不克隆。默认是false
var cloneNode1 = child1.cloneNode();
console.log(cloneNode1);
var cloneNode2 = child1.cloneNode(true);
console.log(cloneNode2);
删除节点
父元素.removeChild(子元素) 让父元素中的子元素下树
box.removeChild(child4);
元素.remove() 让调用remove方法的元素下树
box.remove();
根据数据,自动生成表格
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<table>
<thead>
<tr>
<th>菜品</th>
<th>菜名</th>
<th>价格</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
var arr = [
{
type_id: 1,
name: "大菜",
food:[
{
food_id: 1,
name: "鱼香肉丝",
price: 10
},
{
food_id: 2,
name: "红烧肉",
price: 10
},
{
food_id: 3,
name: "香辣粉",
price: 10
}
]
},
{
type_id: 2,
name: "中菜",
food: [
{
food_id: 4,
name: "小炒肉",
price: 13
},
{
food_id: 5,
name: "云吞",
price: 14
}
]
},
{
type_id: 3,
name: "小菜",
food: [
{
food_id: 6,
name: "雪糕",
price: 3
},
{
food_id: 7,
name: "可口可乐",
price: 3
}
]
}
]
// 获取元素
var tbody = document.querySelector("tbody");
// 创建文档碎片
var fragment = document.createDocumentFragment();
// 要根据数组中的数据,渲染表格
// console.log(arr.length);
for (var i = 0; i < arr.length; i++){
// console.log(arr[i]);
// console.log(arr[i].food.length);
for (var j = 0; j < arr[i].food.length; j++){
// 创建tr和td
var tr = document.createElement("tr");
var td1 = document.createElement("td");
var td2 = document.createElement("td");
var td3 = document.createElement("td");
// 将内容渲染到td中
td1.innerText = arr[i].name;
td2.innerText = arr[i].food[j].name;
td3.innerText = arr[i].food[j].price;
// 将td追加到tr中
tr.appendChild(td1);
tr.appendChild(td2);
tr.appendChild(td3);
// 将创建出来的tr放入文档碎片中存储
fragment.appendChild(tr);
}
}
// 等循环结束后,一起上树
tbody.appendChild(fragment);
</script>
</body>
</html>
制作一个随机点名系统
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
background: #444;
}
h1,h2{
text-align: center;
margin: 50px 0;
}
.nameBox{
width: 1000px;
height: auto;
padding: 10px;
border: 2px solid #ccc;
margin: 0 auto;
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
}
.btn{
position: absolute;
width: 100px;
height: 50px;
margin: 30px 0;
text-align:center;
left: 50%;
transform: translate(-50%);
background-color: green;
color: #fff;
font-size: 20px;
border: none;
outline: none;
cursor: pointer;
}
.name{
display: inline-block;
justify-content: space-between;
width: 80px;
height: 30px;
background-color: yellow;
text-align: center;
line-height: 30px;
margin: 10px;
}
.clickName{
color: red;
}
</style>
</head>
<body>
<h1>随机点名系统</h1>
<h2>恭喜选中:<span class="clickName" id="clickName"></span></h2>
<div id="box" class="box">
<div id="nameBox" class="nameBox"></div>
<input type="button" name="btn" class="btn" id="btn" value="点名">
</div>
<script>
// 数据准备
var arr = [1,2,3,4,5,6,7,8,9,10]
// 获取元素
var box = document.getElementById("box");
var nameBox = document.getElementById("nameBox");
var btn = document.getElementById("btn");
var clickName = document.getElementById("clickName");
// 定时器名
var timeId;
// 根据名字数组渲染到页面
arr.forEach(function(value, index, self){
// 创建新元素
var nameSpan = document.createElement("span");
// 为新创建的元素添加属性
nameSpan.className = "name";
nameSpan.innerHTML = value;
nameBox.appendChild(nameSpan);
});
// 添加点名事件
btn.onclick = function(){
// 如果按钮显示点名,点击开始点名
if(this.value === "点名"){
// 清空选中的名字
clickName.innerHTML = "";
// 创建一个定时器,使用箭头函数
timeId = setInterval(function() {
// 首先清空样式
arr.forEach(function(value, index, self){
nameBox.children[index].style.backgroundColor = "";
nameBox.children[index].style.color = "";
})
// 随机选择名字
var randomName = parseInt(Math.random()*arr.length);
// 将随机选中的名字添加样式
nameBox.children[randomName].style.backgroundColor = "red";
nameBox.children[randomName].style.color = "#FFF";
clickName.innerHTML = nameBox.children[randomName].innerHTML;
}, 100);
// 将点名按钮变为停止按钮
this.value = "停止";
this.style.backgroundColor = "red";
}else{
// 如果此时是停止按钮,点击停止按钮,清除计时器
clearInterval(timeId);
// 将停止按钮变为点名按钮
this.value = "点名";
this.style.backgroundColor = "green";
}
}
</script>
</body>
</html>