JavaScript 事件

21 篇文章 0 订阅
5 篇文章 0 订阅

1、JavaScript 的事件

JavaScript 中的事件共分为鼠标事件、键盘事件、HTML 事件三大类。

1.1、鼠标事件

鼠标事件,就是需要通过鼠标进行触发的事件。

常用的鼠标事件
事件发生时间
onclick用户单击对象时
ondblclick用户双击对象时
onmouseover鼠标移到某个元素之上时
onmouseout鼠标移出某个元素时
onmousemove鼠标被移动
onmousedown鼠标按键被按下
onmouseup鼠标按键被松开

1.2、键盘事件

键盘事件是指通过按下键盘按键所触发的事件。按下一个按键并抬起的过程,实际上可以分为三个阶段,每个阶段的触发时间如下表所示。

键盘事件
事件发生时间
onkeydown键盘按下去触发
onkeypress键盘按下并松开的瞬间触发
onkeyup键盘抬起时触发

1.键盘事件注意事项

(1)三个事件的执行顺序

键盘事件一共有三种类型。这三种类型是按顺序执行的,依次是 onkeydown、onkeypress、onkeyup。

(2)长按时触发的事件

当长按一个按键时,会不断触发 onkeydown 和 onkeypress,只有按键抬起以后才会触发 onkeyup 事件。

(3)onkeydown / onkeyup 和 onkeypress 的区别

  • onkeypress 只能捕获字母、数字、符号键,不能捕获功能键(如 Enter 键、F1~F12 键等);onkeydown / onkeyup 基本可以捕获所有功能键(特殊键盘的某些按键除外)。
  • 捕获字母键时,onkeypress 可以区分大小写,onkeydown 和 onkeyup 不区分大小写。
  • 捕获数组键时,onkeydown / onkeyup 可以区分主键盘和小键盘,onkeypress 不能够区分。

(4)通常将键盘事件声明在 document 上

在使用键盘事件时,通常会直接将键盘事件监测到 document 上,而且 onkeydown 和 onkeyup 通常监测一个即可。

代码示例如下:

document.onkeydown = function() {
    // 键盘按键按下时触发的函数
}

2.判断键盘按键

在使用键盘事件时,除了需要检测触发的是 onkeydown 还是 onkeyup,更重要的是判断用户按下去的是哪一个按键。

当监测键盘事件时,浏览器会默认将事件因子 e 传入事件触发函数中,事件因子可以通过 keyCode 等属性确认按键 ASCII 码值,进而确定用户按下的是哪一个按键。

判断浏览器按键的第一步是取到事件因子,绝大部分浏览器可以将事件因子通过触发函数传入,但是部分浏览器需要通过 window.event 手动取到。所以,通常使用如下代码兼容所有浏览器。

document.onkeydown = function(e) {
    var evn = e || window.event;
}

取到事件因子后,可以通过事件因子取到用户按键的 ASCII 码值。最常用的方式是 evn.keyCode,但是为了兼容所有浏览器,通常采用如下写法。

var code = evn.keyCode || evn.which || evn.charCode;

以 Enter 键为例,可以判断用户按键是否为 Enter 键。

代码示例如下:

document.onkeydown = function(e) {
    var evn = e || window.event;
    var code = evn.keyCode || evn.which || evn.charCode;
    if (code == 13) {
        alert("您按下了 Enter 键");
    }
}
常用的 ASCII 码值参照表
ASCII 码值按键或含义
0空字符(Null)
13Enter 键
27Esc 键
32空格键
48~57数字键 0~9
65~90大写字母 A~Z
97~122小写字母 a~z
127Delete 键

1.3、HTML 事件

常见的 HTML 事件
事件发生时间
onload文档或图像加载后
onunload文档卸载后,即退出页面时
onblur元素失去焦点
onselect文本被选中
oninput元素在用户输入时触发
onchange内容被改变
onfocus元素获得焦点时
onsubmit表单提交时
onreset重置按钮被单击
onresize窗口被重新调整大小时
onscroll当文档被滚动时发生的事件
ondrag当元素正在拖动时触发的事件
ondragstart当元素开始被拖动的时候触发的事件
ondragover元素被拖动到指定区域的时候触发的事件
ondrop当放置被拖动元素时触发的事件

1.4、event 事件因子

取到事件因子有两种方式,除了键盘事件,还可以在任何事件的触发函数中使用 window.event 取到事件因子对象。

代码示例如下:

<button id="btn">单击我查看事件因子</button>

<script>
    var btn = document.getElementById("btn");
    btn.onclick = function(e) {
        var evn = e || window.event;
        console.log(evn);
    }
</script>

如上述代码所示,给按钮添加的是 onclick 鼠标事件,但依然可以在鼠标事件的函数中查看事件因子。

event 对象常用的属性
属性名说明
keyCode检测键盘事件相对应的 Unicode 字符码
srcElement返回触发事件的元素
type返回当前 event 对象表示的事件名称
button检查按下的鼠标键

x, y

返回鼠标相对于 css 属性中有 position 属性的上级元素的 x  和 y 坐标
clientX, clientY返回鼠标在浏览器窗口区域中的 x 和 y 坐标
screenX,screenY返回鼠标相对于用户屏幕中的 x 和 y 坐标
altKey检查 Alt 键的状态。当 Alt 键按下时,值为 True;否则为 False
ctrlKey检查 Ctrl 键的状态。当 Crtl 键按下时,值为 True;否则为 False
shiftKey检查 Shift 键的状态。当 Shift 键按下时,值为 True;否则为 False
toElement检测 onmouseover 和 onmouseout 事件发生时,鼠标所进入的元素
fromElement检测 onmouseover 和 onmouseout 事件发生时,鼠标所离开的元素

注意:检测鼠标按键的 button 属性仅用于 onmousedown、onmouseup 和 onmousemove 事件。对于其他事件,不管鼠标状态如何,都返回 0 (比如 onclick)。它有 8 个属性值,分别是 0 没按键、1 按左键、2 按右键、3 按左右键、 4 按中间键、5 按左键和中间键、6 按右键和中间键、7 按所有的键。

 

2、JavaScript 的事件模型

在 JavaScript 中,事件的绑定方式被称为“事件模型”。

2.1、DOM0 事件模型

DOM0 事件模型是最早诞生的事件模型,也是最常用的事件绑定方式。DOM0 模型有两种绑定事件的方式,分别是内联模型和脚本模型。

1.内联模型

内联模型又称为“行内绑定”,其绑定事件的方式是直接将函数名作为 HTML 标签某个事件的属性值。

// 基本语法如下
<button onclick="func()">按钮</button>

缺点:违反 W3C 关于 HTML 与 JavaScript 分离的基本原则。

2.脚本模型

脚本模型又称为“动态绑定”,其绑定的方式是通过在 JavaScript 中选中一个节点,并给节点的 onclick 事件添加监听函数。

// 基本语法如下
window.onload = function(){}

document.getElementById("div").onclick = function(){}

优点:实现了 HTML 与 JavaScript 分离,符合 W3C 的基本原则。

缺点:

1)同一节点只能绑定一个同类型事件,如果绑定多次,则只有最后一次生效。

2)一旦绑定事件,无法取消事件绑定。

2.2、DOM2 事件模型

DOM0 绑定事件的两种方式都有其局限性。为了解决 DOM0 事件模型所存在的局限性,DOM2 事件模型应运而生。

1.添加事件绑定

DOM2 事件模型的绑定相对于 DOM0 要稍微复杂一些,并且针对浏览器版本的不同,有两种不同的绑定方式。

1)针对 IE8 之前的浏览器,使用 attachEvent() 进行事件绑定。

// 基本语法如下
var btn = document.getElementById("btn");
btn.attachEvent("onclick", function(){
    // onclick 触发时执行的回调函数
});

其中,attachEvent 接收两个参数。

  • 第一个参数是触发的事件类型,主要事件名称需要用 “on” 开头。
  • 第二个参数是触发事件时执行的回调函数。

2)除 IE8 之外的其他浏览器,统一使用 W3C 规范,使用 addEventListener() 进行事件绑定。

// 基本语法如下
var btn = document.getElementById("btn");
btn.addEventListener("click", function(){
    // click 触发时执行的回调函数
}, true/false);

其中,addEventListener 接收 3 个参数。

  • 第一个参数是触发的事件类型,主要事件名称不需要用 “on” 开头。
  • 第二个参数是触发事件时执行的回调函数。
  • 第三个参数是模型参数,表示事件冒泡或事件捕获,false(默认)表示事件冒泡,true 表示事件捕获。

3)为了能够兼容各种浏览器,可以采用兼容写法进行操作。

// 基本语法如下
var btn = document.getElementById("btn");
if (btn.attachEvent) {
    // 判断浏览器如果支持 attachEvent,就用 attachEvent 进行绑定
    btn.attachEvent;
} else {
    // 如果浏览器不支持 attachEvent,就用 addEventListener 进行绑定
    btn.addEventListener();
}

2.取消事件绑定

DOM2 和 DOM0 相比有一个非常重要的区别,就是使用 DOM2 绑定的事件可以取消事件绑定。如果要取消事件绑定,那么在绑定事件时,回调函数必须使用有名函数,而不能使用匿名函数。

// 基本语法如下
var btn = document.getElementById("btn");
// IE8 之前
btn.attachEvent("onclick", clickFunction);
// 其他浏览器
btn.addEventListener("click", clickFunction, true);

function clickFunction() {
    // 单击事件的回调函数
}

为什么绑定的时候不能使用匿名函数作为回调函数呢?主要原因在于取消事件绑定的时候,语法要求必须传入需要取消的函数名。而匿名函数没有函数名,故无法取消。针对不同浏览器,取消事件绑定也有两种不同方式。

1)针对 IE8 之前使用 attachEvent() 绑定的事件,可以使用 detachEvent() 取消事件绑定。

// 基本语法如下
btn.detachEvent("onclick", 函数名);

2)针对其他浏览器使用 addEventListener() 绑定的事件,可以使用 removeEventListener() 取消事件绑定。

// 基本语法如下
btn.removeEventListener("click", 函数名);

3.DOM2 事件模型的优点

相对于 DOM0 事件模型,DOM2 的优点主要有以下几条:

1)实现了 HTML 与 JavaScript 的分离,符合 W3C 关于内容与行为分离的要求。

2)使用 DOM2 绑定的事件,可以取消事件绑定。

3)使用 DOM2 可以为同一节点添加多个同类型事件,多个事件可以同时生效,而不会被覆盖掉。

 

3、JavaScript 的事件流模型

所谓事件流,就是当一个节点触发事件时,事件会从当前节点流向其他节点,而根据事件流动的方向,事件流模型可以分为事件冒泡和事件捕获。基于事件冒泡,又诞生了一种新的事件绑定方式——事件委派。

3.1、事件冒泡

事件流指页面接收事件的顺序,当一个事件产生时,该事件传播的过程就是事件流。首先介绍事件流模型中的第一种类型——事件冒泡。

1.事件冒泡的概念

当某 DOM 元素触发某事件时,会从当前 DOM 元素开始,逐个触发其祖先元素的同类型事件,直到 DOM 根节点。

事件冒泡示意图

2.触发事件冒泡的情况

在人们接触到的事件绑定方式中,绝大部分都是事件冒泡。详细可以分为如下几种。

1)DOM0 事件模型绑定的事件均为事件冒泡。

2)IE8 之前使用 attachEvent() 添加的事件均为事件冒泡。

3)对于其他浏览器使用 addEventListener() 添加的事件,当第三个参数为 false 或省略时,为事件冒泡。

3.事件冒泡举例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Test</title>

    <style type="text/css">
        #div1 {
            width: 150px;
            height: 150px;
            background-color: blue;
        }
        #div2 {
            width: 100px;
            height: 100px;
            background-color: red;
        }
        #div3 {
            width: 50px;
            height: 50px;
            background-color: yellow;
        }
    </style>

</head>
<body>

    <div id="div1">
        <div id="div2">
            <div id="div3"></div>
        </div>
    </div>
    
<script type="text/javascript">
    document.getElementById("div1").onclick = function () {
        console.log("触发 div1 单击事件");
    }
    document.getElementById("div2").onclick = function () {
        console.log("触发 div2 单击事件");
    }
    document.getElementById("div3").onclick = function () {
        console.log("触发 div3 单击事件");
    }
</script>

</body>
</html>

上述三个 div 为相互嵌套的关系,使用 addEventListener() 添加 click 事件并设为事件捕获,当单击最内层的 div3 时,可以发现三个 div 的 onclick 事件都被触发,并且触发顺序是从祖先元素 div1 开始,依次触发到当前元素 div3。

单击 div3 触发的 onclick 事件(事件冒泡)

3.2、事件捕获

事件捕获与事件冒泡类似,只是在事件流的方向上与事件冒泡恰恰相反。

1.事件捕获的概念

当某 DOM 元素触发某事件时,会从根节点开始,逐个触发其祖先元素的同类型事件,直到当前节点。

事件捕获示意图

 

2.触发事件捕获的情况

相比与事件冒泡,事件捕获只有一种方式能够触发,即 IE8 之外的其他浏览器使用 addEventListener() 添加的事件,当第三个参数为 true 时,为事件捕获。

3.事件捕获举例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Test</title>

    <style type="text/css">
        #div1 {
            width: 150px;
            height: 150px;
            background-color: blue;
        }
        #div2 {
            width: 100px;
            height: 100px;
            background-color: red;
        }
        #div3 {
            width: 50px;
            height: 50px;
            background-color: yellow;
        }
    </style>

</head>
<body>

    <div id="div1">
        <div id="div2">
            <div id="div3"></div>
        </div>
    </div>
    
<script type="text/javascript">
    document.getElementById("div1").addEventListener("click", function () {
        console.log("触发 div1 单击事件");
    }, true);
    document.getElementById("div2").addEventListener("click", function () {
        console.log("触发 div2 单击事件");
    }, true);
    document.getElementById("div3").addEventListener("click", function () {
        console.log("触发 div3 单击事件");
    }, true);
</script>

</body>
</html>

上述三个 div 为相互嵌套的关系,使用 addEventListener() 添加 click 事件并设为事件捕获,当单击最内层的 div3 时,可以发现三个 div 的 onclick 事件都被触发,并且触发顺序是从祖先元素 div1 开始,依次触发到当前元素 div3。

单击 div3 触发的 onclick 事件(事件捕获)

3.3、事件委派

基于事件冒泡诞生了一种新的事件绑定方式——事件委派。

1.事件委派的概念

事件委派也叫事件委托,是将本该添加在节点自身的事件,选择添加到其父节点上,同时委派给当前元素来执行。

2.事件委派的原理

事件委派的原理就是事件冒泡。 由于给多个子元素添加事件,会沿着事件冒泡流触发其父元素的同类型事件,所以可以直接将事件添加在父元素上,并在事件函数中判断单击的是哪一个子元素,进而进行具体操作。

3.原生 JavaScript 实现事件委派

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Test</title>
</head>
<body>

    <ul id="ul">
        <li>Java</li>
        <li>C++</li>
        <li>C#</li>
        <li>JavaScript</li>
    </ul>
    
<script type="text/javascript">
    var ul = document.getElementById("ul");

    ul.onclick = function (e) {
        var evn = e || window.event;
        console.log(evn);
        var target = event.target || event.srcElement;
        console.log(target);
        if (target.nodeName.toLowerCase() === 'li') {
            console.log(target.innerText);
        }
    }
</script>

</body>
</html>

从上述代码可以看到,将本该添加在 li 上面的单击事件,添加在 li 的父节点 ul 上,并在事件函数中取到事件因子,进而通过事件因子取到当前单击的元素。如果单击的元素是 li,则触发操作。

4.事件委派的作用

事件委派有很大用处,主要体现在如下两点:

(1)提高性能

将事件绑定在父节点上,只需要绑定一个事件就可以;而将事件依次添加给子节点,则需要绑定多个事件。因此,事件委派具有更优的性能。

(2)新添加的元素会具有同类型元素的事件

如果使用其他方式绑定事件,当页面新增同类的节点时,这些节点不会获得之前绑定的事件。但是,使用事件委派可以让新添加的元素获得之前绑定的事件。

3.4、阻止事件冒泡

事件委派的原理就是事件冒泡,但并不是所有的事件冒泡都是对开发有利的,实际开发中,大多情况并不想让子元素的事件影响到父元素。因此,阻止事件冒泡的传播也是一种重要方法。

对于阻止事件冒泡的写法,由于浏览器的兼容性问题,存在两种不同的写法。对于 IE8 以前的浏览器,可以将 e.cancelBubble 属性设为 true;对于其他浏览器,则可以调用 e.stopPropagation() 方法。当然也有兼容写法,基本语法如下:

function myParagraphEventHandler(e) {
    e = e || window.event;
    if (e.stopPropagation) {
        e.stopPropagation();
    } else {
        e.cancelBubble = true;
    }
}

3.5、阻止默认事件

除了事件冒泡,还有一种情况存在妨碍开发的问题,那就是某些标签的默认事件。

取消默认事件也有两种常用方式。对于 IE8 之前的浏览器,可以将 e.returnValue 属性设置 false;对于 IE8 以外的浏览器,可以调用 e.preventDefault() 方法。同样,也有兼容写法,基本语法如下:

function eventHandler(e) {
    e = e || window.event;
    if (e.preventDefault) {
        e.preventDefault();
    } else {
        e.returnValue = false;
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值