【学习前端第三十二课】DOM事件

本文详细介绍了DOM事件的概念,包括其在面向对象中的作用,0级DOM事件的分类、绑定方式,事件对象的结构,事件冒泡与事件委托的原理,以及this关键字在事件中的指向。还探讨了如何控制元素的响应和阻止默认行为。
摘要由CSDN通过智能技术生成

DOM事件

在面向对象当中,其实有三个点存在

1、属性:用于描述对象

2、方法:对当前对象使用这个方法操作它

3、事件:用于交互,事件是会产品影响(结果)

DOM中的事件是指DOM的交互行为,可以于DOM产生交互的向主要两个

1、DOM与做用域进行事件交互

2、DOM与系统进行事件交互

事件是DOM对象里面的一个特殊属性,它需要经过一定的条件触发,普通属性后面跟的都是属性值,而事件作为一个特殊属性它接收属性值是一个function,或者直接写一个表达式也可以

<input type="button" onclick="console.log('hello world')" value="点我">
<button onclick="sayHello()">再来点我</button>
<script type="text/javascript">
    function sayHello(){
        console.log("hello world");
    }
</script>

用户触发事件,事件调用方法

按照w3c的标准,DOM事件被划分成两个级别

0级DOM事件

这是一个基本DOM事件,0级事件本质上来讲就是DOM对象的一个属性,只是这个属性比较特殊,这些属性都是有一些共同的特点

1、这些属性都是on开头

2、这些属性的属性值一般都是一个function

在0级事件里面,我们的事件又可以大致分为以下几类

1、鼠标事件

2、键盘事件

3、文档事件

4、其他事件

现在我们就来学习这些事件

在学习之前,我们要先要学会事件的使用,也就是事件的绑定

事件的绑定

第一种绑定方式

<input type="button" onclick="console.log(this)" value="点我">

当我们用鼠标去点击上面的按钮时,就会触发 onclick 事件,这是事件就会调用后面的方法,运行console.log打印操作

在上面的代码里面,我们的this指向的是这个按钮,这就是说明一个情况,console.log这个方法在调用的时候是DOM对象在调用,而不是用户在调用,用户仅仅是触发了onclick点击事件而已

第二种绑定方式

<button onclick="sayHello()">再来点我</button>
<script type="text/javascript">
    function sayHello(){
        console.log("hello world");
    }
</script>

上面的sayHello方法是我们自定义的方法,然后通过将方法赋值给触发事件的方式来绑定事件

第三种绑定方式

<button id="btn1">第三种绑定方式</button>
<script>
var btn = document.querySelector("#btn1");
			
function abc(){
    console.log("haha");
}
//这里注意:赋值的时候赋的是方法体,而不是方法结果,因为现在方法的调用不再是它自己,而是事件
btn.onclick = abc;
</script>

上面的赋值过程,我们现在还可以用面向对象的基础来完成,也就是匿名函数

btn.onclick = function(){
    console.log(this);
	console.log("haha");
}

上面的三种方法,第三种情况适合对于元素的批量绑定

<ul class="ul1">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
</ul>
<script type="text/javascript">
    //请给以上li绑定一个事件
    var liList = document.querySelectorAll(".ul1>li");
    for(var i = 0;i < liList.length;i++){
        liList[i].onclick = function(){
            this.classList.toggle("active");
        }
    }
</script>

0级DOM事件列表

1、onclick 鼠标点击事件

2、ondblclick 鼠标双击事件

3、onmousemove 鼠标移动事件

4、onmousedown 鼠标按下事件

5、onmouseup 鼠标松开事件

补充,鼠标的点击事件其实就是鼠标按下和鼠标松开的集合体

6、onmouseenter 鼠标进入事件

7、onmouseleave 鼠标离开事件

补充一点:以上两个事件是很老的事件,这个两个事件是不支持后期的【事件冒泡】

8、onmouseover 鼠标进入事件

9、onmouseout 鼠标离开事件

补充:这两个事件可以形成一组事件,它是上面6,7的替代,这两个事件支持【事件冒泡】

10、onmousewheel 鼠标中间滚动事件

11、onkeydown 键盘按下事件

12、onkeyup 键盘松开事件

13、onkeypress 键盘敲击事件

补充:onkeypress于onkeydown很类似,但是也有区别,onkeydown可以捕捉任意按键,但是onkeyress不能捕捉功能键,比如 ctrl、alt、Fn、home、end、F1-F12都不行

14、onload 加载事件

15、onerror 加载错误事件

16、oninput 输入框输入的时候触发的事件

17、onfocus 表单元素获取光标的时候触发的事件(获取焦点)

18、onblur 表单元素失去焦点

19、onchange 表单里面的值改变的时候触发的事件

20、onsubmit 表单被提交的时候触发的事件

21、onreset 表单被重置时触发的事件

22、oncontextmenu 右键菜单事件

23、onscroll 滚动条滚动的时候触发的事件

0级事件批量绑定

场景: 现在页面上有10个按钮,我们希望对这10个按钮都绑定一个onclick事件,每个按钮点击的时候,在控制台打印当前按钮的序号,怎么实现?

<button class="btn1" type="button">0</button>
<button class="btn1" type="button">1</button>
<button class="btn1" type="button">2</button>
<button class="btn1" type="button">3</button>
<button class="btn1" type="button">4</button>
<button class="btn1" type="button">5</button>
<button class="btn1" type="button">6</button>
<button class="btn1" type="button">7</button>
<button class="btn1" type="button">8</button>
<button class="btn1" type="button">9</button>

将上面的按钮批量绑定

var btns = document.querySelectorAll(".btn1");
for(var i = 0;i < btns.length;i++){
    btns[i].onclick = function(){
        console.log(btns[i].innerText);
    }
}

注意:上面的写法是错误的, 因为for循环已经执行完毕,i的值已经固定成10了,这个时候当我们在去触发事件,事件再调用方法的时候,方法里面的要调用的i的值就是10,所以实际执行的是 btns[10] , 但是集合里面没有索引值为10个这个元素,所以就错了

要解决以上的问题,以下两种方式

第一种:通过this关键字解决

var btns = document.querySelectorAll(".btn1");
for(var i = 0;i < btns.length;i++){
    btns[i].onclick = function(){
        console.log(this.innerText);
    }
}

这里注意,是用户触发了事件,事件再调用方法,所以事件方法里面的this指向的是当前DOM对象

第二种:通过闭包函数的立即执行

var btns = document.querySelectorAll(".btn1");
for(var i = 0;i < btns.length;i++){
    btns[i].onclick = (function(j){
    	return function(){
    		console.log(btns[j].innerText);
    	}        
    })(i);
}

0级事件中的this指向

我们学习过三种0级事件的绑定方式

1、直接在事件的后面写js代码

2、在事件的后面写调用方法名

3、直接把方法赋值给DOM的事件上面

第一种方式

<button type="button" onclick="console.log(this)"></button>

这个时候this指向的是当前的DOM对象(button)

第二种方式

<button type="button" onclick="abc()"></button>
<script>
	function abc(){
		console.log(this);
	}
</script>

注意:这种情况下this指向的是window对象

问题:我们能不能在这种情况下改变this 的指向,让它指向当前的DOM对象

我们可以通过call/apply的调用,来改变this的指向

<button type="button" onclick="abc.call(this)"></button>
<script>
	function abc(){
		console.log(this);
	}
</script>

第三种方式

<button type="button" id="btn1"></button>
<script>
var btn1 = document.querySelector("#btn1");
btn1.onclick = function(){
    console.log(this);
}
</script>

事件对象event

事件对象是所有事件都具备的,当用户触发事件的时候,事件会调用方法,事件在调用方法的过程当中会向当前的方法内部注入一个参数,这个参数就是事件对象参数event

获取事件对象

获取事件对象参数三种方式

第一种方式

<button type="button" onclick="console.log(event)">按钮</button>

第二种方式

<button type="button" onclick="abc(event)"></button>
<script>
	function abc(event){
		console.log(event);
	}
</script>

第三种方式

<button type="button" id="btn1"></button>
<script>
var btn1 = document.querySelector("#btn1");
btn1.onclick = function(e){
    e = event || window.event;  //兼容性写法,保证我们在不同的浏览器里面都可以正确的获取到事件对象
}
</script>

上面获取事件对象方式中要注意一下,浏览器不同会造成我们获取event对象的时候代码不太一样,谷歌核心的浏览器是会像事件方法中注入event参数,而火狐和IE不会注入这个参数,它会直接附加在window对象上面,所以我们需要 event = event || window.event; 这种方式来获取事件对象

分析事件对象

mouseEvent事件
  • 1、altkey : 事件触发时是否按下了alt键
  • 2、ctrlkey:事件触发时是否按下了ctrl键
  • 3、shiftkey:事件触发时是否按下了shift键
  • 4、button:代表当前鼠标事件是由哪个键触发的,0代表鼠标左键,1代表鼠标中键,2代表鼠标右键
  • 5、clientX / clientY :鼠标距离浏览器左上的横纵坐标
  • 6、screenX / screenY :鼠标距离屏幕左上角的横纵坐标
  • 7、X / Y:这两个属性于clientX / clientY保持一致,只是浏览器兼容性的问题,如果想要获取坐标 var x = event.X || event.clientX
  • 8、type:当前事件类型

keyboardEvent事件

1、keyCode:触发事件时的按键编码,它不区别大小写,也就是A和a按键编码是一样的,都是65

2、key:触发事件时的按钮内容

3、repeat:当前的键盘事件是否时上一次事件没有松开以后自动触发的

0级事件的特点

0级事件是DOM中最基本的事件

1、它是以on开头

2、它的属性值一般是一个function

3、0级事件不能多次赋值,多次赋值,后面的会把前面的盖掉

4、0级事件会进行事件传播,但是传播方向不可控【事件的传播分别两种,分别是事件冒泡和事件捕获】

场景一:事件的多次赋值

<button type="button" onclick="console.log('这是第一个方法')" id="btn">按钮</button>
<script type="text/javascript">

    var btn = document.querySelector("#btn");
    function abc(){
        console.log("这是方法abc");
    }
    btn.onclick = abc;

    btn.onclick = function(){
        console.log("这又是一个方法")
    }
</script>

这个时候我们看到上面的onclick赋值了多次,但是只会以最后一次为主,0级事件如果想清除,需要给当前事件赋值一个null

场景二:事件的传播行为

一个DOM对象上面的事件会传播给另外一个DOM对象

<div class="div1">
    <button type="button" id="btn1">按钮</button>
</div>
<script type="text/javascript">
    var div1 = document.querySelector(".div1");
    var btn1 = document.querySelector("#btn1");
    div1.onclick = function(){
        console.log("我是div1");
    }
    btn1.onclick = function(){
        console.log("我是btn1");
    }
</script>

上面的代码中,我们点击div1中的btn1按钮的时候,我们发现两个事件都被触发了,这就说明了一点,内部按钮btn1的onclick事件行为传递给了外面元素div1的onclick上面去了,这种现象我们就叫事件冒泡

事件冒泡

它指的是由内向外进行传播

取消事件冒泡
event.cancelBubble = true;   //取消事件冒泡
event.stopPropagation();     //停止事件的传播
事件的触发者与绑定者
div1.onclick = function(event){
    event = event || window.event;
    console.log("target",event.target);
    console.log("currentTarget",event.currentTarget);
}

上面的代码我们点击了btn1这个按钮,这个按钮本身是没有绑定事件的,但是它会冒泡到外面div1上面去,外部的div1上面是有绑定事件的,所以btn1的点击行为传播到了父级的div1上面,因此触发绑定在div1上面的事件,事件就会调用绑定在div1上面的事件方法

这里,我们理清楚,也就是说btn1是触发,div1绑定

target 指事件的触发者

currentTarget 指的是事件的绑定者

事件冒泡实现事件委托

我们先来看一下代码:

<ul class="ul1">
    <li>1</li>
    <li class="active">2</li>
    <li>3</li>
    <li class="active">4</li>
</ul>
<button type="button" onclick="addNewLi()">新添加一个li</button>
<script type="text/javascript">
    //bindLiEvent给ul1中的li批量绑定onclick事件,并赋值事件方法
    function bindLiEvent(){
        //获取到ul1中所有的li
        var lis = document.querySelectorAll(".ul1>li");
        //遍历所有的li,进行事件的绑定
        for(var i = 0;i < lis.length;i++){
            //每一次循环给一个li绑定一个单击事件
            lis[i].onclick = function(){
                //单击事件赋值一个在控制台打印自己元素内的文本内容的事件方法
                console.log(this.innerText);
            }
        }
    }
    //在这里先执行一遍,给默认存在的4个li绑定事件
    bindLiEvent();

    //addNewLi给ul1里面的后面添加新的li
    function addNewLi(){
        //创建一个li元素
        var newLi = document.createElement("li");
        //给新创建的li元素添加文本内容
        newLi.innerText = "新增的项";
        //获取ul1,然后给ul1里面的后面添加新建的带文本内容的li
        document.querySelector(".ul1").appendChild(newLi);
        //执行bindLiEvent
        bindLiEvent();
    }
</script>

在上面的代码里面,我们每次添加一个新的li之后,都需要重新执行一遍事件绑定,这样很消耗性能

我们尝试进行一下性能优化

我转换思考一下,能否把这个事件绑定在li的父级ul1上面,然后让里面的元素都通过事件冒泡来执行外边绑定的事件

//我们把事件绑定在ul1这个元素上面
//ul1的内部元素的所有事件最后都会冒泡传递到ul1上面
var ul1 = document.querySelector(".ul1");
ul1.onclick = function(event){
    event = event || window.event;
    //target指向是你当前点击的这个li
    console.log(event.target.innerText);
}
function addNewLi(){
    //创建一个li元素
    var newLi = document.createElement("li");
    //给新创建的li元素添加文本内容
    newLi.innerText = "新增的项";
    //获取ul1,然后给ul1里面的后面添加新建的带文本内容的li
    document.querySelector(".ul1").appendChild(newLi);
}

上面的代码就是最基本的事件委托代码,onclick事件本来应该是绑定在li上面的,但是现在委托给它的父级元素ul进行绑定,然后利用事件冒泡原理进行传递,这种现象我们就叫事件委托

现在我们想让指定的元素成为触发者,只有点击指定的元素才会触发事件,那么这里怎么判断触发者是指定的元素,这里可以使用DOM里面的一个API方法 matches() 来完成判断

var ul1 = document.querySelector(".ul1");
ul1.onclick = function(event){
    event = event || window.event;
    if(event.target.matches("li.active")){
        //target指向是你当前点击的这个li
        console.log(event.target.innerText);
    }				
}
事件委托中的this

根据对象调用方法的this指向原则,方法里面的this指向当前调用这个方法的对象,而这个方法又是绑定在事件绑定者身上,所以事件委托中的this指向的是事件的绑定者

事件先于响应

有些html标签在经过JavaScript的处理之后,还是会做除一些响应,比如a标签

<a href="https://www.baidu.com" id="a1">百度一下</a>
<script type="text/javascript">
    var a1 = document.querySelector("#a1");
    a1.onclick = function(){
        alert("hello world");
    }
</script>

在上面的代码中,当我们点击a标签的时候,它会执行onclick事件,然后再去执行a标签的响应操作跳转页面

我们可以再事件当中取消这个响应操作。只需要再事件方法中返回一个false就可以了

a1.onclick = function(){
    alert("hello world");
    return false;
}

同样的,我们也可以通过return false来取消表单的重置按钮的重置功能

<form action="">
    <input type="text">
    <input type="text">
    <button type="reset" id="btn">重置</button>
</form>
<script type="text/javascript">
    var btnReset = document.querySelector("#btn");
    btnReset.onclick = function(){
        return false;
    }
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值