一、JavaScript事件简介:
什么叫事件:当我们点击一个按钮的时候,会弹出一个对话框。在JavaScript中,“点击”这个事情就看做一个事件。“弹出对话框”其实就是我们在点击事件中做的一些事情。
事件应该分为三部分:
事件源:触发谁的事件
事件类型:这个事件是干什么的,是点击呢,还是移动呢等等
事件处理函数:事件过程做的一些事情
二、事件对象event:
每触发一个事件都会生成事件对象
事件对象包含对事件的描述信息:你触发一个点击事件的时候,你点在哪个位置了,坐标是多少
你触发一个键盘事件的时候,你按的是哪个按钮
获取事件对象:在每一个时间处理函数的行参位置,默认第一个就是事件对象
IE兼容写法:
e=e || window.event
三、点击事件的光标坐标点获取
每个点击事件的坐标点都不是一对,因为有一个相对的坐标系
相对事件源(你点击的元素),相对页面,相对浏览器窗口
相对事件源(你点击的元素)offsetX,offsetY:
是相对于你点击的元素的边框内侧开始计算
offsetX和offsetY
相对于浏览器窗口(clientX,clientY):
是相对于浏览器窗口来计算的,不管你页面滚动到什么情况,都是根据窗口来计算坐标
clientX和clientY
相对于页面(pageX和pageY):
是相对于整个页面的坐标点,不管有没有滚动,都是相对于页面拿到的坐标点
pageX和pageY
四、常见的事件:
大致分为几类,浏览器事件/鼠标事件/键盘事件/表单事件/触发事件
浏览器事件:load:页面全部资源加载完毕 scroll:浏览器滚动的时候触发 resize:页面大小事件
鼠标事件:click:点击事件 dbclick:双击事件 contextmenu:右键点击事件 mousesown:鼠标左键按下事件 mouseup:鼠标左键抬起事件 mousemove:鼠标移动事件 mouseout:鼠标移出事件 mouseover:鼠标移入事件 mouseenter:鼠标移入事件 mouseleave:鼠标移出事件
mouseover与mouseenter区别
1、onmouseover、onmouseout:鼠标经过时自身触发事件,经过其子元素时也触发该事件;(父亲有的东西,儿子也有) ,支持冒泡
2、onmouseenter、onmouseleave:鼠标经过时自身触发事件,经过其子元素时不触发该事件。(父亲的东西就是父亲的,不归儿子所有) ,不支持冒泡
键盘事件:
keyup:键盘抬起事件
keydown:键盘按下事件
keypress:键盘按下再抬起事件
表单事件:
change:表单内容改变事件
input:表达内容输入事件
submit:表单内容提交事件
触摸事件:touchstart:触摸开始事件
touchend:触摸结果事件
touchmove:触摸移动事件
五、事件
鼠标事件:
鼠标移入移出改变样式
表单提交事件onsubmit
html: <div class="container">
<form id="loginForm" action="#" method="get" autocomplete="off">
<div class="user-wrap">
<label for="username">用户名: </label>
<input type="text" name="username" id="username" />
</div>
<div class="psw-wrap">
<label for="password">密 码: </label>
<input type="password" name="password" id="password" />
</div>
<div class="btn-wrap">
<input type="submit" value="提交" />
<input type="reset" value="重置" />
</div>
</form>
</div>
js:window.onload = function(){
const userNameEle = this.document.querySelector("#username");
const passwordEle = this.document.querySelector("#password");
const passWord = passwordEle.value;
const userWrap = document.querySelector(".user-wrap");
const userInputEle = this.document.querySelector("#username");
//事件处理
userNameEle.onblur = function(){
const userName = userNameEle.value;
if(userName == ""){
if(!userInputEle.nextElementSibling){
const spanEle = document.createElement("span");
const spanText = document.createTextNode("用户名不能为空!");
spanEle.appendChild(spanText);
spanEle.style.color = "red";
spanEle.style.fontSize = "12px";
userWrap.appendChild(spanEle);
}
}else{
if(userInputEle.nextElementSibling){
userWrap.removeChild(userInputEle.nextElementSibling);
}
}
}
}
css:* {
padding: 0;
margin: 0;
font-size: 14px;
}
body {
background: rgba(104, 117, 104, .5);
position: relative;
height: 100vh;
}
.container {
width: 600px;
height: 400px;
background-color: rgba(130, 64, 192, .4);
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
border-radius: 30px;
display: flex;
align-items: center;
justify-content: center;
form{
line-height: 60px;
width: 100%;
padding: 0 30px;
.user-wrap{
display: flex;
height: 40px;
margin: 30px 0;
label{
color: white;
font-size: 20px;
line-height: 40px;
margin-right: 10px;
}
input{
flex: 1;
}
}
.psw-wrap{
display: flex;
height: 40px;
margin-bottom: 20px;
input{
flex: 1;
}
label{
color: white;
font-size: 20px;
line-height: 40px;
margin-right: 10px;
}
}
.btn-wrap{
display: flex;
justify-content: center;
input{
width: 100px;
height: 50px;
background-color: rgb(60, 60, 145);
color: white;
outline: none;
border: none;
margin-right: 10px;
border-radius: 10px;
cursor: pointer;
&:hover{
background-color: rgb(67, 150, 67);
}
}
}
}
}
表单提交项目中常用方式:
内容转变事件onchange
焦点事件:失去焦点onblur
获取焦点onfocus
键盘事件:
只给能在页面上选中的元素(表单元素)和document来绑定键盘事件
注:不能给页面上一个div元素,设置键盘事件的
确定按键:我们的键盘上每一个按键都有一个自己独立的编码,我们就是靠这个编码来确定我们按下的是哪个按键的,我们通过事件对象.keyCode或者事件对象.which来获取,为什么要有两个呢,是因为FireFox2.0不支持keycode所以要which
常见的键盘码:8:删除键(delete)9:制表符(tab)等等
组合按键:
组合按键最主要的就是alt/shift/ctrl三个按键
在我们点击某一个按键的时候判断一下这三个按键有没有按下,有就是组合了,没有就是没组合
六、事件绑定方式:
事件属性DOM0:
把事件写在标签的属性里面:
好处:大家都会,几乎所有的浏览器都支持
坏处:夹杂在HTML文件中,代码不简洁;这种事件写法效率不高‘不符合“行为,样式,结构”相分离
<input type="button" οnclick="alertMessage()"value="按钮">
事件赋值式DOM0:
缺点:只能给一个元素注册一个事件,绑定一个事件,后一个会覆盖前一个
好处:符合“行为,样式,结构”想分离;便于操作当事对象;方便读取事件对象
当你点击的时候,只会执行第二个,第一个就没有了
事件监听DOM2:
addEventListener:非IE 7 8下使用
语法:元素.addEventListener('事件类型',事件处理函数,冒泡还是捕获)
当你点击div的时候,两个函数都会执行,并且会按照你注册的顺序执行
先打印(我是第一个事件)再打印(我是第二个事件)
注意:事件类型的时候不要写on,点击事件就是click,不是onclick
attachEvent:IE7 8 下使用:
语法:元素.attEvent('事件类型',事件处理函数)
当你点击div的时候,两个函数都会执行,并且会按照你注册的顺序倒序执行
先打印(我是第二个事件)再打印(我是第一个事件)
注意:事件类型的时候要写on,点击事件onclick
两种写法的去区别;
注册事件的时候事件类型参数的写法
addEventListener:不用写on
attachEvent:要写on
参数个数:
addEventListener:一般是三个常用参数
attachEvent:两个参数
执行顺序:
addEventListener:顺序注册,顺序执行
attachEvent:循序注册,倒序执行
适用浏览器:
addEventListener:非IE 7 8的浏览器
attachEvent:IE 7 8浏览器
七、事件的执行机制
事件的传播:
思考:点击红色区域会不会触发粉红色区域?
就像上面这张图片一样,我们点击在红色盒子身上的同时,也点击在了粉色盒子上,这个是既定的事实,那么两个盒子的点击事件都会触发,这个叫做事件的传播
当元素触发一个事件的时候,其父元素也会触发相同的事件,父元素的父元素也会触发相同的事件
就像上面的图片一样,点击红色盒子上的时候,会触发红色盒子的点击事件,也是点击在了粉色盒子上,也会触发粉色盒子的点击事件,也是点击了body上,也会触发body的点击事件,也是点击在了html上,也会触发html的点击事件,也是点击在了document上,也会触发document的点击事件,也是点击在了window上,也会触发window的点击事件,也就是说,页面上任何一个元素触发事件,都会一层一层最终导致window的相同事件触发,前提是各层级元素得有注册相同的事件,不然不会触发。
在事件传播的过程中,有一些注意的点:只会传播同类事件,只会从点击元素开始按照html的结构逐层向上元素的事件会被触发,内部元素不管有没有该事件,只要上层元素有该事件,那么上层元素的事件就会被触发。
事件传播的方向:
事件确实会从自己开始,到window的所有相同事件都会触发
是因为我们点在自己身上,也确实逐层的点在了直至window的每一个元素身上
但是到底是先点自己身上,还是先点在了window身上呢?
先点在自己身上,就是先执行自己的事件处理函数,逐层向上最后执行window的事件处理函数
反之,则是先执行window的事件处理函数,逐层向下最后执行自己的事件处理函数
目标:你是点击在哪个元素身上了,那么这个事件的目标是就是什么
事件冒泡:
就是从事件目标的事件处理函数开始,依次向上,直到window的事件处理函数触发
特点:事件传播方向,由内而外
事件捕获:
就是从window的事件处理函数开始,依次向内,只要事件目标的事件处理函数执行,也就是从上向下的执行事件处理函数
事件原型图:
实现:事件捕获和事件冒泡
addEventListener的第三个参数决定了是事件捕获还是事件冒泡
true:表示注册的事件在捕获阶段触发
false:表示注册的事件在冒泡阶段触发-----默认值
事件处理三个阶段:
事件的处理过程主要有三个阶段:捕获阶段,目标阶段,冒泡阶段;
W3C:任何事件发生时,先从顶层开始进行事件捕获,直到事件触发到达事件源,再从事件源向上进行事件捕获(事件冒泡)。
标准浏览器:addEventListener("dlick",function,"true")方法,若第三个参数为true,则采用事件捕获。若false,则采用事件冒泡。
IE浏览器只支持事件冒泡,不支持事件捕获,所以它不支持addEventListener("click",function,"true")方法,所以ie浏览器使用ele.attachEvent("click",doSomething).
事件传播的阻止方法:
在W3C中,使用stopPropagation()方法
在IE下使用cancelBubble=true方法
事件目标对象target:
target这个属性是事件对象里面的属性,表示你点击的目标,当你触发点击事件的时候,你点击在哪个元素上,target就是哪个元素,这个target也不兼容,在IE下要使用srecElement
target与currTarget属性
当我点击哪个元素时,event.target返回的是点击的元素节点
event.currentTarget返回的是绑定事件的元素
阻止事件传播:
e.stopPerpagation()标准浏览器
e.canceBubble=true IE低版本
兼容性写法:
if(e.stopPropagation){
e.stopPropagation()
}else{
e.canceBubble=true
}
或者e.stopPropagation?e.stopPropagation:e.canceBubble=true
事件委托:
这个时候,当我们点击li的时候,可以触发ul的点事件,并且在事件内部,我们也可以拿到你点击的到底是ul还是li,这个时候,我们就可以把li的事件委托给ul来做
为什么要用事件委托:
事件委托的好处:
减少事件绑定的数量,对后来动态创建的元素依然有效,解决动态添加的元素节点无法绑定的问题,减少事件的冗余绑定,节约事件资源。
缺点;事件委托基于冒泡,对于不冒泡的事件不支持。层级过多,冒泡过程中,可能会被某层阻止掉。理论上委托会导致浏览器频繁调用处理函数,虽然很可能不需要处理。所以建议就近委托,比如在table上代理td,而不是在document上代理td。
把所有事件都用代理就可能会出现事件误判。比如,在document中代理了所有button的click事件,另外的人在引用该js时,可能不知道,造成单击button触发两个click事件。
八、默认行为;
默认行为,就是不用我们注册,它自己就存在的事情,比如我们点击鼠标右键的时候,会自动弹出一个菜单,比如我们点击a标签的时候,我们不需要注册点击事件,他自己就会跳转页面
这些不需要我们注册就能实现的事情,我们叫做默认行为
阻止默认行为:
有的时候,我们不希望浏览器执行默认事件
比如我给a标签绑定了一个点击事件,我点击你的时候希望你能告诉我你的地址是什么,而不是直接跳转链接,那么我们就要把a标签原先的默认事件阻止,不让他执行默认事件
两个方法来阻止默认事件 e.preventDefault():非IE使用
e.returnValue=false:IE使用
阻止默认事件的时候也要写一个兼容的写法: