1. 节点
1.1 什么是节点:
根据 W3C 的 HTML DOM 标准,HTML 文档中的所有内容都是节点(文档,标签,文本,属性,注释)
-
整个文档是一个文档节点
-
每个HTML标签是一个标签节点/元素节点
-
HTML 标签内的文本是文本节点
-
每个HTML标签的属性是属性节点
-
注释是注释节点
1.2 什么是DOM树
当浏览器加载文档的时候,会将文档中每一个节点,以树状的结构组织起来,我们将这种结构称为之节点树或DOM树
1.3 节点中常用的属性和方法
1.3.1 节点类型的属性
-
nodeType 节点的类型
-
1 元素节点
-
-
nodeName 节点的名称
-
nodeValue 节点值
-
元素节点的nodeValue始终是null
-
var box = document.getElementById('box');
// console.log(box); //浏览器的优化行为: 当做标签打印在控制台上
console.dir(box); // 以对象的形式打印在控制台上
//
// box.nodeType //返回节点的类型 标签节点是 1
// box.nodeName //返回的是节点的名称 大写的标签名
// box.nodeValue // 标签节点的nodeValue 永远是null
// console.log(box.childNodes); //返回box里面的所有子节点
1.3.2 节点层级的属性
-
找儿子的属性:
-
children 返回包含所有子元素(子标签节点)的伪数组
-
childNodes 返回包含所有的子节点的伪数组
-
-
找父亲的属性:
-
parentNode 返回父节点
-
-
找兄弟
-
nextElementSibling 返回下一个兄弟元素
-
previousElementSibling 返回上一个兄弟元素
-
1.3.3 操作节点的方法
-
appendChild() 往节点的内容后面添加一个子节点
语法: 父节点.appendChild(子节点)
//html
<div id="far">
<div id="one"></div>
</div>
<div id="two"></div>
//js
var far = document.getElementById('far');
var two = document.getElementById('two');
far.appendChild(two);
//js执行之后的效果
<div id="far">
<div id="one"></div>
<div id="two"></div>
</div>
//appendChild方法会将一个节点添加到另一个节点内容的尾部,如果这个被添加的节点是本身在页面上存在的,则会有剪切的效果
insertBefore() 往节点里面添加一个子节点,这个子节点的位置在参考子节点之前
语法: node.insertBefore(要插入的节点, 参考子节点)
//html
<div id="far">
<div id="one"></div>
</div>
<div id="two"></div>
//js
var far = document.getElementById('far');
var one = document.getElementById('one');
var two = document.getElementById('two');
far.insertBefore(two,one)
//js执行之后的效果
<div id="far">
<div id="two"></div>
<div id="one"></div>
</div>
//insertBefore是插入到参考节点之前,也有剪切的效果
removeChild() 移除某个子节点
语法: node.removeChild(要被删除的节点); 返回被移除的节点
//html
<div id="far">
<div id="son"></div>
</div>
//js
var far = document.getElementById('far');
var son = document.getElementById('son');
var result = far.removeChild(son);
console.log(result); //<div id="son"></div>
//js执行之后的效果
<div id="far">
</div>
replaceChild() 替换节点使用其他节点替换掉自己的某个子节点
语法: element.replaceChild(替换的节点, 被替换的子节点);
//html
<div id="far">
<div id="one"></div>
</div>
<div id="two"></div>
//js
var far = document.getElementById('far');
var one = document.getElementById('one');
var two = document.getElementById('two');
far.replaceChild(two,one);
//js执行之后的效果
<div id="far">
<div id="two"></div>
</div>
//也有剪切的效果
cloneNode() 克隆节点
语法: element.cloneNode([true]) ;
参数是boolean值,不传参数默认是false,为浅拷贝.传true,则是深拷贝
//html
<div id="box">
div里面的内容
<p>p元素</p>
</div>
//js
var box = document.getElementById('box');
console.log(box.cloneNode()); //<div id="box"></div>
console.log(box.cloneNode(true)) //<div id="box"> div里面的内容 <p>p元素</p> </div>
小结:
-
有剪切效果的方法:
-
appendChild()
-
insertBefore()
-
replaceChild()
-
-
移除的方法
-
removeChild()
-
-
需要传递两个参数的方法:
-
insertBefore(要插入的节点, 参考节点)
-
replaceChild(替换的节点, 被替换的节点)
-
2. 创建元素的三种方式
2.1 innerHTML
语法: element.innerHTML = '标签字符串'
//html
<div id="box">
这是div中的内容
</div>
//js
var box = document.getElementById('box');
box.innerHTML = '<p>这是动态增加的p标签</p>'
//js代码执行完毕之后的结果
<div id="box">
<p>这是动态增加的p标签</p>
</div>
2.2 docuement.write()
语法: document.write('标签字符串')
//html
<body>
</body>
//js
document.write('<div>这是动态增加的p标签</div>')
//js代码执行完毕之后的结果
<body>
<div>
这是动态增加的p标签
</div>
</body>
2.3 document.createElement()
语法: document.createElement('标签名')
///html
<div id="box">
</div>
//js
var newElement = document.createElement('p'); //此时新创建出来的newElement并没有加入到DOM树中
var box = document.getElementById('box');
box.appendChild(newElement);// 通过appendChild这个方法,将新元素添加到已经在DOM树中的元素中,这样新
//创建出来的元素才会添加到DOM树中,然后渲染到页面上展示出来
//js代码执行完毕之后的结果
<div id="box">
<p></p>
</div>
小结:
innerHTML 会覆盖原来元素里面的内容,并且会将新的元素直接渲染到页面上,但是不推荐用来创建表格(常用)
document.write() 也会直接渲染到页面上,并且在事件中执行的话,会覆盖原来页面的内容(慎用)
document.write('<h1>doucment.write加上来的</h1>'); // 直接写在script里面,不会覆盖原来的内容
var btn = document.getElementById('btn');
btn.onclick = function(){
document.write('<h1>点击之后添加的</h1>'); //放大事件函数里面,会覆盖原来的内容
}
docuement.createElement() 只是在内存中创建出来一个元素,但是并没有添加到DOM树中(常用)
2.4 动态创建列表案例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<button id="btn"> 点击按钮,假装去服务器拿数据</button>
<div id = "container">
</div>
<script>
var arr = ['html', 'css', 'es5.0js', 'dom']
//需求: 点击按钮,根据arr的数据,动态的创建无序列表,之后,每
// 1. 根据arr的数据,动态的创建无序列表
// 1.1 获取元素 btn container
var btn = document.getElementById('btn');
var container = document.getElementById('container');
// 1.2 给按钮注册点击事件
btn.onclick = function(){
// 1.3 在事件处理函数中,根据arr创建无序列表 innerHTML
// container.innerHTML = '<ul><li>html</li><li>css</li><li>es5.0js</li><li>dom</li></ul>';
// 1.3.1 根据arr的数据,把字符串拼出来
var str = '<ul>';
for(var i = 0; i < arr.length; i++) {
str += '<li>'+arr[i]+'</li>';
}
str += '</ul>';
console.log(str);
// 1.3.2 直接赋值即可
container.innerHTML = str;
// 2. 鼠标移入到li,当前li高亮
// 2.1 获取元素
var lis = document.getElementsByTagName('li');
// 2.2 给每一个li注册mouseover事件
for(var i = 0; i < lis.length; i++) {
lis[i].onmouseover = fn;
}
function fn(){
// 2.3 在事件处理函数中
// 2.3.1 先排他
for(var i = 0; i < lis.length; i++) {
lis[i].style.backgroundColor = '';
}
// 2.3.2 让当前的里高亮 this
this.style.backgroundColor = '#ccc';
}
}
</script>
</body>
</html>
2.4 动态创建表格案例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
table{
border-collapse: collapse;
}
</style>
</head>
<body>
<!--<table border="1px" width="300px">-->
<!--<thead style="background-color: #ccc">-->
<!--<tr>-->
<!--<th>haha </th>-->
<!--<th>hehe </th>-->
<!--</tr>-->
<!--</thead>-->
<!--<tbody align="center">-->
<!--<tr>-->
<!--<td>123</td>-->
<!--<td>345</td>-->
<!--</tr>-->
<!--</tbody>-->
<!--</table>-->
</body>
<script>
// 数据行 中的数据
var bodyData = [
{name: 'zs', subject: '语文', score: 100},
{name: 'ls', subject: '数学', score: 80},
{name: 'sdb', subject: '体育', score: 0},
{name: 'gw', subject: '英语', score: 59},
{name: 'bzr', subject: '数学', score: 50}
];
// 表头数据
var headData = ['姓名', '科目', '成绩', '操作'];
//需求:根据数据动态创建表格, 还要增加一个删除的操作
// 1. 先创建表格的基本机构
// 1.1. 创建table标签
var table = document.createElement('table');
table.border = '1px';
table.width = '500px';
// 1.2 创建thead
var thead = document.createElement('thead');
thead.style.backgroundColor = '#ccc';
table.appendChild(thead);
// 1.3 创建tbody
var tbody = document.createElement('tbody');
tbody.align = 'center';
table.appendChild(tbody);
// 2. 完成表头部分
// 2.1 创建表头中的tr
var tr = document.createElement('tr');
thead.appendChild(tr);
// 2.2 根据headdata中的数据,创建tr中的th
for(var i = 0; i < headData.length; i++) {
var th = document.createElement('th');
th.innerText = headData[i];
tr.appendChild(th);
}
//3. 完成表体
// 3.1.根据bodyData中对象的个数,决定创建多少个tr
for(var i = 0; i < bodyData.length; i++) {
var tr = document.createElement('tr');
//3.2 创建每一个tr的td td的个数是对象中键值对的个数 + 1
for(var key in bodyData[i]){
var td = document.createElement('td');
td.innerText = bodyData[i][key];
tr.appendChild(td);
}
// 加上后面的那个td
var td = document.createElement('td');
//删除是一个a元素
var a = document.createElement('a');
a.innerText = '删除';
a.href = ''; //没有href属性,a元素就相当于一个普通的标签.没有超链接的效果
td.appendChild(a);
tr.appendChild(td);
tbody.appendChild(tr);
//给每一个a注册点击事件,在事件处理函数中,删除当前行
a.onclick = fn;
}
// 删除点击时,调用的函数
function fn(){
// 删除当前行 tbody.removeChild(tr)
// console.log(this.parentNode.parentNode);
var result = confirm('您确定要删除吗?');
if(result){
tbody.removeChild(this.parentNode.parentNode);
}
return false;
}
//最后把table加到dom树上,这样就只会渲染一次
document.body.appendChild(table);
// //for..in
// var obj = {
// name: 'zs',
// age: 18,
// score : 100
// }
// for(var key in obj){
// // console.log(key);
// // console.log(obj[]);
// // console.log(obj['age']); //中括号语法里面,允许写字符串/数字/变量
// // console.log(obj.key); //.后面写什么就去对象中找对应的那个属性
// console.log(obj[key]);
// }
</script>
</html>
3. 扩展内容@
3.1 节点层级的其他属性
-
firstChild 返回第一个子节点
-
lastChild 返回最后一个子节点
-
firstElementChild 返回第一个子元素
-
lastElementChild 返回最后一个子元素
-
nextSibling 返回下一个兄弟节点
-
previousSibling 返回上一个兄弟节点
3.2 节点属性的兼容性问题:
-
children 在ie6-8浏览器中返回的内容会包含注释节点
-
firstElementChild ie9+才支持
-
lastElementChild ie9+ 才支持
-
nextElementSibling ie9+才支持
-
previousElementSibling ie9+才支持
3.3 创建元素的三种方式的效率问题
-
document.write() 和 innerHTML都是解析字符串执行效率相同
-
document.createElement 直接创建元素,执行效率比前两者高很多
-
document.write() 和 innerHTML优化后的代码效率跟document.createElement类似
var d1 = +new Date();
for ( var i = 0; i < 1000; i++ ) {
document.body.innerHTML += '<div style="width:100px; height:2px; border:1px solid blue;"></div>';
}
var d2 = +new Date();
console.log( d2 - d1 );
}
fn();
function fn() {
var d1 = +new Date();
var array = [];
for ( var i = 0; i < 1000; i++ ) {
array.push('<div style="width:100px; height:2px; border:1px solid blue;"></div>');
}
// console.log(array);
document.body.innerHTML = array.join('');
var d2 = +new Date();
console.log( d2 - d1 );
}
fn();