第十五节 JavaScript 事件及事件绑定
1. 事件理解
1.1 什么是事件
事件是用户或浏览器自身执行的某个动作,诸如点击click,
JavaScript制作交互效果,离不开事件。所谓的事件,就是用户的某个行为,能够触发一个函数的执行
1.2 绑定事件绑定:
oDiv.onclick = function(){
}
这个匿名函数,平时永远不会执行,必须等到事件的发生才执行。
响应某个事件的函数叫做事件处理程序,通常我们俗称为事件处理函数,事件的处理程序是以‘on-’开始的,
因此点击click的事件处理程序是onclick
2. DOM0事件绑定
DOM分为级别,DOM的标准分0级、1级、2级、3级,不同的标准,标准一直在升级。
DOM1级没有定义相关的内容,
DOM3级只是在DOM2级基础上增加了更多的时间类型,
所以我们学习的重点还是DOM0级和DOM2的事件绑定
接下来先了解DOM标准中的0级的事件绑定方法:
2.1 DOM0 级事件绑定的用法
语法:
dom.on+type = fn;
-
dom: 绑定事件的对象
-
type: 为事件的类型
-
fn : 为事件触发时执行的函数
// 得到这个box
var oDiv = document.getElementById("box");//事件
oDiv.onclick = function(){
alert("你好,点我干嘛,我烦着呢!!");
}
也可以绑定一个有名的函数,有名函数方便复用。当做事件处理程序
oDiv.onclick = fun; //绑定的是函数,而不是函数的执行,所以不加圆括号。
function fun(){
alert("你好,点我干嘛,我烦着呢!!");
}
原来我们想要一个函数执行,必须调用这个函数,比如fun();
但是现在你知道了,一个函数可以当做一个事件的处理函数,当这个事件发生的时候,函数也能执行了。
2.2 DOM0级绑定事件处理函数的次数
注意:一个dom对象同一个事件类型只能绑定一个事件处理函数
// 得到这个box
var oDiv = document.getElementById("box");
// 第一次绑定点击事件事件
oDiv.onclick = function(){
alert("第一次绑定点击事件事件");
}
//第二次绑定点击事件
oDiv.onclick = function(){
alert("第二次绑定点击事件事件!");
}
我们会发现弹出的是“第二次绑定点击事件”,后面的会把前面的覆盖,就好像给一个对象的属性付了两次值,发生覆盖
双击执行的事件
<div id="box">双击
</div>
<script>
box.ondblclick = function () {
console.log("双击执行");
}
</script>
2.3 DOM0级解除事件绑定
语法:
dom.on+type = null
通过给元素的事件属性上绑定空对象null 来达到解除事件绑定
oDiv.onclick = null;
实现用户只能点击一次
方法一通过判断拦截,缺点事件一直占用着内存,没有被销毁
<div id="box">执行一次
</div>
<script>
var istrue = false;
box.onclick = function () {
if(istrue){
return
}
istrue = true;
console.log("只执行一次");
}
</script>
方法二事件不用了,可以考虑注销,释放内存
<div id="box">执行一次
</div>
<script>
box.onclick = function () {
console.log("只执行一次");
box.onclick = null//this.onclick也可以
}
</script>
3.批量绑定事件和事件排他
3.1 批量绑定事件
- 利用for循环批量绑定事件。
<style>
#ulist li {
float: left;
list-style-type: none;
width: 100px;
height: 100px;
background-color: pink;
margin-right: 10px;
}
</style>
</head>
<body>
<div>
<ul id=ulist>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
</ul>
</div>
<script>
//批量绑定事件
var ali = document.querySelectorAll("#ulist li");
var len = ali.length;
for (var i = 0; i < len; i++) { //for循环包裹添加绑定事件的语句。
ali[i].onclick = function () {
console.log("批量绑定事件");
}
}
</script>
2、批量绑定事件,对序号的影响
批量绑定事件获取索引的问题,for是同步语句,为每个li绑定事件,i最后为6。用户点击时触发相应的li里的函数,函数AO作用域中没有i,到GO中找,所以i为6
方法一添加对象属性保存索引值
<style>
#ulist li {
float: left;
list-style-type: none;
width: 100px;
height: 100px;
background-color: pink;
margin-right: 10px;
}
</style>
</head>
<body>
<div>
<ul id=ulist>
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</div>
<script>
//li调用的onclick,所以每个函数的this就是ali[i],所以给ali[i]添加一个属性aLi[i].index =i
var aLi = document.querySelectorAll("#ulist li");
var len = aLi.length;
for (var i = 0; i < len; i++) {
aLi[i].index = i; //任何一个对象,我们都可以通过点语法来设置新的属性。
aLi[i].onclick = function () {
console.log("批量绑定事件,我是" + this.index + "号");
}
}
</script>
方法二利用闭包,在for循环内部套一层自执行函数 IIFE(该函数有自己的作用域)
<div>
<ul id=ulist>
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</div>
<script>
var aLi = document.querySelectorAll("#ulist li");
var len = aLi.length;
for (var i = 0; i < len; i++) {
(function (j) {//用j接受i传进来的值
aLi[j].onclick = function () {
console.log("批量绑定事件,我是" + j + "号");
}
})(i)
}
</script>
方法二的优化,j能用i代替,变量查询规则会沿着作用域链找
<div>
<ul id=ulist>
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</div>
<script>
var aLi = document.querySelectorAll("#ulist li");
var len = aLi.length;
for (var i = 0; i < len; i++) {
(function (i) {//用j接受i传进来的值
aLi[i].onclick = function () {
console.log("批量绑定事件,我是" + i + "号");
}
})(i)
}
</script>
3.2 对应和排他
排他
方法一添加for循环所有变成pink,然后自己变成blue
<head>
<style>
div#box>div {
display: inline-block;
list-style-type: none;
width: 100px;
height: 100px;
background-color: pink;
margin-left: 20px;
}
</style>
</head>
<body>
<div id="box">
<div>0</div>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</div>
<script>
var adiv = document.querySelectorAll('div#box>div');
var alen = adiv.length;
for(var i=0;i<alen;i++){
adiv[i].index=i;
adiv[i].onclick =function(){
console.log(this.index);
for(var j=0 ;j<alen;j++){//点击之前将所有的恢复成粉色
adiv[j].style.backgroundColor ="pink";
}
this.style.backgroundColor="blue"; //this就是点击的DOM元素
}
}
方法二将每次索引保存起来
<head>
<style>
div#box>div {
display: inline-block;
list-style-type: none;
width: 100px;
height: 100px;
background-color: pink;
margin-left: 20px;
}
</style>
</head>
<body>
<div id="box">
<div>0</div>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</div>
<script>
var adiv = document.querySelectorAll('div#box>div');
var index = 0; // 保存索引
var alen = adiv.length;
for (var i = 0; i < alen; i++) {
adiv[i].index = i;
adiv[i].onclick = function () {
adiv[index].style.backgroundColor = "pink"; //精准定位到上一个div索引,恢复成pink,轮播会用到。性能比for循环好,能不用for就不用
this.style.backgroundColor = "blue";
index = this.index; //上一个点中的索引赋值给index
}
}
</script>
对应:点击第一排的p,第二排对应的p变红:
aBox[this.idx].style.backgroundColor = “red”;
<style>
#box{
margin-bottom: 15px;
}
div#box>div,
div#wrap>div{
display: inline-block;
list-style-type: none;
width: 100px;
height: 100px;
background-color: pink;
margin-left: 20px;
}
</style>
</head>
<body>
<div id="box">
<div>0</div>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</div>
<div id="wrap">
<div>0</div>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</div>
<script>
var abox = document.querySelectorAll('div#box>div');
var awrap = document.querySelectorAll("div#wrap>div");
var index = 0; // 保存索引
var alen = abox.length;
for (var i = 0; i < alen; i++) {
abox[i].index = i;
abox[i].onclick = function () {
awrap[index].style.backgroundColor = "pink"; //精准定位到上一个div索引,恢复成pink,轮播会用到。性能比for循环好,能不用for就不用
abox[index].style.backgroundColor="pink"//自己也排他
awrap[this.index].style.backgroundColor = "blue";
this.style.backgroundColor = "blue";//自己也变蓝色
console.log(this.index);
index = this.index; //上一个点中的索引赋值给index
}
}
</script>
4. DOM2级事件监听
DOM2级做了新的规范,不用on***来绑定监听了,而是使用一个方法
4.1 主流浏览器事件的绑定和解绑方法
-
绑定事件方法
// 绑定事件的方法
addEventListener();add添加,Event事件,Listener监听
它接受三个参数:什么事件、函数、是否监听捕获阶段。
oBox.addEventListener("click",function(){},false);第1个参数:事件名不用写on, click、mouseover 、mouseout
第2个参数:函数可以是匿名函数,也可以是有名函数
第3个参数:布尔值(默认false,可以省略),true表示监听捕获、false表示监听冒泡阶段
示例:
<div id="box">
DOM二级事件
</div>
<script>
function haha(){
console.log("DOM2");
return function(){
console.log(111);
}
}
box.addEventListener('click',haha())//这里的haha是个自执行函数,返回的函数才是事件执行的函数
</script>
oBox.addEventListener("click", function(){
alert("box1被点击,捕获阶段");
}, false)
第三个参数是true,表示监听box1的捕获阶段的单击事件。
-
事件绑定的this指向
oBox.addEventListener('click',function(){
console.log(this);
},false)发现this指向oBox元素自身
-
可以绑定多个事件处理程序
addEventListener可以重复添加相同事件名的事件:
oBox.addEventListener("click", function(){
alert("嘻嘻");
}, false);oBox.addEventListener("click", function(){ alert("哈哈"); }, false);
我们给box1的绑定了两个事件监听,不会覆盖,两个监听的函数都会执行,按照代码执行顺序。
以下写法不是多个,而是同一个事件处理程序
oBox.addEventListener("click", fn, false); oBox.addEventListener("click",fn, false); function fn(){ alert("哈哈"); }
-
解绑事件
使用方法removeEventListener
oBox.addEventListener("click", fn, false);
// 解绑有名函数
oBox.removeEventListener("click",fn, false);
function fn(){
alert("哈哈");
}// 解绑匿名函数 oBox.addEventListener("click",function(){ console.log(11); oBox.removeEventListener("click",arguments.callee, false); }, false);
4.2. 低版本IE的事件的绑定和解绑方法
IE永远是个奇葩,
IE 6、7、8不支持addEventListener()方法,
-
IE 8及以下的事件绑定
需要加on
oBox.attachEvent("onclick",函数)没有第三个参数,也就是说,不能选择监听捕获、冒泡。只能监听冒泡。
box1.attachEvent("onclick", function(){
alert("box1");
});
第一个参数,必须写on,和addEventListener()不一样;
第二个参数,就是事件处理函数
没有第三个参数,只能监听冒泡。所以和on***写法一样。
-
低版本IE的事件监听方法的this指向
oBox.attachEvent("onclick", function(){
console.log(this === window); //true
});低版本IE的事件监听attachEvent:**事件处理函数里面的this,不是触发事件的这个元素,而是window
-
可以绑定多个事件处理程序
同一个事件名的多个监听,会反着执行:
oBox.attachEvent("onclick", function(){
alert(1);
});oBox.attachEvent("onclick", function(){ alert(2); }); oBox.attachEvent("onclick", function(){ alert(3); }); // 弹出3、2、1。
-
解绑事件
使用方法removeEventListener
var oBox = document.getElementById("box");// 绑定事件 oBox.attachEvent("onclick", fn); // 解除事件绑定 oBox.detachEvent('onclick' ,fn); function fn(){ alert("嘻嘻"); }
4.3 封装兼容方法
- DOM2级事件监听兼容
<div id="box">
DOM二级事件
</div>
<script>
function addEvent(obj,type,callback){
if(obj.addEventListener){ //主流浏览器,得到函数
obj.addEventListener(type,callback,false); //主流就执行这个函数,传参
}else if(obj.attachEvent){ //谷歌是undefined IE低版本中是函数
obj.attachEvent("on" + type,function(){ //IE绑定事件要加on,所以拼接
callback.call(obj);
});
}else{ //只支持DOM0级绑定事件
obj["on" + type] = callback;
}
}
addEvent(box,'click',function(){
console.log(111);
})
</script>
上面我们学习的就是一些理论知识,总结一下:
4.4 DOM2级事件的绑定和解绑罗列
-
事件监听的兼容问题
1.IE8以上主流浏览器
dom.addEventListener(type,fn,false)
this指向dom本身- IE8及以下
dom.attachEvent(‘on‘+type,fn)
this指向window
- IE8及以下
-
解绑事件处理函数
-
IE8以上主流浏览器
dom.removeEventListener(type,fn,false) -
IE8及以下
dom.detachEvent(‘on’+type,fn)
5. 事件的分类
5.1 鼠标事件
onclick 点击鼠标左键触发
oncontextmenu 点击鼠标右键触发(浏览器有默认的右键行为)不常用
ondblclick 双击鼠标左键触发
onmousedown 鼠标任意键按住时触发
onmouseup 鼠标任意键抬起时触发
onmouseenter` 鼠标进入元素时触发
onmouseleave 鼠标离开元素时触发
onmouseover 鼠标进去元素时触发
onmouseout 鼠标离开元素时触发
onmousemove 鼠标在元素上移动触发 ===>持续触发
注意:
onclick = onmousedown + onmouseup
<style>
.box{
width: 100px;
height: 100px;
background-color: red;
}
</style>
</head>
<body>
<div class="box">
我是盒子
</div>
<script>
var obox =document.querySelector(".box")
obox.onmouseenter=function(){
console.log("onmouseenter");
obox.style.height="200px";
obox.style.backgroundColor="pink"
}
console.log(getComputedStyle(obox).backgroundColor);//获取元素样式属性
console.log(window.innerWidth);//获取窗口尺寸
</script>
5.2 滚轮事件
onmousewheel 鼠标滚轮在元素上滚动时触发(IE+chrome)
DOMMouseScroll 鼠标滚轮在元素上滚动时触发(firefox)
5.3 键盘事件
onkeydown 按住键盘上任意键触发 ==>持续触发
onkeypress 按住键盘上部分键触发 ==>持续触发
onkeyup 键盘上按键抬起时触发
5.4 资源事件
onload 页面或者图片加载完成时触发
5.5 window事件
onresize 在窗口大小改变时触发
onscroll 在页面滚动的时候触发
5.6 焦点事件
onfocus 得到焦点
onblur 失去焦点