HTML中与javascript交互是通过事件驱动来实现的,例如鼠标点击事件、页面的滚动事件onscroll等等,可以向文档或者文档中的元素添加事件侦听器来预订事件。想要知道这些事件是在什么时候进行调用的,就需要了解一下“事件流”的概念。
事件流描述的就是从页面中接收事件的顺序。而早期的IE和Netscape提出了完全相反的事件流概念,IE事件流是事件冒泡,而Netscape的事件流就是事件捕获。
即从下至上,从目标触发的元素逐级向上传播,直到window对象。
即从上至下,从document逐级向下传播到目标元素。
后来ECMAScript在DOM2中对事件流进行了进一步规范,基本上就是上述二者的结合。
DOM2级事件规定的事件流包括三个阶段:
注意:warning::先捕获后冒泡,但是在目标节点上谁写在前面谁先执行。但是在目标元素上不区分冒泡还是捕获,按绑定的顺序来执行。
分为四个级别
DOM0:不是W3C规范。
DOM1:开始是W3C规范。专注于HTML文档和XML文档。
DOM2:对DOM1增加了 样式表对象模型
DOM3:对DOM2增加了 内容模型 (DTD 、Schemas) 和 文档验证 。
DOM0级事件具有极好的跨浏览器优势,会以最快的速度绑定。绑定方式有如下两种
将函数名直接作为html标签中属性的属性值。
<div onclick="btnClick()">按钮</div>
<script>
function btnClick(){
console.log("hello");
}
</script>
通过在JS中选中某个节点,然后给节点添加onclick属性
<div id="btn">按钮</div>
<script>
var btn=document.getElementById("btn");
btn.onclick=function(){
console.log("点击");
}
</script>
其中DOM1级事件处理标准中并没有定义事件相关的内容,所以没有所谓的DOM1事件处理
DOM2级定义了两个事件处理程序。(观察者模式)
函数均有3个参数, 第一个参数是要处理的事件名 第二个参数是作为事件处理程序的函数 第三个参数是一个boolean值,默认false表示使用冒泡机制,true表示捕获机制。
<div id="btn">按钮</div>
<script>
var btn=document.getElementById("btn");
btn.addEventListener("click",hello,false);
btn.addEventListener("click",helloagain,false);
function hello(){
console.log("hello");
}
function helloagain(){
console.log("hello again");
}
</script>
// 点击后结果:
// hello
// hello again
注意:warning:
如果定义了一模一样的监听方法时,是会发生覆盖的。
<div id="btn">点击</div>
<script>
var btn=document.getElementById("btn");
btn.addEventListener("click",hello,false);
btn.addEventListener("click",hello,false);
function hello(){
console.log("hello");
}
</script>
// 点击后结果:
// hello
对DOM2增加了 内容模型 (DTD 、Schemas) 和 文档验证 。定义了一些新的事件,比如键盘事件,还可以自定义事件。
自定义事件不是由DOM原生触发的,它的目的是让开发人员创建自己的事件。要创建的自定义事件可以由createEvent("CustomEvent"); 返回的对象有一个initCustomEvent()方法接收如下四个参数。
可以像分配其他事件一样在DOM中分派创建的自定义事件对象。如:
var div=document.getElementById("myDiv");
EventUtil.addEventHandler(div,"myEvent", function () {
alert("div myEvent!");
});
EventUtil.addEventHandler(document,"myEvent",function(){
alert("document myEvent!");
});
if(document.implementation.hasFeature("CustomEvents","3.0")){
var e=document.createEvent("CustomEvent");
e.initCustomEvent("myEvent",true,false,"hello world!");
div.dispatchEvent(e);
}
这个例子中创建了一个冒泡事件“myEvent”。而event.detail的值被设置成了一个简单的字符串,然后在div和document上侦听该事件,因为在initCustomEvent中设置了事件冒泡。所以当div激发该事件时,浏览器会将该事件冒泡到document。
stopPropagation函数
btn.addEventListener('click',function(ev){
ev.stopPropagation();
console.log('阻止冒泡')
}, false)
如果有多个DOM节点需要监听事件的情况下,给每个DOM绑定监听函数,会极大的影响页面的性能,因为我们通过事件委托来进行优化,事件委托利用的就是冒泡的原理。
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
var li_list=document.getElementsByTagName('li')
for(let index=0;index<li_list.length;index++){
li_list[index].addEventListener('click', function(ev){
console.log(ev.currentTarget.innerHTML)
})
}
</script>
正常情况我们给每一个li都会绑定一个事件,但是如果这时候li是动态渲染的,数据又特别大的时候,每次渲染后(有新增的情况)我们还需要重新来绑定,又繁琐又耗性能;这时候我们可以将绑定事件委托到li的父级元素,即ul。
var ul_dom=document.getElementsByTagName('ul')
ul_dom[0].addEventListener('click', function(ev){
console.log(ev.target.innerHTML)
})
target和currentTarget区别:
参考自
JS高级程序设计
https://zhuanlan.zhihu.com/p/114276880
https://www.jianshu.com/p/7f5f4c74dde8
https://www.jianshu.com/p/5d2905584a2f
https://www.jianshu.com/p/394e31cc8e7f
本文作者:一只菜鸟攻城狮啊
原文地址:https://www.cnblogs.com/suihang/p/13599887.html
、javaScript介绍
JavaScript是一种基于对象和事件驱动的、并具有安全性能的脚本语言
(客户端语言)
JavaScript特点
向HTML页面中添加交互行为
脚本语言,语法和Java类似
解释性语言,边解释边执行
JavaScript组成:ECMAScript 、DOM、BOM
基本结构:
<script type="text/javascript">
<!—
JavaScript 语句;
—>
</script >
示例:
……
<title>初学JavaScript</title>
</head>
<body>
<script type="text/javascript">
document.write("初学JavaScript");
document.write("<h1>Hello,JavaScript</h1>");
</script>
</body>
</html>
注:<script>…</script>可以包含在文档中的任何地方,只要保证这些代码在被使用前已读取并加载到内存即可
执行原理:
外部JS文件:
<script src="export.js" type="text/javascript"></script>
直接在HTML标签中使用:
<input name="btn" type="button" value="弹出消息框"
onclick="javascript:alert('欢迎你');"/>
二、基本常见语法:
1、核心语法:同时声明和赋值变量
var catName="皮皮";
2、数据类型:
undefined:var width;
变量width没有初始值,将被赋予值undefined;
null:表示一个空值,与undefined值相等;
number:var iNum=23; //整数
var iNum=23.0; //浮点数
boolean:true 和false;
string:一组被引号(单引号或双引号)括起来的文本
var string1="This is a string";
3、typeof运算符:
typeof检测变量的返回值
typeof运算符返回值如下函数
undefined:变量被声明后,但未被赋值
string:用单引号或双引号来声明的字符串
boolean:true或false
number:整数或浮点数
object:javascript中的对象、数组和nul
4、String对象:
5、数组:
数组的常用属性和方法
类别 名称 描述
属性 length 设置或返回数组中元素的数目
方法 join( ) 把数组的所有元素放入一个字符串,通过一个的分隔符进行分隔
sort() 对数组排序
push() 向数组末尾添加一个或更多 元素,并返回新的长度
6、逻辑控制语句:
if(条件)
{
//JavaScript代码;
}
内容是《Web前端开发之Javascript视频》的课件,请配合大师哥《Javascript》视频课程学习。
Javascript与HTML的交互是通过事件实现的,其采用的是异步事件驱动编程模型;
事件Event:
就是文档或浏览器窗口中发生的一些特定的交互瞬间;可以使用侦听器(或处理程序)来预定事件,以便事件发生时执行相应的代码;
这种方式在传统软件工程中被称为观察员模式的模型,目的就是支持页面的行为(Javascript代码)与页面的外观(html和CSS)之间的松散耦合;
事件最早是在IE3和Naviagator3中出现的,从IE4和Navigator4发布时,它们提供了相似但不相同的API,这些API发展了好几个版本;从DOM2就开始尝试以一种符合逻辑的方式来标准化DOM事件,标准浏览器已经基本实现了DOM2级事件模块,但低版本的IE(主要是IE8)仍然使用其专用的事件系统;
DOM2级事件模块,本身并没有涵盖所有事件类型;DOM3级的事件,增加了许多事件API,但更加繁琐;
事件类型(event type):
是一个用来说明发生了什么类型的事件的字符串,例如常见的事件:click(鼠标点击)、load(页面或图像载入)、mouseover(鼠标悬停)、select(在表单中选取输入框)、submit(提交表单)、keypress(键盘按键);
事件目标(event target):发生事件的关联对象;
事件处理程序(event handler):事件通常与函数配合使用,当事件发生时函数才会执行,这个函数被称为事件处理程序(函数)或事件监听程序或侦听器,是响应和处理事件的函数(event listener);当对象上注册的事件处理程序被调用时,被称为“触发”(fire、trigger))和“派发”(dispatch)了事件;
事件流(事件传播event propagation):
事件流是指哪些元素可以触发其事件处理程序的过程,也就是这些可以触发事件的元素在页面中接收事件的顺序;
IE与Netscape在事件发生顺序(事件流)支持上有差别,IE的事件流是冒泡流,而Netscape的事件流是捕获流;
冒泡型事件:
IE有事件流叫做事件冒泡(event bubbling);
基本思想:事件按照从最具体的事件目标元素(文档中嵌套层次最深的那个节点)向上传播到最不具体的事件目标元素(window或document对象)的顺序触发; 如:
<body onclick="clickHandle(this)">
<script>
function clickHandle(e){
console.log("click:" + e.nodeName);
}
</script>
<html onclick="clickHandle(this)">
<head></head>
<body onclick="clickHandle(this)">
<div onclick="clickHandle(this)">div</div>
</body>
事件按照DOM的层次结构像水泡一样不断上升到顶端,冒泡顺序为: <div>、<body>、<html>及document;
冒泡事件流
现代所有浏览器都支持事件冒泡;不过,事件一直”冒泡”到window对象,而不是document对象;
捕获型事件:
Netscape团队开发的事件流叫做事件捕获(event capturing),其基本思想与冒泡相反,是从最不精确的对象(document对象)开始接收事件,到最精确对象接收事件;
document.addEventListener("click", function(event){
console.log("document");
},true);
document.documentElement.addEventListener("click", function(event){
console.log("html");
},true);
document.body.addEventListener("click", function(event){
console.log("body");
},true);
var oDiv=document.getElementById("mydiv");
mydiv.addEventListener("click", function(event){
console.log("div");
},true);
如以上事件流的捕获顺序为:document、<html>、<body>及<div>,也可以称之为自顶向下的事件模型;
捕获事件流
事件捕获的用意在于,在事件到达预定目标之前捕获它;现代浏览器都支持捕获事件流,低版本IE不支持;
DOM2事件规范要求事件应该从document对象开始,但标准浏览器都是从window对象开始捕获事件的;
DOM事件流:
DOM同时支持两种事件模型,捕获型事件和冒泡型事件;DOM2事件规定事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段;
DOM事件流三个阶段
在DOM事件流中,实际的目标在捕获阶段不会接收到事件;目标阶段可以被看作是冒泡阶段的一部分;三个阶段的事件流会触及DOM中的所有对象,从document对象开始,也在document对象结束;
DOM2级事件规范明确要求,捕获阶段不会涉及事件目标;但现代浏览器都会在捕获阶段触发事件对象上的事件,其结果就是,有两次机会在目标对象上面操作事件;
注册事件处理程序/事件监听器:
用于响应某个事件而调用的函数称为事件处理程序(event handle),或称为事件监听器(event listener);事件处理程序的返回值有时用来指示函数是否充分处理了事件,以及阻止浏览器的默认行为;
注册事件处理程序共有三种方式;
HTML事件处理程序:
在HTML元素的事件特性中指定,该事件特性的名称是“on”+事件名,且该事件特性中的值就是能够执行的Javascript代码,也就是HTML事件处理函数体;
<div onclick="alert('大师哥王唯')"></div>
不能在其中使用未经转义的HTML语法字符,如&、”、< >;
如果HTML事件处理程序里包含多条Javascript语句,必须使用分号分隔这些语句,或断开属性值使其可以跨越多行,如:
<div onclick="console.log('HTML');
alert('CSS');">div1</div>
甚至可以在其中定义函数,如:
<div id="div1" onclick="console.log('HTML');
function show(){
console.log('show');
};
show();">div1</div>
HTML事件处理程序也可以定义在页面其他位置,甚至是在一个外部的Javascript文件中;
<script>
function show(){
alert("大师哥王唯");
}
</script>
<div onclick="show();">Web前端开发</div>
HTML事件处理程序,在后台会创建一个封装着元素属性(特性)值的函数,也就是由解释器动态创建的一个函数,该函数中还有一个局部变量event,也就是事件对象;
<div onclick="alert(event);alert(event.type);">零点程序员</div>
HTML事件处理程序中的this,指向事件的目标元素,如:
<div onclick="console.log(this);console.log(this.innerHTML);">零点程序员</div>
HTML事件处理程序中的作用域,比较特殊,它可以访问全局作用域中的任何变量和对象,但是它扩展作用域的方式,如同使用with语句,也就是说,在它内部可以像访问局部变量一样访问document及该元素本身的成员,如:
function(){
with(document){
with(this){
// 元素属性值
}
}
}
如此,事件处理程序在访问自己元素本身的属性(特性)就非常方便了,如:
<input type="button" value="Web前端开发" onclick="console.log(this.value)" />
<input type="button" value="不使用this" onclick="console.log(value)" />
<input type="button" value="大师哥王唯" style="background-color: purple;" onclick="console.log(style); alert(type)" />
如果当前元素是一个表单控件元素,则作用域中还会包含访问表单元素(父元素),如:
function(){
with(document){
with(this.form){
with(this){
// 元素属性值
}
}
}
}
如此,事件处理程序不需要引用表单元素就能访问其他表单控件,如:
<form>
<input type="text" name="username" />
<input type="button" value="显示username" onclick="alert(username.value)" />
</form>
HTML事件处理程序缺点:
存在时间差:如果在响应时,当时的事件处理程序可能尚不具备执行条件,会出错;因此,为了避免这种错误发生,一是必须保证触发事件前,相关的处理程序必须定义好;二是可以把相关处理代码封装在try-catch中,如:
<div onclick="try{show();}catch(e){}">零点程序员</div>
其特殊的扩展作用域链的方式在不同浏览器中可能会导致不同的结果;HTML与JS代码耦合性高;鉴于以上的缺点,因此HTML事件处理程序并不太常用;
DOM0级事件处理程序:
首先获得元素的引用,然后将函数赋值给该元素对应的事件处理函数属性;按照约定,事件处理程序的属性名以“on”为开头,以事件名为结尾;
window.onload=function(){
console.log("loaded");
}
var oDiv=document.getElementById("mydiv");
oDiv.onclick=function(){
alert("Web前端开发");
}
优点:简单,且具有跨浏览器的优势;
每个元素(包括window和document)都有自己的事件处理程序属性,并且这些属性名是区分大小写的,通常全部小写,即使属性名是由多个单词组成,例如:onclick、onload、readystatechange等;
这种事件处理程序被认为是元素的方法,因此,此时的事件处理程序是在元素的作用域中运行的,即其中的this引用当前元素,也就是事件目标;
var oDiv=document.getElementById("mydiv");
oDiv.onclick=function(){
console.log(this);
console.log(this.id);
console.log(this.innerHTML);
}
因此,可以通过this访问该元素的任何属性和方法;
以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理;
document.documentElement.onclick=function(){
console.log("html");
};
var oDiv=document.getElementById("mydiv");
oDiv.onclick=function(){
console.log("div")
};
document.onclick=function(){
console.log("document");
};
document.body.onclick=function(){
console.log("body");
};
window.onclick=function(){
console.log("window");
};
也可以删除事件这种事件处理程序,只需为其设置为null即可;如:
oDiv.onclick=null;
HTML事件处理程序和DOM0级事件处理程序的返回值:在某些情况下,可以为它们设置返回值;通常情况下,返回false,就是阻止浏览器默认行为,如:
<a href="cn.bing.com" onclick="console.log('a'); return false;">链接</a>
<script>
var txt=document.getElementById("txt");
txt.onkeypress=function(event){
if(event.key=="w")
return false; // 过滤了w
}
</script>
DOM0事件处理程序的缺点是,只能为目标元素的某种事件注册一个事件处理程序,如果注册多个,最后注册的会覆盖前面的,如:
var oDiv=document.getElementById("mydiv");
oDiv.onclick=function(){
console.log("click");
};
oDiv.onclick=function(){
console.log("click again");
};
DOM2级事件处理程序:
DOM2定义了标准的事件模型,为所有能成为事件目标的元素(包括window和document)定义了addEventListener()方法,用于处理(注册)指定的事件处理程序;
该方法接受3个参数:要处理的事件名(不能加on,此处是标准的事件名)、作为事件处理程序的函数和一个布尔值;最后的参数值如果为true,表示在捕获阶段调用事件处理程序,如果false,表示在冒泡阶段调用事件处理程序,这个参数也可忽略,默认为false;
var oDiv=document.getElementById("mydiv");
oDiv.addEventListener("click", function(){
console.log(this.id + ":被单击了");
}, false);
// 或
function clickHandle(){
console.log(this.id + ":被单击了");
}
oDiv.addEventListener("click", clickHandle, false);
也可以为同一个事件注册多个事件处理程序;
function fn1(){console.log("第一个事件");}
function fn2(){console.log("第二个事件");}
oDiv.addEventListener("click", fn1, false);
oDiv.addEventListener("click", fn2, false);
同时定义HTML事件处理程序或DOM0级事件处理程序与DOM2级事件处理程序,如:
<div id="mydiv" onclick="console.log('王唯是好人')" >Web前端开发</div>
<script>
var oDiv=document.getElementById("mydiv");
oDiv.onclick=function(){
console.log("Web前端开发");
}
oDiv.addEventListener("click", function(){
console.log(this.id + ":被单击了");
}, false);
</script>
removeEventListener()移除事件:通过addEventListener()添加的事件处理程序只能用removeEventListener()方法来移除,移除时,所传入的与添加处理程序时的参数相同;
var oDiv=document.getElementById("mydiv");
function clickHandle(){
console.log(this.id + ":被单击了");
this.removeEventListener("click", clickHandle,false);
}
oDiv.addEventListener("click", clickHandle, false);
如果通过addEventListener()添加匿名函数将无法移除,如:
oDiv.addEventListener("click", function(){
console.log(this.id + ":被单击了");
}, false);
// 后期如果使用
oDiv.removeEventListener("click", function(){
// 没有用的
},false);
但可以变相地移除,如:
oDiv.addEventListener("click", function(){
console.log(this.id + ":被单击了");
this.removeEventListener("click", arguments.callee,false);
}, false);
如果使用addEventListener()将事件处理函数加入到捕获阶段,则必须在removeEventListener()中指明是捕获阶段,才能正确移除此事件,也就是第三个参数也必须相同;
function clickHandle(event){
console.log(this.id + ":被单击了");
this.removeEventListener("click", clickHandle,true);
}
oDiv.addEventListener("click", clickHandle, false);
也可以一次性移除多个事件,如:
function clickHandle(event){
console.log(event.type);
this.removeEventListener("mouseover", clickHandle,false);
this.removeEventListener("mouseout", clickHandle,false);
this.removeEventListener("click", clickHandle,false);
}
oDiv.addEventListener("click", clickHandle, false);
oDiv.addEventListener("mouseover", clickHandle, false);
oDiv.addEventListener("mouseout", clickHandle, false);
三个事件使用了相同的处理函数,此时,只要三个事件有中有一个事件被触发,三个事件处理程序都会被移除;
function clickHandle(event){
console.log(event.type);
this.removeEventListener("mouseover", overHandle,false);
this.removeEventListener("mouseout", outHandle,false);
this.removeEventListener("click", clickHandle,false);
}
function overHandle(){
console.log("over");
}
function outHandle(){
console.log("out");
}
oDiv.addEventListener("click", clickHandle, false);
oDiv.addEventListener("mouseover", overHandle, false);
oDiv.addEventListener("mouseout", outHandle, false);
分别使用了三个处理程序;
如果要获取Event事件对象,也是通过在事件处理函数的参数中指定;另外,事件处理程序中的this也是指当前元素;
oDiv.addEventListener("click", function(event){
console.log(event);
console.log(event.type);
console.log(this.innerHTML);
}, false);
一般情况下,都将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器;
IE事件处理程序:
IE9及以下不支持DOM事件,但它实现了与DOM类似的事件,其为每个元素和window对象添加了两个方法:attachEvent(“event_name”, fnHandler):用来给一个对象附加事件及事件处理函数;detachEvent(“event_name”, fnHandler):清除一个对象的事件及事件处理函数;两个方法都接受相同的两个参数:事件名称与处理函数,但事件名称必须以“on”开头,如onclick;
var oDiv=document.getElementById("mydiv");
oDiv.attachEvent("onclick", function(){
console.log("onclick");
});
(IE11不支持,IE10及以下支持)
也可以添加多个事件处理程序,但处理程序执行的顺序有可能与DOM不同,如;
var oDiv=document.getElementById("mydiv");
oDiv.attachEvent("onclick", function(){
console.log("Web前端面开发");
});
oDiv.attachEvent("onclick", function(){
console.log("大师哥王唯");
});
// 或
function fn1(){console.log("fn1");}
function fn2(){console.log("fn2");}
oDiv.attachEvent("onclick", fn1);
oDiv.attachEvent("onclick", fn2);
IE10和IE9的执行顺序与DOM相同,但IE8及以下,执行的顺序与DOM相反;
由于IE只支持事件冒泡(不支持事件捕获),所以以上方法会被添加到冒泡阶段;
oDiv.attachEvent("onclick", function(){
console.log("div");
});
document.body.attachEvent("onclick", function(){
console.log("body");
});
document.documentElement.attachEvent("onclick", function(){
console.log("html");
});
document.attachEvent("onclick", function(){
console.log("document");
});
window.attachEvent("onclick", function(){
console.log("window");
});
window对象上的onclick并没有触发,说明IE的冒泡到顶层是document对象;
使用detachEvent()来移除attachEvent()添加的事件处理程序,但也必须提供相同的参数,同时,它也不能移除添加的匿名函数,如:
var oDiv=document.getElementById("mydiv");
function clickHandler(){
console.log("Web前端面开发");
oDiv.detachEvent("onclick", clickHandler);
}
oDiv.attachEvent("onclick", clickHandler);
// 或
oDiv.attachEvent("onclick", function(){
console.log("大师哥王唯");
oDiv.detachEvent("onclick", arguments.callee);
});
使用attachEvent()与使用DOM0级方法的主要区别在于事件处理程序的作用域,其会在全局作用域中运行,因此this等于window;
oDiv.attachEvent("onclick", function(){
console.log(this); // window
console.log(this===window); // true
});
可以封装一个函数,为一个元素添加某种类型的事件并注册相关的事件处理程序,并指定它的this为事件目标,如:
var oDiv=document.getElementById("mydiv");
function addEvent(target, type, handler){
target.attachEvent("on" + type, function(event){
// 把处理程序作为事件目标的方法调用,并传递事件对象
return handler.call(target, event);
});
}
// 在IE10以下测试
addEvent(oDiv, "click", function(event){
console.log(event);
console.log(this); // div
});
在IE事件处理程序中,获取Event事件对象与DOM也不一样;
兼容DOM和IE注册事件处理程序:
var btn=document.getElementById("btn");
var handler=function(){
console.log("Web前端开发");
};
if(btn.addEventListener)
btn.addEventListener("click", handler, false);
else
btn.attachEvent("onclick", handler);
跨平台添加/删除事件处理函数:
var EventUtil={
addHandler: function(element, type, handler){
if(element.addEventListener)
element.addEventListener(type, handler, false);
else if(element.attachEvent)
element.attachEvent("on" + type, handler);
else
element["on" + type]=handler;
},
removeHandler: function(element, type, handler){
if(element.removeEventListener)
element.removeEventListener(type, handler, false);
else if(element.detachEvent)
element.detachEvent("on" + type, handler);
else
element["on" + type]=null;
}
}
// 应用
window.onload=function(){
function clickHandler(){
console.log("clickHandler");
var oDiv=document.getElementById("mydiv");
EventUtil.removeHandler(oDiv, "click", clickHandler);
}
var oDiv=document.getElementById("mydiv");
EventUtil.addHandler(oDiv, "click", clickHandler);
}
Event事件对象:
在触发DOM上的某个事件时,会产生一个事件对象event,这个对象包含着所有与事件有关的信息;
var oDiv=document.getElementById("mydiv");
oDiv.addEventListener("click", function(event){
console.log(event); // MouseEvent,与鼠标事件相关的信息
});
document.addEventListener("keypress", function(event){
console.log(event); // KeyboardEvent,与按下的键相关的信息
});
获取事件信息很重要,一般会获取以下信息:引起事件的元素(对象)、事件的类型、事件发生时鼠标的信息、事件发生时键盘的信息等;不同的事件所包含的信息也不同,例如,鼠标致的事件对象中,会包含鼠标位置等相关的信息,而键盘操作导致的事件,会包含与按下的键有关的信息;
事件对象只在发生事件时才被创建,且只有事件处理函数才能访问;所有事件处理函数执行完毕后,事件对象就被销毁;所有浏览器都支持event事件对象,但支持方式不同,IE与DOM是用两种不同的方法实现事件对象;
DOM的事件对象:
在DOM中,event对象必须作为唯一的参数传给事件处理函数,DOM0级和DOM2级都是使用这个参数获取事件对象;
var oDiv=document.getElementById("mydiv");
oDiv.onclick=function(event){
console.log(event);
}
oDiv.addEventListener("click", function(event){
console.log(event);
});
在通过HTML特性添加的事件处理程序时,变量event保存着event对象,如:
<input type="button" value="Web前端开发" onclick="console.log(event)" />
Event类:
Event接口表示在 DOM 中出现的事件,其是其他类型事件的基类,包含适用于所有事件的属性和方法;构造函数:Event(),创建并返回一个 Event 对象;
语法:event=new Event(typeArg, eventInit);参数:typeArg,字符串,表示所创建事件的名称;eventInit可选,是EventInit 类型的字典对象,其接受以下字段:
var event=new Event("gohome", {"bubbles":true, "cancelable": false, "composed":false});
console.log(event);
但是IE不支持;有了事件后,就可以为某个元素添加这个事件,并注册其处理程序,如:
function goHomeHandler(event){
console.log(event);
}
document.addEventListener("gohome", goHomeHandler,false);
使用dispatchEvent()方法触发该事件,如:
document.dispatchEvent(event);
var oDiv=document.getElementById("mydiv");
oDiv.dispatchEvent(event);
由于这个事件是可以冒泡的,所以document后代元素也可以触发该事件;
使用Event构造函数返回一个event对象的应用非常少,并且IE也不支持,后面我们会讲到另外一种创建自定义的Event对象的方法:document.createEvent(“type”);如:
var event=document.createEvent("CustomEvent");
event.initCustomEvent("gohome",true,false,"我想家了");
function goHomeHandler(event){
console.log(event); // type为gohome的CustomEvent类型
console.log(event.detail);
}
Event对象的属性和方法:
属性/方法类型读/写说明
Event对象包含与创建它的特定事件有关的属性和方法,但触发的事件类型不同,可用的属性和方法也不同;DOM事件对象还具有以下共同成员;
常见Event的子类:
type属性:
在需要通过一个函数处理多个事件时,可以使用type属性;
var btn=document.getElementById("btn");
btn.addEventListener("click", clickHandler, false);
btn.addEventListener("mouseover", clickHandler, false);
btn.addEventListener("mouseout", clickHandler, false);
function clickHandler(event){
switch(event.type){
case "click":
console.log("click");
break;
case "mouseover":
event.target.style.backgroundColor="green";
break;
case "mouseout":
event.target.style.backgroundColor="";
break;
}
}
deepPath属性:返回由事件流所经过的DOM节点组成的Array;所有浏览器均未实现,但Webkit浏览器实现了一个类似的path属性;
// 在子元素div1上进入
var oDiv=document.getElementById("mydiv");
var div1=document.getElementById("div1");
function handler(event){
console.log(event.path);
}
// path数组中包括div1
oDiv.addEventListener("mouseover", handler,false);
// path数组中不包括div1
oDiv.addEventListener("mouseenter", handler,false);
composedPath():返回包含事件的路径的一个Array;
console.log(event.composedPath());
返回的结束与path基本是一致的,但IE不支持此方法;
bubbles属性:
bubbles返回一个布尔值,表明当前事件是否会向DOM树上层元素冒泡;
// oDiv中有个id为div1的子元素
var oDiv=document.getElementById("mydiv");
function handler(event){
console.log(event.type + ":"+event.bubbles +",target:" + event.target.id);
}
oDiv.addEventListener("mouseover", handler,false);
oDiv.addEventListener("mouseenter", handler,false);
例如可以检查该属性是否冒泡,如:
var oDiv=document.getElementById("mydiv");
function handler(event){
if(!event.bubbles){
console.log("不冒泡,做点什么事");
}
console.log("不管冒不冒泡,都去做");
}
// oDiv.addEventListener("mouseover", handler,false);
oDiv.addEventListener("mouseenter", handler,false);
this、currentTarget、target及srcElement属性:
var oDiv=document.getElementById("mydiv");
oDiv.addEventListener("mouseover", function(event){
console.log(event.currentTarget);
console.log(event.target);
console.log(event.srcElement);
},false);
在事件处理程序内部,this始终等于currentTarget的值,而target则只包含事件的实际目标;如果直接将事件处理程序指定给了目标元素,则this、currentTarget和target包含相同的值;
var oDiv=document.getElementById("mydiv");
oDiv.addEventListener("click", function(event){
console.log(event.currentTarget==this); // true
console.log(event.target==this); // true
},false);
如果事件处理程序被添加到元素的父节点上,三者就不相同,如:
document.body.addEventListener("click", function(event){
console.log(event.currentTarget);
console.log(this);
console.log(event.currentTarget===document.body);
console.log(this===document.body);
console.log(event.target);
console.log(event.target==document.getElementById("mydiv"));
},false);
当将相同的事件处理程序注册到多个元素时,currentTarget属性是很有用的,如:
function hide(event){
event.currentTarget.style.visibility="hidden";
console.log(event.currentTarget);
}
var ps=document.getElementsByTagName("p");
for(var i=0,len=ps.length; i<len; i++){
ps[i].addEventListener("click", hide, false);
}
对于srcElement属性,它本来是由IE6开始被引入的,与DOM事件的target指向同一个对象,虽然现在被纳入标准,但在部分移动端浏览器中并不支持,所以在生产环境中,只是为了兼容老版的IE,并不把它作为标准的属性来使用;
eventPhase属性:
事件对象的eventPhase属性,返回一个整数值,用来确定事件当前正位于事件流的哪个阶段,如果没有事件正在被处理,该属性返回Event.NONE,值为0(这个值一般不会出现),如果在捕获阶段调用的事件处理程序,该属性返回Event.CAPTURING_PHASE,值为1,如果事件处理程序处于目标对象上,则返回Event.AT_TARGET,值为2,如果是在冒泡阶段调用的事件处理程序,返回Event.BUBBLING_PHASE,值为3;
// 为mydiv添加一个子div,分别在子div和mydiv上单击
var oDiv=document.getElementById("mydiv");
oDiv.addEventListener("click", function(event){
console.log(event.currentTarget);
console.log(event.target);
console.log(event.eventPhase);
},false);
目标对象本身的事件处理程序调用是第2个阶段;
如果事件处理程序被注册为捕获,那它会在事件传播的第1个阶段被调用;
document.body.addEventListener("click", function(event){
console.log(event.currentTarget);
console.log(event.target);
console.log(event.eventPhase);
},true);
分别注册捕获型事件处理程序:
var div1=document.getElementById("div1");
div1.addEventListener("click", function(event){
console.log("div1:" + event.eventPhase); // 1
},true);
var oDiv=document.getElementById("mydiv");
oDiv.addEventListener("click", function(event){
console.log("div:" + event.eventPhase); // 1
},true);
document.body.addEventListener("click", function(event){
console.log("body:" + event.eventPhase); // 1
},true);
事件捕获提供了在事件没有送达目标之前查看它们的机会;事件捕获能用于程序调试,或用于后面介绍的事件取消技术,过滤掉事件从而使目标事件处理程序绝不会被调用;
oDiv.addEventListener("click", function(event){
console.log("div:" + event.eventPhase);
},false);
document.body.addEventListener("click", function(event){
console.log("body:" + event.eventPhase); // 1
if(event.currentTarget !==event.target)
event.stopPropagation();
},true);
事件捕获常用于处理鼠标拖放,因为要处理拖放事件的位置不能是这个元素内部的子元素;
示例:
<style>
div,p{margin:20px; padding:4px; border:1px solid;}
</style>
<p><input type="checkbox" id="chCapture" />使用捕获</p>
<div id="d1">d1
<div id="d2">d2
<div id="d3">d3
<div id="d4">d4</div>
</div>
</div>
</div>
<p id="divInfo"></p>
<script>
var clear=false, divInfo=null, divs=null, useCapture=false;
window.onload=function(){
divInfo=document.getElementById("divInfo");
divs=document.querySelectorAll("div");
chCapture=document.getElementById("chCapture");
chCapture.onclick=function(){
RemoveListeners();
AddListeners();
}
Clear();
AddListeners();
}
function RemoveListeners(){
for(var i=0,len=divs.length; i>len; i++){
var d=divs[i];
d.removeEventListener("click", OnDivClick, true);
d.removeEventListener("click", OnDivClick, false);
}
}
function AddListeners(){
for(var i=0,len=divs.length; i<len; i++){
var d=divs[i];
d.addEventListener("click", OnDivClick, false);
if(chCapture.checked)
d.addEventListener("click", OnDivClick, true);
d.onmousemove=function(){
clear=true;
}
}
}
function OnDivClick(event){
if(clear){
Clear();
clear=false;
}
if(event.eventPhase==2)
event.currentTarget.style.backgroundColor="red";
var level=event.eventPhase==0 ? "none" :
event.eventPhase==1 ? "capturing" :
event.eventPhase==2 ? "target" :
event.eventPhase==3 ? "bubbling" : "error";
divInfo.innerHTML +=event.currentTarget.id + "; eventPhase: " + level + "<br/>";
}
function Clear(){
for(var i=0,len=divs.length; i<len; i++){
divs[i].style.backgroundColor=(i & 1) ? "#f6eedb" : "#cceeff";
}
divInfo.innerHTML="";
}
</script>
取消事件(默认行为):
在HTML事件处理程序和DOM0级事件处理程序中使用返回false值,用于取消事件的默认行为;例如:阻止超连接导航行为(链接的默认行为就是在被单击时会导航到href指定的URL);
<a href="https://www.zeronetwork.cn/" onclick="alert('走不了');return false;">零点网络</a>
<!-- 或者提交表单时 -->
<form action="demo.jsp" onsubmit="alert('如果验证不通过'); return false;">
<input type="submit" value="提交">
</form>
在使用Event对象时,可以使用preventDefault()方法阻止(或者称为取消)特定事件的默认行为;
var link=document.getElementById("myLink");
link.onclick=function(event){
alert("跳不了");
event.preventDefault();
}
var myform=document.getElementById("myform");
myform.addEventListener("submit", function(event){
console.log("正在处理数据...");
var flag=false;
try {
if(!flag)
throw new Error("数据验证没通过");
} catch (error) {
console.log(error.message);
event.preventDefault();
}
});
在使用preventDefault()方法时,只有cancelable属性为true时才可以阻止事件默认行为;如:
document.addEventListener("wheel", function(event){
console.log(event.cancelable);
if(typeof event.cancelable !=="boolean" || event.cancelable){
console.log("可以被取消");
event.preventDefault();
}else{
console.log("此事件默认行为不能被取消");
console.dir(event);
}
});
示例:验证数据输入,如:
<style>
.warning{border:2px solid #f39389;border-radius: 2px;padding: 10px;position:absolute;background-color: #fbd8d4;color:#3b3c40;}
</style>
<form id="myform" action="demo.jsp">
<input type="text" id="username" />
</form>
<script>
var username=document.getElementById("username");
username.addEventListener("keypress", checkName, false);
function checkName(event){
var charCode=event.charCode;
if(charCode < 97 || charCode > 122){
event.preventDefault();
displayWarning("只能输入字母,charCode:" + charCode);
}
}
var warningTimeout;
var warningBox=document.createElement("div");
warningBox.className="warning";
function displayWarning(msg){
warningBox.innerHTML=msg;
if(document.body.contains(warningBox))
clearTimeout(warningTimeout);
else
username.parentNode.insertBefore(warningBox, username.nextSibling);
warningTimeout=setTimeout(function(){
warningBox.parentNode.removeChild(warningBox);
warningTimeout=-1;
},2000);
}
</script>
event对象的defaultPrevented属性,是DOM3事件中新增的,表示当前取消事件的状态,默认是false,如果调用了preventDefault()方法,该属性值就为true,如:
document.body.addEventListener("click", function(event){
console.log(event.defaultPrevented); // false
event.preventDefault();
console.log(event.defaultPrevented); // true
},false);
returnValue属性:与preventDefault()和defaultPrevented属性作用相同,其由旧版IE引入的一个非标准历史属性,现被收入规范;默认情况下,它被设置为 true,即允许进行默认操作,将该属性设置为 false 即可阻止默认操作;
// event.preventDefault();
event.returnValue=false; // 与preventDefault()作用相同;
console.log(event.returnValue); // false 值相反
取消事件传播:
使用stopPropagation(),用于立即停止事件在DOM层次中的传播,也就是取消进一步的事件捕获或冒泡,如:
var oDiv=document.getElementById("mydiv");
oDiv.addEventListener("click", function(event){
console.log("wangwei");
event.stopPropagation();
},false);
document.body.addEventListener("click", function(event){
console.log("body"); // 当单击oDiv时,不会打印
},false);
// 或
var oDiv=document.getElementById("mydiv");
oDiv.addEventListener("click", function(event){
console.log("div"); // 当单击oDiv时,不会打印
},true);
document.body.addEventListener("click", function(event){
console.log("body");
event.stopPropagation();
},true);
如果同一个对象注册了多个事件处理程序,即使调用了stopPropagation()方法,所有的事件处理程序还会执行,如:
document.body.addEventListener("click", function(event){
console.log("body");
event.stopPropagation();
},true);
document.body.addEventListener("click", function(event){
console.log("body again");
},true);
document.body.addEventListener("click", function(event){
console.log("body fianl");
},true);
document.body.addEventListener("mouseover", function(event){
console.log("body mouseover");
},true);
cancelBubble,布尔值,可读写,设置是否阻止冒泡,是stopPropagation()方法的历史别名,设置为 true,就可以阻止事件继续冒泡;
// event.stopPropagation();
console.log(event.cancelBubble); // false
event.cancelBubble=true;
console.log(event.cancelBubble); // true
DOM3中对event对象新增了一个stopImmediatePropagation()方法,其类似于stopPropagation()方法,用于阻止事件传播,同时也会阻止同一个对象上注册的同一事件的其他事件处理程序的调用,如:
document.body.addEventListener("click", function(event){
console.log("body");
event.stopImmediatePropagation();
}, true);
document.body.addEventListener("click", function(event){
console.log("body again");
}, true);
document.body.addEventListener("click", function(event){
console.log("body final");
}, true);
document.body.addEventListener("mouseover", function(event){
console.log("body mouseover");
}, true);
如果多个事件处理程序被注册到相同元素的相同事件类型上,当此事件触发时,它们会按照它被添加的顺序被调用,如果在其中一个事件处理程序中执行 stopImmediatePropagation()方法,那么剩下的事件监听器都不会被调用,如:
document.body.addEventListener("click", function(event){
console.log("body");
}, true);
document.body.addEventListener("click", function(event){
console.log("body again");
event.stopImmediatePropagation();
}, true);
document.body.addEventListener("click", function(event){
console.log("body final");
}, true);
其他属性:timestamp,只读,事件创建时的时间戳,单位为毫秒;
document.addEventListener("click", function(event){
console.log(event.timeStamp);
var minutes=1000 * 60;
console.log(event.timeStamp / minutes);
},false);
例如,可以计算鼠标移动速度,显示每秒移动的像素数量,如:
var previousX, previousY, previousT;
window.addEventListener("mousemove", function(event){
if(previousX !==undefined && previousY !=undefined && previousT !==undefined){
var deltaX=event.screenX - previousX;
var deltaY=event.screenY - previousY;
// deltaD 斜线的长度
var deltaD=Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
// 时间差
var deltaT=event.timeStamp - previousT;
console.log(deltaD / deltaT * 1000);
}
previousX=event.screenX;
previousY=event.screenY;
previousT=event.timeStamp;
});
isTrusted,只读的布尔值,DOM3新增,为true,表示事件是由浏览器(例如用户点击)生成的,为false是由脚本创建的;
initEvent():为通过document.createEvent()创建的事件对象初始化;
document.body.addEventListener("click", function(event){
console.log(event.isTrusted); // true
},false);
oDiv.addEventListener("click", function(event){
console.log(event.isTrusted); // false
},false);
oDiv.click();
var event=document.createEvent("MouseEvents");
event.initEvent("click",true,true);
document.addEventListener("click", function(e){
console.log(e.isTrusted); // false
},false);
document.dispatchEvent(event);
isTrusted属性一般用来检查事件是否受信任,如果是用户操作的,肯定是值得信任的,但是在IE中,除了使用createEvent()方法创建的事件之外,所有事件都是可信任的;如:
function eventHandler(event){
if("isTrusted" in event){
if(event.isTrusted)
console.log("这个:" + event.type + "是值得依赖的");
else
console.log("这个:" + event.type + "是不值得依赖的");
}else{
console.log("你的浏览器不支持");
}
}
document.addEventListener("click", eventHandler, false);
oDiv.click();
IE中的事件对象:
在IE中,要访问event对象有几种方式,取决于指定事件处理程序的方法;在使用DOM0级方法时,事件对象是window对象的一个属性event,如:
var btn=document.getElementById("btn");
btn.onclick=function(){
var event=window.event;
console.log(event); // MouseEvent
console.log(event.type); // click
}
如果使用attachEvent()添加的,那么就会有一个event对象作为参数被传入到事件处理程序函数中; 即使如此,也可以通过window对象来访问event对象;
var btn=document.getElementById("btn");
btn.attachEvent("onclick", function(myevent){
console.log(myevent); // 在IE10及以下 MSEventObj
console.log(myevent.type); // click
var e=window.event;
console.log(e===myevent); // false,指向不同的对象
console.log(e); // MSEventObj
console.log(e.type); // click
console.log(event);
console.log(event===e); // false
console.log(event===myevent); // false
});
如果通过HTML特性指定的事件处理程序,那么可以通过一个名叫event的变量来访问event对象:
<input type="button" id="btn" value="单击" onclick="alert(event.type)"/>
IE中的event对象属性和方法:
IE中的event对象同样也包含与创建它的事件相关的属性和方法;其中很多属性和方法都与DOM的事件对象属性和方法相对应;这些属性和方法也会因为事件类型的不同而不同,以下为共同成员:属性/方法类型读/写说明
IE中的事件处理程序的作用域是根据指定它的方式来确定的,所以不能认为this会始终等于事件目标,因此,最好使用event.srcElement,如:
var btn=document.getElementById("btn");
btn.onclick=function(){
console.log(window.event.srcElement);
console.log(this);
console.log(window.event.srcElement===this); // true
};
btn.attachEvent("onclick", function(event){
console.log(event.srcElement);
console.log(event.srcElement===this); // false
console.log(this===window); // true
});
returnValue属性相当于DOM中的preventDefault()方法,它们的作用都是取消给定事件的默认行为,其默认为true,只要将该属性值设为false,就可以阻止默认行为,如:
var link=document.getElementById("mylink");
link.onclick=function(){
window.event.returnValue=false;
}
// 或者
link.attachEvent("onclick", function(event){
event.returnValue=false;
});
cancelBubble属性与DOM中的stopPropagation()方法作用相同,都是用来停止事件传播的,但由于IE不支持事件捕获,所以cancelBubble只能取消事件冒泡,而stopPropagation() 可以同时取消事件捕获和冒泡;
oDiv.attachEvent("onclick", function(){
window.event.cancelBubble=true;
console.log("div");
});
document.body.attachEvent("onclick", function(){
console.log("body");
});
在eventutil.js中添加跨浏览器事件;
getEvent: function(event){
return event ? event : window.event;
},
getTarget: function(event){
return event.target || event.srcElement;
},
preventDefault: function(event){
if(event.preventDefault)
event.preventDefault();
else
event.returnValue=false;
},
stopPropagation: function(event){
if(event.stopPropagation)
event.stopPropagation();
else
event.cancelBubble=true;
}
应用:
*请认真填写需求信息,我们会在24小时内与您取得联系。