这是以前整理的JavaScript事件的一些基础内容。
一、事件的由来
随着Web的迅速发展,HTML+CSS的静态页面已经无法满足用户的需求,于是就出现了能让用户与浏览器进行交互的JavaScript,而实现这部分功能的大功臣就是我们本次要讲的——事件。事件是JavaScript和DOM之间交互的桥梁,是指用户在浏览器上由于某种行为所执行的操作。
- 事件的分类
UI事件
- load Web 页面加载完成
- unload Web 页面正在卸载
- error JS解析出错或有不存在资源
- resize 浏览器窗口大小变化
- scroll 滚动条移动
键盘事件
- keydown 用户按下按键
- keyup 用户松开按键
- keypress 按入了一个字符
鼠标事件
- click 在一个元素上按下并松开
- dblclick 在一个元素上连按两下并松开
- mousedown 在一个元素上按下鼠标按键
- mouseup 在一个元素上松开鼠标按键
- mousemove 鼠标移动
- mouseover 鼠标移入一个元素上
- mouseout 鼠标从一个元素上移开
焦点事件
- focus/focusin 元素得到焦点
- blur/focusout 元素失去焦点
表单事件
- input 输入框中值发生了变化
- change 表单元素的值发生了变化
- submit 用户提交表单
- cut 剪切了内容
- copy 复制了内容
- paste 粘贴了内容
变动事件
- DOMSubtreeModified 文档发生了变化
- DOMNodeInserted 一个节点呗插入为另一个节点的直接子节点
- DOMNodeRemoved 一个节点被从另一个节点中移除
- DOMNodeInsertedIntoDocument 一个节点被插入为另一个节点的后代
- DOMNodeRemovedFromDocument 一个节点被从其祖先节点上移除
这五花八门的各种事件类型,使JavaScript代码变得十分灵活性,给开发人员的设计也提供了更多可能性。
- 怎么将事件绑定到节点上
随着时代的发展,不仅事件的种类越来越多,事件与DOM节点的绑定方式也出现了很多种。
DOM0级事件
<a onclick=”alert()”></a>
这种写法能以最快的速度绑定,不用等到JS运行,但因为现在要求HTML与JS代码的分离,所以大多采用以下形式在JS代码中进行节点与事件的绑定。
element.onclick = function(){}
DOM0的事件具有极好的跨浏览器优势,即兼容性好。
DOM1级事件
1级DOM标准中并没有定义事件相关的内容,所以没有所谓的1级DOM事件模型。
DOM2级事件
element.addEventListener(‘click’, myFunttion(obj), false)
这里传入的执行函数不能加小括号,不然JS代码执行到这里的时候就会认为是要执行这个函数,如果要传入参数的话可以使用匿名函数,如下:
element.addEventListener(‘click’, function(){
myFunction(object);
}, false)
估计有人就要问了,匿名函数虽然好用,但是如果我要移除这个事件该怎么办?我们都知道移除绑定事件可以用node.removeEventListener(‘type’,funName),但需要指定事件类型和所绑函数名,然而匿名函数是没名字的,这时候可以采用以下方法移除事件:
var fun;
btn.addEventListener("click",function(e){
fun=arguments.callee; //arguments.callee指的是本函数
});
function remove(){
btn.removeEventListener("click",fun);
}
DOM3
- 事件流
因为HTML元素总是盒子套盒子,当你在子元素中触发点击事件,同样也是相当于点击了父元素,若是父子都有绑定点击事件,那么事件的顺序触发便产生了事件流。事件流有两种不同的流向:事件冒泡、事件捕获。
事件冒泡
概念:事件从最具体的节点向外传播到最顶层节点(window),这是事件流的默认类型,也被绝大多数浏览器所支持。不是所有的事件都能冒泡,例如:blur、focus、load、unload等。
事件捕获
概念:事件从最顶层(window)的节点向内传播到最具体的节点,在IE8及以下不支持。
在多个节点上同时添加事件冒泡和事件捕获执行顺序
实验见分晓:
grandfather.addEventListener('click',function(){
console.log('爷节点捕获');
},true)
father.addEventListener('click',function(){
console.log('父节点冒泡');
},false)
son.addEventListener('click',function () {
console.log('子冒泡');
},false)
son.addEventListener('click',function () {
console.log('子捕获');
},true)
点击子节点:
grandfather.addEventListener('click', function () {
console.log('爷节点捕获');
}, true)
father.addEventListener('click', function () {
console.log('父节点冒泡');
}, false)
son.addEventListener('click', function () {
console.log('子捕获');
}, true)
son.addEventListener('click', function () {
console.log('子冒泡');
}, false)
点击子节点:
结论:绑定在点击元素的事件是按照代码的顺序发生的,其他非绑定的元素则是通过冒泡或者捕获的触发。按照W3C的标准,先发生捕获事件,后发生冒泡事件。所以事件的整体顺序是:非目标元素捕获 -> 目标元素代码顺序 -> 非目标元素冒泡。
- 事件对象
每当事件发生时,如果有指定参数,事件对象会作为匿名封装函数的第一个参数传递进去(自动发生),事件对象中包含一些该事件的有用信息和方法。
function hide(e,object){
e.target /srcElement(IE8以下) //事件的对象
e.type //事件的类型
e.preventDefault(); //阻止默认事件,如超链接跳转
e.stopPropagation(); //阻止事件冒泡/捕获
event.stoplmmediatePropagation() //不仅阻止默认事件还阻止事件流
......
}
var a=document.getElementById('a');
a.addEventListener('click',function(e){
hide(e,obj);
},false);
事件委托
当子元素过多,逐一添加监听器会造成页面流畅度下降,所以利用事件流的特性将事件监听器的工作委托给父元素或祖先元素。
例:需要一个<ul>的每一个<li>点击后都能弹框,如果<ul>中有1000个<li>,那我们也只在<ul>上绑定一个点击事件触发弹框就可以了,而不需要逐一的去给<li>添加事件。
事件节流
高频事件触发,但在n秒内只会执行一次,每次触发事件时,如果当前有等待执行的延时函数,则直接return。
function throttle(fn,delay=100){
let timer=null
return function(){
if(timer){
return
}
time=setTimeout(()=>{
fn.apply(this,arguments)
timer=null
},delay)lay)
}
}
事件防抖
触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。如果事件在规定的时间间隔内被不断的触发,则调用方法会被不断的延迟。
function debounce(fn,delay=500){
let timer=null
return function(){
if(timer){
clearTimeout(timer)
}
timer=setTimeout(()=>{
fm.apply(this,arguments)
timer=null
},delay)
}
}