节点
节点操作
删除节点
- node.remobeChild(child)
node.removeChild()方法是从DOM中删除一个子节点,返回被删除的节点
点击按钮 删除ul中的li
<!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>
<style>
li {
cursor: pointer;
}
</style>
</head>
<body>
<button>按钮</button>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</body>
<script>
var bth = document.querySelector('button');
var ul = document.querySelector('ul');
bth.onclick = function() {
if (ul.children.length === 0) {
this.disabled = 'true'
} else {
console.log(ul.removeChild(ul.children[0]));
}
}
</script>
</html>
删除留言板功能
思路如下
- 给li赋值的时候多加一个删除链接
- 获取所有的删除链接,点击删除链接让删除链接所在的父元素移除
<!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>
<style>
textarea {
resize: none;
outline: none;
vertical-align: bottom;
}
ul {
list-style: none;
}
li {
width: 255px;
background-color: pink;
}
a {
float: right;
}
</style>
</head>
<body>
<textarea name="" id="" cols="30" rows="10"></textarea>
<button>添加</button>
<ul></ul>
</body>
<script>
// 获取元素
var text = document.querySelector('textarea');
var bth = document.querySelector('button');
var ul = document.querySelector('ul');
bth.onclick = function() {
var flag = true;
if (text.value === '') {
alert('请输入内容');
flag = false;
return flag
} else {
var li = document.createElement('li')
li.innerHTML = text.value + "<a href='javascript:;'> 删除</a>"
ul.insertBefore(li, ul.children[0]);
text.value = '';
var as = document.querySelectorAll('a');
for (var i = 0; i < as.length; i++) {
as[i].onclick = function() {
ul.removeChild(this.parentNode)
}
}
}
}
</script>
</html>
克隆节点
- node.cloneNode():浅拷贝 只复制结构
- node.cloneNode(true):深拷贝 不仅复制结构 还复制内容
<!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>cloneNode()</title>
</head>
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</body>
<script>
var ul = document.querySelector('ul');
var li = ul.querySelectorAll('li');
var test = ul.children[0].cloneNode(true);
ul.insertBefore(test, ul.children[0])
</script>
</html>
JS动态创建表格
- 学生数据都是动态的 所以需要js动态生成 采用对象的方式存储
- 列表项所有的数据都是放到tbody里面的行
- 创建行的个数取决于对应多少人
- 使用循环对象的方式创建单元格,并且把数据存入单元格
- 最后一列单元格是删除按钮 需要单独创建单元格
- 列表项最后添加删除操作,单击删除,可以删除当前行
<!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>
<style>
* {
margin: 0;
padding: 0;
}
table {
width: 600px;
margin: 20px auto;
}
thead tr {
background-color: skyblue;
}
a {
text-decoration: none;
}
table,
th,
tr,
td {
text-align: center;
border: 1px solid red;
border-collapse: collapse;
}
</style>
</head>
<body>
<table>
<thead>
<th>姓名</th>
<th>科目</th>
<th>成绩</th>
<th>操作</th>
</thead>
<tbody>
</tbody>
</table>
</body>
<script>
var dates = [{
name: '尧子陌',
subject: 'javascript',
score: 99
}, {
name: '惊鸿',
subject: 'javascript',
score: 100
}, {
name: '初七',
subject: 'javascript',
score: 99
}]
// 获取tbody
var tbody = document.querySelector('tbody');
for (var i = 0; i < dates.length; i++) {
// 创建tr;
var tr = document.createElement('tr');
tbody.appendChild(tr);
// 创建列
for (k in dates[i]) {
var td = document.createElement('td');
td.innerHTML = dates[i][k];
tr.appendChild(td)
};
// 单独创建删除按钮
var td = document.createElement('td');
td.innerHTML = "<a href='javascript:;'>删除</a>"
tr.appendChild(td);
};
// 删除操作
var as = document.querySelectorAll('a');
console.log(as);
for (var i = 0; i < as.length; i++) {
as[i].onclick = function() {
tbody.removeChild(this.parentNode.parentNode)
}
}
</script>
</html>
创建动态元素三种方式
- document.write()
- element.innerHTML
- document.creatElement()
区别
- document.write是将页面直接写入内容,文档流执行完毕后,会导致页面内容全部重绘
- innerHTML是将内容写入DOM节点,不会导致页面的重绘
- innerHTML创建多个元素效率更高(不要拼接字符串,采用数组方式拼接),结构稍微复杂
- creatElement()创建多个元素效率稍低一点点,但是结构更清晰
总结 :不同浏览器下,innerHTML效率要比creatElement高
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>document.write()</title>
</head>
<body>
<button>按钮</button>
</body>
<script>
var bth = document.querySelector('button');
bth.onclick = function() {
document.write('<div>Hello Word</div>')
}
</script>
</html>
innerHTML()
<!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>innerHTML</title>
</head>
<body>
<div class="inner"></div>
</body>
<script>
var inner = document.querySelector('.inner');
inner.innerHTML = '<b>Hello </b>'
// innerHTMLL采用拼接字符串的方式创建多个元素
/*for (var i = 0; i < 1000; i++) {
inner.innerHTML += '<b>Hello </b>'
}*/
// innerHTML采用数组的方式创建元素
var arr = [];
for (var i = 0; i < 1000; i++) {
arr.push('<b>Hello </b>')
}
inner.innerHTML = arr.join('')
</script>
</html>
creatElement()
<!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>creatElement()</title>
</head>
<body>
<div class="creat"></div>
</body>
<script>
var creat = document.querySelector('.creat');
for (var i = 0; i < 1000; i++) {
var b = document.createElement('b');
b.innerHTML = 'Hello';
creat.appendChild(b)
}
</script>
</html>
innerHTML的执行效率
<!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>innerHTML的执行效率</title>
<style>
div {
width: 150px;
height: 40px;
border: 1px solid red;
}
</style>
</head>
<body>
</body>
<script>
function getTime() {
var t1 = +new Date();
for (var i = 0; i < 1000; i++) {
document.body.innerHTML += '<div></div>'
}
var t2 = +new Date()
console.log(t2 - t1);
};
getTime()
</script>
</html>
innerHTML数组的执行效率
<!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>innerHTML数组的执行效率</title>
<style>
</style>
</head>
<body>
</body>
<script>
function getTime() {
var t1 = +new Date();
var arr = [];
for (var i = 0; i < 1000; i++) {
arr.push('<div style="width:150px;height:4px;border:1px solid red;"></div>');
}
document.body.innerHTML = arr.join('');
var t2 = +new Date();
console.log(t2 - t1);
}
getTime()
</script>
</html>
creatElement()的执行效率
<!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>creatElement()的执行效率</title>
<style>
div {
width: 150px;
height: 4px;
border: 1px solid blue;
}
</style>
</head>
<body>
</body>
<script>
function getTime() {
var t1 = +new Date();
for (var i = 0; i < 1000; i++) {
var div = document.createElement('div');
document.body.appendChild(div)
}
var t2 = +new Date();
console.log(t2 - t1);
}
getTime()
</script>
</html>
DOM核心总结
DOM:文档对象模型。主要提供访问与操作网页内容的接口与方法.DOM主要对元素进行操作。
主要有创建、增、删、改、查、属性操作、事件操作
创建
增加元素
删除元素
更改元素
查找元素
属性操作
事件操作
事件
eventTarget:触发事件的元素
监听方式
给元素添加事件 称为注册事件
注册方式分为两种:传统注册方式 事件监听方式
区别如下
传统注册方式
传统注册具有唯一性 同一个元素只能设置一个事件 如果同一个元素有多个事件 后面事件会覆盖前面事件
<!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>
<button>按钮</button>
</body>
<script>
var bth = document.querySelector('button');
bth.onclick = function() {
alert('22')
}
bth.onclick = function() {
alert('33')
}
</script>
</html>
addEventListener()事件监听(IE9以后支持)
- type:事件类型字符串,如onclick onmouseover等等
- listener:事件处理函数,事件发生时,调用该监听函数
- useCapture:可选函数,是一个布尔值,默认值是false
<!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>addEventListener()事件监听(IE9以后支持)</title>
</head>
<body>
<button>按钮</button>
</body>
<script>
var bth = document.querySelector('button');
bth.addEventListener('click', function() {
alert('尧子陌')
})
bth.addEventListener('click', function() {
alert('惊鸿一面')
})
</script>
</html>
attachEvent()事件监听(IE8 9 10支持)
<!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>attachEvent()事件监听(IE8 9 10支持)</title>
</head>
<body>
<button>按钮</button>
</body>
<script>
var bth = document.querySelector('button');
bth.attachEvent('onclick', function() {
alert('Hello Word')
})
</script>
</html>
事件监听解决方案
解绑事件
传统注册方式之解绑事件
eventTarget.onclick = 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>
<button>按钮</button>
</body>
<script>
var bth = document.querySelector('button');
bth.onclick = function() {
alert('尧子陌');
bth.onclick = null;
}
</script>
</html>
事件监听注册方式之解绑事件
eventTarget.removeEventListener(type,listener[,useCapture]);
eventTarget.detachEvent(eventNameWithOn,callback)
<!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>
<style>
* {
margin: 0;
padding: 0;
}
div {
width: 200px;
height: 200px;
background-color: blue;
margin: 20px auto;
}
</style>
</head>
<body>
<div></div>
<div></div>
</body>
<script>
var box = document.querySelectorAll('div');
box[0].addEventListener('click', fn1);
function fn1() {
alert('尧子陌')
box[0].removeEventListener('click', fn1)
};
box[1].attachEvent('onclick', fn2);
function fn2() {
alert('惊鸿一面');
box[1].detachEvent('onclick', fn2)
}
</script>
</html>
DOM事件流
事件在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流。
注意
- js代码只能执行捕获和冒泡的其中一个阶段
- onclick和attachEvent只能达到冒泡阶段
- addEventListener(type,listener[,useCapture])第三个参数是true,表示进入事件捕获阶段,如果是false,表示事件进入冒泡阶段
- 实际开发的过程中,我们很少使用事件捕获,我们更关注事件冒泡。
- 有些事情是没有冒泡的,如onblur,onfocus,onmouseenter等等
捕获阶段
<!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>
<style>
.father {
width: 600px;
height: 600px;
margin: 20px auto;
border-top: 1px solid transparent;
background-color: pink;
}
.son {
width: 200px;
height: 200px;
margin: 200px auto;
background-color: red;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
</body>
<script>
var father = document.querySelector('.father');
var son = document.querySelector('.son')
father.addEventListener('click', function() {
alert('father')
}, true)
son.addEventListener('click', function() {
alert('son')
}, true)
</script>
</html>
冒泡阶段
<!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>
<style>
.father {
width: 600px;
height: 600px;
margin: 20px auto;
border-top: 1px solid transparent;
background-color: pink;
}
.son {
width: 200px;
height: 200px;
margin: 200px auto;
background-color: red;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
</body>
<script>
var father = document.querySelector('.father');
var son = document.querySelector('.son')
father.addEventListener('click', function() {
alert('father')
})
son.addEventListener('click', function() {
alert('son')
})
</script>
</html>
通过两个案例不难发现,捕获事件是从上往下依次执行,冒泡事件是从下往下依次执行
事件对象
- 事件对象写在侦听函数后面的小括号,当形参使用。是系统自动创建的,不需要传递任何的参数
- 事件对象必须要有事件 是一系列事件的相关数据的集合。
- 事件对象的名字可以被我们命名的,如e event evt等等
- 事件对象也有兼容性问题,在IE下通过window.event才能识别。
事件对象的兼容性写法
<!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>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<button>按钮</button>
</body>
<script>
var bth = document.querySelector('button');
bth.onclick = function(e) {
e = e || window.event;
console.log(e);
}
</script>
</html>
事件对象之属性与方法
e.target
区别如下
- this是指绑定的事件对象
- e.target是指被触发的事件对象
<!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>e.target</title>
<style>
div {
width: 200px;
height: 200px;
background-color: pink;
}
li {
list-style: none;
width: 200px;
height: 40px;
margin-bottom: 20px;
background-color: purple;
}
</style>
</head>
<body>
<button>按钮</button>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</body>
<script>
var bth = document.querySelector('button');
var ul = document.querySelector('ul')
bth.onclick = function(e) {
console.log(e.target);
console.log(this);
}
ul.addEventListener('click', function(e) {
console.log(e.target);
console.log(this);
})
</script>
</html>
e.target与e.srcElement的兼容性写法
<!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>e.target与e.srcElement的兼容性写法</title>
</head>
<body>
<button>按钮</button>
</body>
<script>
var bth = document.querySelector('button');
bth.onclick = function(e) {
e = e || window.event;
target = e.target || e.srcElement;
console.log(e.target);
console.log(this);
}
</script>
</html>
e.type
e.type:返回事件的类型
<!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>e.type</title>
</head>
<body>
<button>按钮</button>
</body>
<script>
var bth = document.querySelector('button');
bth.onclick = function(e) {
console.log(e.type);
}
</script>
</html>
e.returnValue e.preventDefault() 阻止默认行为
<!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;
}
a {
display: block;
width: 50px;
height: 50px;
color: white;
margin: 200px auto;
text-align: center;
text-decoration: none;
line-height: 50px;
background: pink;
}
</style>
</head>
<body>
<a href="https://www.baidu.com/">百度</a>
<script>
var a = document.querySelector('a');
a.onclick = function(e) {
e.preventDefault();
e.returnValue;
}
</script>
</body>
</html>
阻止事件冒泡
e.stopPropagation()
e.cancelBubble = true
<!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>
.father {
overflow: hidden;
width: 800px;
height: 800px;
margin: 200px auto;
background-color: blue;
}
.son {
width: 400px;
height: 400px;
margin: 200px;
background-color: yellow;
}
</style>
</head>
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
// 获取元素
var father = document.querySelector('.father');
var son = document.querySelector('.son');
father.addEventListener('click', function(e) {
alert('father');
}, false)
son.addEventListener('click', function(e) {
alert('son')
e.stopPropagation()
e.cancelBubble = true
}, false)
</script>
</body>
</html>
事件委托
给父节点添加侦听器 利用事件冒泡影响每个子节点 只操作了一次 DOM 提高了程序的性能
<!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>
<li>知否</li>
<li>知否</li>
<li>知否</li>
</ul>
</body>
<script>
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
e.target.style.backgroundColor = 'red'
})
</script>
</html>
常见鼠标事件
禁止右键菜单和禁止复制文字
- contextmenu :禁止右键菜单
- selectstart :禁止复制文字
<!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>
Hello Word
</body>
<script>
// 禁止右键菜单
document.addEventListener('contextmenu', function(e) {
e.preventDefault()
})
// 禁止复制文字
document.addEventListener('selectstart', function(e) {
e.preventDefault()
})
</script>
</html>
鼠标事件对象
<!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.addEventListener('click', function(e) {
// 鼠标在可视区的X坐标与Y坐标
console.log(e.clientX);
console.log(e.clientY);
// 鼠标在页面文档的X坐标与Y坐标
console.log(e.pageX);
console.log(e.pageY);
// 鼠标在电脑屏幕的X坐标与Y坐标
console.log(e.screenX);
console.log(e.screenY);
})
</script>
</html>
小天使案例
分析如下
- 1.鼠标不断的移动,需要鼠标移动事件:mousemove
- 2.在页面中移动,给document注册事件
- 3.图标要移动距离,而且不占位置,我们要使用绝对定位
- 4.核心原理:每次鼠标移动,都会获得新的鼠标坐标,把这个x和y坐标作为图片的top和left值就可以移动图片。
<!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>
<style>
img {
position: absolute;
top: 2px;
}
</style>
</head>
<body>
<img src="./image/angel.gif" alt="">
</body>
<script>
var pic = document.querySelector('img');
console.log(pic);
document.addEventListener('mousemove', function(e) {
// 获取最新的坐标
var x = e.clientX;
var y = e.clientY;
// 将坐标赋值给图片
pic.style.left = x - 50 + 'px';
pic.style.top = y - 40 + 'px'
})
</script>
</html>