第6天-javascript事件
什么是事件
事件是用户在访问页面执行时的操作,也就是用户访问页面时的行为。当浏览器探测到一个事件时,比如鼠标点击或者按键。它可以触发与这个事件相关的JavaScript对象(函数),这些对象成为事件处理程序。
事件函数绑定
事件函数:当事件发生了,用于处理该事件的具体应对方案,表现出来就是一些代码块。例如:当鼠标点击(事件)---做什么操作?就由处理函数来完成
总结:
注意的就是事件发生和事件处理函数是不同的概念
事件发生以后,可以有事件处理函数来做对应的事情,也可以没有
如果没有事件处理函数,不会影响事件的发生,该发生的还是会发生,至于做什么事情,由事件处理函数来决定
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<button id="btn1">按钮1</button> <button id="btn2">按钮2</button> <script> oBtn1 = document.getElementById('btn1'); oBtn2 = document.getElementById('btn2'); oBtn1.onclick = function(){ alert('hello world'); } oBtn2 = null </script>
鼠标事件
onmousedown | 当鼠标按下的时候触发 |
onmouseup | 当鼠标抬起的时候触发 |
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<div id="box" style="width: 100px; height: 100px; background-color: red;"></div> <script> oBox = document.getElementById('box'); oBox.onmousedown = function(){ oBox.style.backgroundColor = 'green'; }; oBox.onmouseup = function(){ oBox.style.backgroundColor = 'orange'; }; </script>
onmouseover | 当鼠标移入的时候触发 |
onmouseout | 当鼠标移出的时候触发 |
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<style> a{ padding: 20px; text-decoration: none; color: black; } </style> ... <a href="#">首页</a> <a href="#">产品介绍</a> <a href="#">关于我们</a> <script> //找到a标签 aA = document.getElementsByTagName('a'); //oA是一个数组,遍历出每个a标签 for(i in aA){ //鼠标移入事件 aA[i].onmouseover = function(){ //如何确定是哪个a标签,可以使用this //onsole.log(this) this.style.backgroundColor = 'red'; this.style.color = 'white'; }; //鼠标移出事件 aA[i].onmouseout = function(){ this.style.backgroundColor = 'white'; this.style.color = 'black'; }; } </script>
onclick | 当鼠标点击的时候触发 |
ondblclick | 当鼠标双击的时候触发 |
onmousemove | 当鼠标移动的时候触发 |
oncontextmenu | 当鼠标右键的时候触发(可以定义右键菜单) |
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<button>按钮</button> <script> //通过标签获取元素,获取到的是一个数组 oBtn = document.getElementsByTagName('button'); //鼠标双击,因为是数组,所以必须要oBtn加索引才能获取到具体的元素 oBtn[0].ondblclick = function(){ alert('鼠标双击了'); } //鼠标移动事件 document.onmousemove = function(){ console.log('鼠标移动了'); } //鼠标右键事件 document.oncontextmenu = function(){ alert('右键显示菜单'); //阻断原来的右击动作 return false; } </script>
键盘事件
onkeydown | 当键盘按下的时候触发 |
onkeyup | 当键盘抬起的时候触发 |
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<script> //键盘按下 document.onkeydown = function(){ console.log('键盘按下'); //alert('键盘按下') 这个会阻断事件,导致键盘抬起的动作函数不会执行 } document.onkeyup = function(){ console.log('键盘抬起'); } </script>
那么键盘事件有什么使用场景呢。比如:百度搜索框,当我们输入完关键字,按下回车键后,就会执行搜索
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<script> //传一个事件参数 document.onkeydown = function(evt){ console.log(evt); } </script>
然后我们随便按一个键盘,查看console, 有一项 keyCode(键盘码),每一个按键都有一个唯一的keyCode
我们可以,这样,来按下回车键,查看到回车键的keyCode为13
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<script> document.onkeydown = function(evt){ //console.log(evt); console.log(evt.keyCode); } </script>
因此,我们可以这样模拟回车搜索
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<script> //键盘按下 document.onkeydown = function(evt){ if(evt.keyCode === 13){ alert('开始搜索..'); } } </script>
表单事件
onsubmit 当表单提交的时候触发
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<form action="https://www.baidu.com/s"> <input name="wd" id='ipt' /> <button type="submit">提交</button> </form> <script> oForm = document.getElementsByTagName('form'); oIpt = document.getElementById('ipt'); oForm[0].onsubmit = function(){ iptValue = oIpt.value; if (iptValue == ''){ alert('内容不能为空'); //return flase可以阻止提交 return false; }; return true; }; </script>
onchange 当修改表单字段的时候会触发(内容改变就会触发)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
商品单价: <span id="price">198</span> <br/> 商品数量:<input id="ipt1" type="text" value="1" /> 商品总价:<input id="ipt2" type="text" value="198"> <script> var oIpt1 = document.getElementById('ipt1'); oIpt1.onchange = function(){ var price = document.getElementById('price').innerHTML; var oIpt2 = document.getElementById("ipt2"); oIpt2.value = price * this.value; }; </script>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<form action="https://www.baidu.com/s" id="fm"> <input id="ipt" type="text" value="请输入搜索内容" name="wd"/> </form> <script> var oIpt = document.getElementById('ipt'); //获取焦点事件 oIpt.onfocus = function(){ //把输入框内容清空 oIpt.value = ""; }; //失去焦点事件 oIpt.onblur = function(){ //让输入框内容恢复原样,当用户没有输入内容的时候 if(oIpt.value == ""){ oIpt.value = "请输入搜索内容"; }; } //按回车键表单会自动提交到action设置的地址,浏览器的默认行为 //当用户没有输入内容的时候,提示不能提交,只有当用户输入内容后才可以提交 var oForm = document.getElementById("fm"); oForm.onsubmit = function(){ if(oIpt.value == ""){ alert('内容不能为空'); return false; }; }; </script>
窗口事件
onload 当对象加载完成以后触发
要解决这个问题,我们就需要当整个对象加载完再执行,这样就不会报错了
onresize 当窗口改变的时候的触发
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<script> window.onresize = function(){ //窗口改变的时候去计算宽高,来做布局 //获取浏览器可视区的高端 console.log(document.documentElement.clientHeight); console.log(document.documentElement.clientWidth); } </script>
事件对象 event以及兼容性
事件对象就是当事件发生的时候,用来记录事件的相关信息的对象
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<script> alert(event); window.onload = function(){ alert(event); //object event console.log(event); } //注意 :必须要在事件发生的时候才有值,否则就是undefined //兼容性问题 // 1、在IE和chrome下event对象是内置的,直接使用event就可以了, 在火狐下不支持 // 2、在火狐和chrome下事件对象是事件处理函数的第一个参数,在ie低版本下不支持 window.onload = function(evt){ alert(evt); //object event console.log(evt); } //如果要解决兼容性,可以这样 window.onload = function(evt){ var ev = evt || event; alert(ev); } </script>
event对象上的属性 clientX, clientY
clientX和clientY是鼠标指针在浏览器页面可视区的坐标
<div id="box" style="height: 200px; background-color: orange;"></div> <script> oBox = document.getElementById('box'); oBox.onclick = function(event){ console.log('x',event.clientX, 'y',event.clientY); } </script>
百度登录拖拽效果前置知识-offsetLeft和offsetTop
<style type="text/css"> #box{ height: 200px; width: 200px; background-color: red; position: absolute; left: 0px; top: 30px; } </style> ... <script> //基本思想:要让div移动,可以通过改变left和top值 //通过js来动态改变 //条件:需要知道如何获取left值和top值 oBox = document.getElementById('box'); oBox.onclick = function(){ console.log(oBox.offsetLeft, oBox.offsetTop); } </script>
拖拽效果
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<style type="text/css"> #box{ height: 200px; width: 200px; background-color: orange; position: absolute; left: 0; top: 0; } </style> ... <div id="box"></div> <script> var oBox = document.getElementById('box'); oBox.onmousedown = function(event){ var difX = event.clientX - oBox.offsetLeft; var difY = event.clientY - oBox.offsetTop; //鼠标移动 oBox.onmousemove = function(event){ oBox.style.left = event.clientX - difX + "px"; oBox.style.top = event.clientY - difY + "px"; }; //鼠标抬起后,box不再移动 oBox.onmouseup = function(){ oBox.onmousemove = null; } } </script> //这段代码实现了拖拽效果 //但是当快速移动鼠标的时候还有问题,这个后面再解决
事件冒泡机制
当一个元素接收到一个事件以后,会将事件传播给它的父级元素,它的父级元素会一层一层往上传播,直到最顶层的window,这种事件传播机制叫做事件冒泡
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<style type="text/css"> #box1{ height: 400px; width: 400px; background-color: green; margin: 0 auto; } #box2{ height: 300px; width: 300px; background-color: orange; margin: 0 auto; } #box3{ width: 200px; height: 200px; background-color: red; margin: 0 auto; } </style> ... <script> var oBox1 = document.getElementById('box1'); var oBox2 = document.getElementById('box2'); var oBox3 = document.getElementById('box3'); function fn(event){ alert(this.id); } oBox1.onclick = fn; oBox2.onclick = fn; oBox3.onclick = fn; </script>
当点击div3的时候,先触发div3的点击事件,弹出div3的id值为box3
然后把点击事件传给父级元素div2,触发div2的点击事件,div2绑定了事件处理函数fn,因此会弹出div2的id属性值box2
接着div2再把点击事件传播给div1,div1同样也绑定了事件处理函数,弹出id值为box1
div1再往上传播点击事件,由于div1的父级没有绑定事件处理函数,所以没有弹出值,但是div1的父级还是接收了点击事件,只是没有做出响应
这个就是冒泡机制的全过程,冒泡机制在javascript中是默认存在的
事件冒泡带来的影响
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<style type="text/css"> #box{ width: 300px; height: 300px; background-color: orange; display: none; } </style> ... <button id="btn">显示</button> <div id="box"></div> <script> var oBtn = document.getElementById('btn'); var oBox = document.getElementById('box'); //点击按钮显示div, 但是因为冒泡机制,会触发它的父级onclick时间,而document的onclick时间处理函数有把div隐藏 //因此时间冒泡机制会导致div不能显示出来 oBtn.onclick = function(){ oBox.style.display = 'block'; } document.onclick = function(){ oBox.style.display = 'none'; } </script>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
... <script> var oBtn = document.getElementById('btn'); var oBox = document.getElementById('box'); oBtn.onclick = function(event){ oBox.style.display = 'block'; event.stopPropagation(); //阻止冒泡 } document.onclick = function(){ oBox.style.display = 'none'; } </script>
事件冒泡带来的好处
虽然事件冒泡带来了一些不好的影响,但是可以通过取消事件冒泡来解决,之所以默认事件冒泡机制开启,是因为事件冒泡会节省很多代码。例如:有一个需求,点击一个按钮,显示div,点击除按钮外的其他元素,需要隐藏div ,这个时候有两种解决方案。第一种,找到页面中除了按钮外的其他元素,都给这些元素加点击事件,然后隐藏div。这一种如果页面中有几百个元素,那么实现起来就相当复杂,因此不能采用。第二种解决方案,给这些元素的共同父级加点击事件,当这些元素触发点击事件以后,把事件传播给父级元素的点击事件,这样就节省很多代码,也就是上面案例中的应用实现。
事件源
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<ul> <li>python</li> <li>Java</li> <li>Golang</li> </ul> <script> //我们已经学习过事件冒泡机制 //现在在li的父级元素配置点击事件,那么子元素li点击就会传播到ul的点击事件 var oUl = document.getElementsByTagName('ul')[0]; //那么当点击li的时候,我们怎么知道点击了哪个li呢?这就需要用到事件源了event.target oUl.onclick = function(event){ console.log(event.target); } </script>
下面我们来完成一个小案例,在表单中输入内容,点击添加按钮,会把 表单的内容作为li元素追加到ul中,当点击li的时候,字体变成红色
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<input type="text" id="ipt" /> <button id="btn">添加</button> <ul> <li>Python</li> <li>Java</li> <li>Golang</li> </ul> <script> //找到input元素 var oInput= document.getElementById('ipt'); //找到按钮 var oBtn = document.getElementById('btn'); //找到ul oUl = document.getElementsByTagName('ul')[0]; //找到li,注意这里获取到的是个数组 var oLis = document.getElementsByTagName('li'); //按钮点击事件 oBtn.onclick = function(){ //获取input的值 var oInputvalue = oInput.value; //如果值为空则弹窗提示不能为空 if(oInputvalue == ""){ alert('值不能为空!'); return false; } //创建一个li元素 var oLi = document.createElement('li'); //li里面的内容为 input的值 oLi.innerHTML = oInputvalue; //把这个li加入到ul中 oUl.appendChild(oLi); } //设置li的点击事件,字体变为红色 for(var i=0;i<oLis.length;i++){ oLis[i].onclick = function(){ this.style.color = "red"; } } </script>
这是为什么呢?
这是因为先执行了循环,只有3个值,因为前面的3个可以正常变色。那么这种情况下,我们就可以不用循环,利用冒泡机制来解决
把点击事件放在li的父级元素ul上(因为冒泡机制,点击li会传播到ul),然后根据事件源能够做到点击了哪个li,然后把它的字体变色
//设置ul的点击事件 oUl.onclick = function(event){ event.target.style.color = "red"; }
前面我们还遗留了一个拖拽效果,速度变快出现 bug的问题,那是因为移动过快导致鼠标已经移出了div,从而导致oBox.onmousemove事件没有发生了。这个问题也可以通过冒泡机制解决,我们只要把鼠标按下,移动,抬起的事件绑定到它的父级元素document就可以了