3.1 节点
节点:标签、文本、注释、换行等,节点类型nodeType、节点名称nodeName、节点值nodeValue
元素:标签
节点层级:父节点、子节点、兄弟节点
parentNode父节点的最大节点是document,再朝上查找就是null
prentElement最大父元素是html,再朝上查找就是null
<!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> <div>father <span>son</span> </div> <script> let span=document.querySelector('span') console.log(span.parentNode) //div下的东西 console.log(span.parentNode.parentNode.parentNode.parentNode) //null let li=document.querySelector('li') console.log(li) //null console.log(span.parentElement) //div下的东西 console.log(span.parentElement.parentElement.parentElement.parentElement) //null </script> </body> </html>
子节点---childNodes;子元素---children拿到伪数组,开发中常用
firstChild---第一个子节点;firstElementChild---第一个子元素(ie9以上才支持)
lastChild---最后一个子节点;lastElementChild---最后一个子元素(ie9以上才支持)
nodeType的换行---3、注释---8、元素---1
兄弟节点
nextSibling---下一个兄弟节点;previousSibling---上一个兄弟节点
nextElementChild---下一个兄弟元素;previousElementSibling---上一个兄弟元素
<!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> <ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> <li>6</li> </ul> <script> let ul=document.querySelector('ul') let li_second=ul.children[1] //ul的第二个子元素 console.log(li_second.nextSibling) //ul的第二个子元素的下一个兄弟节点 console.log(li_second.nextElementSibling) //ul的第二个子元素的下一个兄弟元素 let li_fourth=ul.children[3] //ul的第四个子元素 console.log(li_fourth.previousSibling) //ul的第4个子元素的上一个兄弟节点 console.log(li_fourth.previousElementSibling) //ul的第4个子元素的上一个兄弟元素 </script> </body> </html>
添加节点
创建元素节点---createElement('标签名')
添加元素节点---parentNode.appendChild(变量名)
添加新增元素的内容---变量名.innerText=' '
给兄弟元素前面插入兄弟元素---insertBefore(加谁,加在谁前面)
删除元素---removeChild(元素)
remove():括号内不写元素,则删除了所有
替换节点---replaceChild(新节点,旧节点)
克隆节点---cloneNode() 只克隆自己的标签,里面的内容未被克隆
cloneNode(true) 克隆自己以及自己的子孙后代和内容
练习
<body> <ul></ul> <button>新增</button> <script> let arr = ['赵龙', '卢兴愿', '吴鑫', '龚政', '钱民君'] let ul = document.querySelector('ul') let btn_append=document.querySelector('button') // 将数组中元素添加到ul中 for (let i = 0; i < arr.length; i++) { let li = document.createElement('li') ul.appendChild(li) li.innerText = arr[i] // 添加删除按钮 let btn = document.createElement('button') li.appendChild(btn) btn.innerText = '删除' // 添加删除事件 /*btn.onclick = function () { btn.parentNode.remove() }*/ btn.onclick =remove function remove(){ this.parentNode.remove() } } btn_append.onclick=function(){ let newValue=prompt('请输入新数据:') let li = document.createElement('li') ul.appendChild(li) li.innerText = newValue // 添加删除按钮 let btn = document.createElement('button') li.appendChild(btn) btn.innerText = '删除' // 添加删除事件 btn.onclick = function () { btn.parentNode.remove() } } </script> </body>
<body> <button>按钮</button> <script> var btn=document.querySelector('button') for(var i=0;i<10;i++){ // 鼠标点击后,for循环已经完成了,所以此时的i=10 btn.onclick=function(){ console.log(i) //10 } } </script> </body>
案例
<!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> <!-- <ul></ul> <button>添加</button> <script> let ul = document.querySelector('ul') let btn = document.querySelector('button') let arr = ['曹鑫宇', '康硕涵', '龚政', '赵龙', '吴穹', '任杰', '钱民君', '盛庆奥', '张国庆', '蔡浩男', '章杰', '卢兴愿', '吴鑫'] // 按钮添加点击事件 btn.onclick = fn1 function fn1() { if (arr.length == 0) { alert('添加完毕') btn.onclick = null } else { let li = document.createElement('li') ul.appendChild(li) li.innerText = arr[0] arr.shift() } // li变红 let lis = document.querySelectorAll('li') for (let i = 0; i < lis.length; i++) { // li背景颜色点击事件 lis[i].onclick = fn2 } } function fn2() { let lis = document.querySelectorAll('li') for (let j = 0; j < lis.length; j++) { lis[j].style.backgroundColor = '' } this.style.backgroundColor = 'red' } </script> --> <!-- 方式2: --> <!-- <ul></ul> <button>添加</button> <script> let ul = document.querySelector('ul') let btn = document.querySelector('button') let arr = ['曹鑫宇', '康硕涵', '龚政', '赵龙', '吴穹', '任杰', '钱民君', '盛庆奥', '张国庆', '蔡浩男', '章杰', '卢兴愿', '吴鑫'] let num = 0 btn.onclick = function () { if (num == arr.length) { alert('添加完毕') btn.onclick = null } else { let li = document.createElement('li') ul.appendChild(li) li.innerText = arr[num] num++ } for (let j = 0; j < ul.children.length; j++) { ul.children[j].onclick = fun } } function fun() { for (let k = 0; k < ul.children.length; k++) { ul.children[k].style.backgroundColor = '' } this.style.backgroundColor = 'red' } </script> --> <!-- 方式3: --> <ul></ul> <button>添加</button> <script> var arr = ['曹鑫宇', '康硕涵', '龚政', '赵龙', '吴穹', '任杰', '钱民君', '盛庆奥', '张国庆', '蔡浩男', '章杰', '卢兴愿', '吴鑫'] let ul = document.querySelector('ul') let but = document.querySelector('button') let num = 0 but.onclick = function () { if (num == arr.length) { alert('数据已经添加完了') but.onclick = null } else { let lili = document.createElement('li') ul.appendChild(lili) lili.innerText = arr[num] num++ } } // 事件委托--- li委托给了父元素 ul ul.onclick = function (e) { for (let j = 0; j < ul.children.length; j++) { ul.children[j].style.backgroundColor = '' } // e.target指向触发的事件对象 if (e.target.tagName == 'LI') { e.target.style.backgroundColor = 'red' } } </script> </body> </html>
3.2 DOM事件流
DOM事件流分三个阶段:捕获 目标元素 冒泡
捕获阶段:document -> html -> body ->父元素 ->目标元素
冒泡阶段: 目标元素->父元素->body -> html -> document
onclick只能拿到冒泡阶段,不能拿到捕获阶段
<!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>
.f{
width: 400px;
height: 400px;
background-color: pink;
}
.s{
width: 100px;
height: 100px;
background-color: skyblue;
}
</style>
</head>
<body>
<div class="f">father
<div class="s">son</div>
</div>
<script>
let f=document.querySelector('.f')
let s=document.querySelector('.s')
f.onclick=function(){
alert('father')
}
// 触发s事件时,先弹出son再弹出father
s.onclick=function(){
alert('son')
}
</script>
</body>
</html>
-
注册事件方法
-
传统事件:给元素重复注册一个事件时,只会执行最后一个(冒泡阶段)---onclick 、oninput 、onmousemove
传统事件的删除方法---元素.事件类型=null
-
事件监听(ie9以上):给元素重复注册一个事件时,都会执行(第三个布尔值为true为捕获阶段,false或者空则为冒泡阶段)--- 元素.addEventListerner('事件类型',function(){ })
监听事件的删除方法---元素.removeEventListerner('事件类型',function(){ })
-
-
事件流的特点
传统事件只有冒泡阶段,没有捕获阶段
事件监听:元素.addEventListerner('事件类型',事件处理函数,布尔值)
布尔值省略或者为false,会触发冒泡阶段;布尔值为true时,会触发捕获阶段
3.3 事件对象
-
事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象。
比如:
1.事件对象的使用
事件触发发生时就会产生事件对象,并且系统会以实参的形式传给事件处理函数。
所以,在事件处理函数中声明1个形参用来接收事件对象。
2.事件对象的兼容性处理
事件对象本身的获取存在兼容问题:
<div>123</div> <script> var div = document.querySelector('div'); div.onclick = function(e) { // 事件对象 e = e || window.event; console.log(e); } </script>
3.e.target 和 this 的区别
常情况下terget 和 this是一致的, 但有一种情况不同,那就是在事件冒泡时(父子元素有相同事件,单击子元素,父元素的事件处理函数也会被触发执行) 这时候this指向的是父元素,因为它是绑定事件的元素对象, 而target指向的是子元素,因为他是触发事件的那个具体元素对象。
<div>123</div> <script> var div = document.querySelector('div'); div.addEventListener('click', function(e) { // e.target 和 this指向的都是div console.log(e.target); console.log(this); }); </script>
事件冒泡下的e.target和this
<ul> <li>abc</li> <li>abc</li> <li>abc</li> </ul> <script> var ul = document.querySelector('ul'); ul.addEventListener('click', function(e) { // 我们给ul 绑定了事件 那么this 就指向ul console.log(this); // ul // e.target 触发了事件的对象 我们点击的是li e.target 指向的就是li console.log(e.target); // li }); </script>
阻止默认行为
html中一些标签有默认行为,例如a标签被单击后,默认会进行页面跳转。
e.preventDefault()----dom标准写法
return false;-----没有兼容性问题
e.returnValue = false;------有兼容性问题
<a href="http://www.baidu.com">百度</a> <script> // 2. 阻止默认行为 让链接不跳转 var a = document.querySelector('a'); a.addEventListener('click', function(e) { e.preventDefault(); // dom 标准写法 }); // 3. 传统的注册方式 a.onclick = function(e) { // 普通浏览器 e.preventDefault(); 方法 e.preventDefault(); // 低版本浏览器 ie678 returnValue 属性 e.returnValue = false; // 我们可以利用return false 也能阻止默认行为 没有兼容性问题 return false; } </script>
阻止事件冒泡
事件冒泡本身的特性,会带来的坏处,也会带来的好处。
e.stopPropagation(); ----阻止冒泡
window.event.cancelBubble = true;------了解
<div class="father"> <div class="son">son儿子</div> </div> <script> var son = document.querySelector('.son'); // 给son注册单击事件 son.addEventListener('click', function(e) { alert('son'); e.stopPropagation(); // stop 停止 Propagation 传播 window.event.cancelBubble = true; // 非标准 cancel 取消 bubble 泡泡 }, false); var father = document.querySelector('.father'); // 给father注册单击事件 father.addEventListener('click', function() { alert('father'); }, false); // 给document注册单击事件 document.addEventListener('click', function() { alert('document'); }) </script>
-
谁绑定了这个事件。
-
鼠标触发事件的话,会得到鼠标的相关信息,如鼠标位置。
-
键盘触发事件的话,会得到键盘的相关信息,如按了哪个键。
-
标准浏览器中是浏览器给方法传递的参数,只需要定义形参 e 就可以获取到。
-
在 IE6~8 中,浏览器不会给方法传递参数,如果需要的话,需要到 window.event 中获取查找。
-
this 是事件绑定的元素(绑定这个事件处理函数的元素) 。
-
e.target 是事件触发的元素。
-
-
事件委托
什么是事件委托
把事情委托给别人,代为处理。
不给子元素注册事件,给父元素注册事件,把处理代码在父元素的事件中执行。
事件委托的原理
给父元素注册事件,利用事件冒泡,当子元素的事件触发,会冒泡到父元素,然后去控制相应的子元素。
事件委托的作用
-
我们只操作了一次 DOM ,提高了程序的性能。
-
动态新创建的子元素,也拥有事件。
<ul> <li>今天是快乐的一天!</li> <li>今天是快乐的一天!</li> <li>今天是快乐的一天!</li> <li>今天是快乐的一天!</li> <li>今天是快乐的一天!</li> </ul> <script> // 事件委托的核心原理:给父节点添加侦听器, 利用事件冒泡影响每一个子节点 var ul = document.querySelector('ul'); ul.addEventListener('click', function(e) { // e.target 这个可以得到我们点击的对象 e.target.style.backgroundColor = 'pink'; }) </script>
-
-
获取鼠标在页面的坐标
屏幕可视区域:e.clientX、e.clientY
页面:e.pageX、e.pageY----会随着页面滑动坐标发生变化
浏览器距离电脑屏幕:e.screenX、e.screenY
<script> // 鼠标事件对象 MouseEvent document.addEventListener('click', function(e) { // 1. client 鼠标在可视区的x和y坐标 console.log(e.clientX); console.log(e.clientY); // 2. page 鼠标在页面文档的x和y坐标 console.log(e.pageX); console.log(e.pageY); // 3. screen 鼠标在电脑屏幕的x和y坐标 console.log(e.screenX); console.log(e.screenY); }) </script>
案例
<!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>
body {
background-color: blueviolet;
}
.div {
width: 100px;
height: 100px;
background-color: skyblue;
position: absolute;
top: 0;
left: 0;
}
img {
width: 100%;
height: 100%;
}
.box {
width: 300px;
height: 300px;
background-color: pink;
margin-top: 300px;
margin-left: 500px;
}
</style>
</head>
<body>
<div class="div">
<img src="../images/fresh_goods_7.jpg" alt="">
</div>
<div class="box"></div>
<script>
// 鼠标按下(在图片区域按下)拖拽盒子才会移动
// 鼠标在中间盒子区域外松开后盒子停止移动
// 鼠标在中间盒子区域松开 图片会展示在中间盒子内,然后图片回到原始位置
// 有个盒子,获取元素,给元素添加事件
var div = document.querySelector('.div')
var img = document.querySelector('img')
var box = document.querySelector('.box')
div.onmousedown = function (e) {
// 把鼠标点击的坐标赋给div的top和left
div.style.top = e.clientY + 'px'
div.style.left = e.clientX + 'px'
// 鼠标先在图片上按下后才能进行移动事件
document.onmousemove = function (e) {
div.style.top = e.clientY + 'px'
div.style.left = e.clientX + 'px'
}
}
// 添加鼠标抬起事件,让图片停止移动
div.onmouseup = function (e) {
// 清除鼠标在文档中的移动事件
document.onmousemove = null
// 通过div的第一个孩子img来获取图片的路径
var imgSrc = this.children[0].src
// 鼠标在y轴方向坐标300-500,图片才能完全在box里
// 鼠标在x轴方向坐标500-700,图片才能完全在box里
if (e.clientX > 500 && e.clientX < 800 && e.clientY > 300 && e.clientY < 600) {
// 原本box里面没有img,所以box_img初始状态为null
var box_img = box.querySelector('img')
div.style.top = 0
div.style.left = 0
// 当box第一次获取到图片后,box_img=true
if (box_img) return
// 创建img
var img = document.createElement('img')
img.src = imgSrc
box.appendChild(img)
}
}
</script>
</body>
</html>