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) //nulllet li=document.querySelector('li')console.log(li) //nullconsole.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 =removefunction 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=10btn.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 = fn1function 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 = 0btn.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 = 0but.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委托给了父元素 ulul.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再弹出fathers.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指向的都是divconsole.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 指向的就是liconsole.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>// 鼠标事件对象 MouseEventdocument.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和leftdiv.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初始状态为nullvar box_img = box.querySelector('img')div.style.top = 0div.style.left = 0// 当box第一次获取到图片后,box_img=trueif (box_img) return// 创建imgvar img = document.createElement('img')img.src = imgSrcbox.appendChild(img)}}
</script>
</body>
</html>