【JavaScript】事件相关知识详解

news/2024/11/16 23:31:40/

💻 【JavaScript】事件相关知识详解🏠专栏:JavaScript
👀个人主页:繁星学编程🍁
🧑个人简介:一个不断提高自我的平凡人🚀
🔊分享方向:目前主攻前端,其他知识也会阶段性分享🍀
👊格言:☀️没有走不通的路,只有不敢走的人!☀️
👉让我们一起进步,一起成为更好的自己!!!🎁

文章目录

  • 【JavaScript】事件概念、绑定、委托、冒泡和阻止默认行为等
    • 一. 概念
    • 二. 事件绑定
      • (1) DOM 0级 事件
      • (2) DOM 2级 事件
      • (3) 两种事件绑定的方式区别
    • 三. 事件解绑
      • (1) 解绑dom0级事件
      • (2) 解绑dom2级事件
    • 四. 事件对象
    • 五. 鼠标事件对象
      • (1) client
      • (2) page
      • (3) offset
      • (4) 案例
    • 六. 键盘事件对象
    • 七. 事件传播
    • 八. 阻止事件传播
    • 九. 阻止默认行为
    • 十. 事件委托
      • 案例

【JavaScript】事件概念、绑定、委托、冒泡和阻止默认行为等

一. 概念

事件指的是用户和浏览器之间的交互行为。比如:点击按钮、关闭窗口、鼠标移动等。

我们可以为事件来绑定回调函数来响应事件。绑定事件的方式:

  1. 可以在标签的事件属性中设置相应的JS代码。

    <button onclick="js代码。。。">按钮</button>
    
  2. 可以通过为对象的指定事件属性设置回调函数的形式来处理事件。

    <button id="btn">按钮</button>	
    <script>var btn = document.getElementById("btn");btn.onclick = function(){		
    };
    </script>
    

执行事件的步骤

  1. 获取事件源
  2. 注册事件(绑定事件)
  3. 添加事件处理程序(采取函数赋值形式)
<div>123</div>
...
<script>
var a = document.querySelector('div');a.onclick= function(){console.log('aaa');// aaa
}
</script>

二. 事件绑定

(1) DOM 0级 事件

语法:事件源.on事件类型 = 事件处理函数

特点:同一个事件源的同一个事件类型只能绑定一个事件处理函数

<div></div>
<!----分割线---->
div.onclick = function () {console.log("绑定了一个点击事件");
};

(2) DOM 2级 事件

语法:事件源.addEventListener(‘事件类型’, 事件处理函数)

特点:可以同一个事件源的同一个事件类型绑定多个事件处理函数,会按照顺序依次触发

<div></div> 
<!----分割线---->
div.addEventListener("click", function () {console.log("绑定一个点击事件");
});

(3) 两种事件绑定的方式区别

DOM 0级 事件:同一个事件源的同一个事件类型只能绑定一个事件处理函数

如果同一个事件源的同一个事件类型绑定多个事件处理函数则后面的处理函数会进行覆盖前面的处理函数

DOM 2级 事件:可以同一个事件源的同一个事件类型绑定多个事件处理函数,会按照顺序依次触发

三. 事件解绑

(1) 解绑dom0级事件

语法:事件源.on事件类型 = null

<button>解绑dom0级事件</button>
<!----分割线---->
var div = document.querySelector("div");
div.onclick = function () {console.log("绑定0级事件");
};
var btn = document.querySelector("button");
btn.onclick = function () {div.onclick = null;
};

(2) 解绑dom2级事件

语法:事件源.removeEventListener(‘事件类型’, 要解绑的事件处理函数)

注意:如果用dom2级解绑, 绑定的时候的事件处理函数必须要在外面单独定义,用函数名的形式进行绑定

<button>解绑dom2级事件</button>
<!----分割线---->
var div = document.querySelector("div");
var clickFn = function () {console.log("绑定dom2级事件");
};
div.addEventListener("click", clickFn);
var btn = document.querySelector("button");
btn.onclick = function () {div.removeEventListener("click", clickFn);
};

四. 事件对象

当响应函数被调用时,浏览器每次都会将一个事件对象作为实参传递进响应函数中,这个事件对象中封装了当前事件的相关信息,比如:鼠标的坐标,键盘的按键,鼠标的按键,滚轮的方向。

可以在响应函数中定义一个形参,来使用事件对象,但是在IE8以下浏览器中事件对象没有做完实参传递,而是作为window对象的属性保存。

获取事件对象

  • 标准浏览器

在事件处理函数有一个参数,参数就是事件对象

  • IE浏览器

IE浏览器天生有一个事件对象 window.event

// eg:
<div></div>
<!----分割线---->
var div = document.querySelector("div");
// 标准浏览器
div.onclick = function (e) {console.log(e);
};
// IE 浏览器事件对象
div.onclick = function () {console.log(window.event);
};
// 兼容性操作
div.onclick = function (e) {var e = e || window.event;
};

五. 鼠标事件对象

(1) client

光标相对于浏览器可视窗口左上角的坐标点

通俗理解就是:鼠标光标相对于肉眼可以看到的浏览器左上角的坐标点

语法

事件对象.clientX
事件对象.clientY

(2) page

光标相对于文档流左上角的坐标点

通俗理解就是:鼠标光标相对于整个文档左上角的坐标点,就是即使页面向下滑动依然相对于最开始时的左上角坐标点。

语法

事件对象.pageX
事件对象.pageY

(3) offset

光标相对于准确触发事件的元素左上角的坐标点

通俗理解就是:鼠标光标相对于要触发的元素的左上角的坐标点

语法

事件对象.offsetX
事件对象.offsetY

三个鼠标事件对象实例

// eg:
<style>* {margin: 0;padding: 0;
}
div {width: 200px;height: 300px;background-color: pink;margin: 100px;margin-top: 700px;
}
</style><div></div>var div = document.querySelector("div");
div.onclick = function (e) {// 光标相对于 浏览器可视窗口 左上角的坐标点console.log("e.clientX, e.clientY");console.log(e.clientX, e.clientY);console.log("==========================");// 光标相对于 文档流 左上角的坐标点console.log("e.pageX, e.pageY");console.log(e.pageX, e.pageY);console.log("==================");// 光标相对于 准确触发事件的元素 左上角的坐标点console.log("e.offsetX, e.offsetY");console.log(e.offsetX, e.offsetY);
};

(4) 案例

案例1:实时显示鼠标坐标点

<h2>x坐标 <span class="x">0</span></h2>
<h2>y坐标 <span class="y">0</span></h2>
<!----分割线---->  
// 获取元素
var xBox = document.querySelector(".x");
var yBox = document.querySelector(".y");
document.onmousemove = function (e) {var x = e.clientX;var y = e.clientY;// 把 x 和 y 放到span中xBox.innerHTML = x;yBox.innerHTML = y;
};

效果图

请添加图片描述

案例2:鼠标跟随

分析思路

/*案例:鼠标跟随1. 在什么时候触发效果鼠标移入鼠标移出鼠标移动2. 在什么范围触发效果鼠标移入   当前的li鼠标移出   当前的li鼠标移动   当前的li3. 触发的效果是什么鼠标移入   让当前的li里面的p出现        display: block鼠标移出   让当前的li里面的p消失        display: none鼠标移动   p跟着鼠标移动                left top   光标距离准确触发事件的元素的左上角的坐标 offsetX offsetY一个小BUG 当从右向左滑动, 没问题当从左向右滑动, p标签抖动 原因:因为p是li的子元素当光标在p标签身上,也会触发li的效果 (触发了父元素mousemove效果)因为offset 一套 是准确触发事件元素的左上角的坐标点当光标在p身上 , offsetX offsetY获取的是光标距离p左上角的位置 解决:1. 让光标和p之间有个距离2. 让p标签保持一个穿透效果    pointer-events: none;*/
<style>* {margin: 0;padding: 0;}li {list-style: none;width: 400px;height: 40px;border: 1px solid #000;margin-bottom: 10px;position: relative;}ul {margin: 100px;}p {width: 200px;height: 100px;background-color: skyblue;position: absolute;z-index: 999;top: 10px;left: 10px;display: none;/* 禁止p的鼠标效果 */pointer-events: none;}
</style>
<body><ul><li class="box">第1个li<p>第1个li里面的p</p></li><li>第2个li<p>第2个li里面的p</p></li><li>第3个li<p>第3个li里面的p</p></li></ul>
</body>
<script>// 0 获取元素var liList = document.querySelectorAll("li");// 1 遍历  li给每个添加效果liList.forEach(function (li) {// 1-1 鼠标移入li.addEventListener("mouseover", overHandler);// 1-2 鼠标移出li.addEventListener("mouseout", outHandler);// 1-3 鼠标移动li.addEventListener("mousemove", moveHandler);});// 1-1 鼠标移入事件function overHandler() {// 让当前的li里面的p出现// 找到当前的li ===> 关键字 this// 找到li里面的pthis.firstElementChild.style.display = "block";}// 1-2 鼠标移出function outHandler() {// 让当前的li里面的p消失// 当前的li ==> this// 当前的li里面的p this.firstElementChildthis.firstElementChild.style.display = "none";}// 1-3 鼠标移动function moveHandler(e) {// 让 li 里面p 移动// 获取 鼠标指针距离 li的左上角的值var x = e.offsetX;var y = e.offsetY;this.firstElementChild.style.left = x + "px";this.firstElementChild.style.top = y + "px";}
</script>

效果图

请添加图片描述

六. 键盘事件对象

事件对象信息

  1. 按下按个键

按下的是否是组合键

​ 2. 按下的是哪一个按键

事件对象内有一个信息,keyCode

  1. 按下的是否是组合键

在事件对象中有四个信息
shiftKey
ctrlKey
altKey
metaKey
以上四个信息值都是false, 按下的时候是true

<input type="text" name="" id="" />
<!----分割线---->
var inp = document.querySelector("input");
inp.onkeydown = function (e) {// 1.获取键盘编码// console.log(e.keyCode);// 2.获取功能键// console.log(e);// 3.按下的是否是组合键if (e.keyCode === 65 && e.shiftKey && e.ctrlKey) {console.log("同时按下 a + shift + ctrl");}
};

七. 事件传播

当行为发生的时候,会按照 父级 依次向上传递, 直到window

传播的三个阶段

  1. 捕获 从window传递到事件目标的过程
  2. 目标 准确触发事件的元素
  3. 冒泡 从事件目标传递到window的过程

事件流机制

  • 可以在冒泡阶段触发事件,也可以在捕获阶段触发事件
  • 默认是冒泡阶段触发事件
  • 完整过程:捕获 -> 目标 -> 冒泡

触发捕获阶段的事件

addEventListener接受三个参数

addEventListener('事件类型', 事件处理函数, true/false)

true 捕获阶段触发
false 冒泡阶段触发(默认)

事件的冒泡(Bubble)

  • 事件的冒泡指的是事件向上传导,当后代元素上的事件被触发时,将会导致其祖先元素上的同类事件也会触发;
  • 事件的冒泡大部分情况下都是有益的,如果需要取消冒泡,则需要使用事件对象来取消;
  • 可以将事件对象的cancelBubble设置为true,即可取消冒泡。

例子:

元素.事件 = function(event){event = event || window.event;event.cancelBubble = true;
};

八. 阻止事件传播

  1. 什么时候需要阻止事件传播?

当我们的父子级结构都有相同的事件类型,就需要阻止事件传播

  1. 如何阻止事件传播

    语法:

    事件对象.stopPropagation()
    
<div></div>
<button>按钮</button>
<!----分割线----> 
// 点击 按钮 ,div出现
// 点击 document , div消失
var div = document.querySelector("div");
var btn = document.querySelector("button");
// 由于事件冒泡,btn的点击事件会向上冒泡,触发到document
btn.onclick = function(e) {// 阻止事件传播e.stopPropagation();div.style.display = "block";console.log(1);
};
document.onclick = function() {div.style.display = "none";console.log(2);
};

九. 阻止默认行为

常见的默认行为

  • 表单标签提交
  • a标签点击
  • 文本选择
  • 右键

阻止默认行为

语法 :

// 标准浏览器  事件对象.preventDefault()
// 通用 return false

案例:关闭鼠标右键默认弹窗,并设置自己的弹窗。

<style>div {width: 100px;height: 200px;background-color: pink;position: absolute;display: none;}
</style>
<body><div></div>
</body>
<script>var div = document.querySelector("div");// 右键点击document.oncontextmenu = function (e) {// 1-1 本身的弹窗不出现  阻止默认行为e.preventDefault();// 1-2 div出现div.style.display = "block";// 1-3 div的位置和光标的位置一样var x = e.clientX;var y = e.clientY;div.style.left = x + "px";div.style.top = y + "px";};// 2) 左键点击document.onclick = function () {div.style.display = "none";};
</script>

效果图

请添加图片描述

十. 事件委托

把子元素的事件交给父元素来绑定

作用

元素的事件内, 通过事件目标(e.target) 判断准确触发事件的元素

优点

  1. 可以减少操作dom的次数。
  2. 对于后面添加的元素很友好,并对子元素添加事件很有用。

案例

案例1:点击按钮,一次出现5个li,li标签里面有数字, 点击li,背景颜色变为绿色。

<style>* {padding: 0;margin: 0;}li {list-style: none;width: 50px;height: 50px;border: 1px solid #000;text-align: center;line-height: 50px;font-size: 20px;margin: 10px;flex-shrink: 0;background-color: #fff;}ul {padding: 30px;background-color: orange;display: flex;width: 400px;flex-wrap: wrap;}
</style>
<body><button>点击</button><ul><li class="box">li1</li><li class="box">li2</li><li class="box">li3</li><li class="box">li4</li><li class="box">li5</li></ul>
</body>
<script>var btn = document.querySelector("button");var ul = document.querySelector("ul");var count = 6;btn.onclick = function () {var str = "";for (var i = 1; i <= 5; i++) {str += `<li class='box'>li${count}</li>`;count++;}ul.innerHTML += str;};ul.onclick = function (e) {if (e.target.className === "box") {e.target.style.background = "green";}};
</script>

效果图

请添加图片描述

案例2:select下拉

<style>html,body {height: 100%;overflow: hidden;}body,div,form,h2,ul,li {margin: 0;padding: 0;}ul {list-style-type: none;}body {background: #23384e;font: 12px/1.5 "微软雅黑";}#search,#search form,#search .box,#search .select,#search a {background: url(search.jpg) no-repeat;}#search,#search .box,#search form {height: 34px;}#search {position: relative;width: 350px;margin: 10px auto;}#search .box {background-position: right 0;}#search form {background-repeat: repeat-x;background-position: 0 -34px;margin: 0 20px 0 40px;}#search .select {float: left;color: #fff;width: 190px;height: 22px;cursor: pointer;margin-top: 4px;line-height: 22px;padding-left: 10px;background-position: 0 -68px;}#search a {float: left;width: 80px;height: 24px;color: #333;letter-spacing: 4px;line-height: 22px;text-align: center;text-decoration: none;background-position: 0 -90px;margin: 4px 0 0 10px;}#search a:hover {color: #f60;background-position: -80px -90px;}#search .sub {position: absolute;top: 26px;left: 40px;color: #fff;width: 198px;background: #2b2b2b;border: 1px solid #fff;display: none;}#search .sub li {height: 25px;line-height: 24px;cursor: pointer;padding-left: 10px;margin-bottom: -1px;border-bottom: 1px dotted #fff;}#search .sub li:hover {background: #8b8b8b;}
</style>
<body><div id="search"><div class="box"><form><span id="select" class="select">请选择游戏名称</span><a href="javascript:;">搜索</a></form></div><ul id="sub" class="sub"><li>地下城与勇士</li><li>魔兽世界(国服)</li><li>魔兽世界(台服)</li><li>热血江湖</li><li>大话西游II</li><li>QQ幻想世界</li></ul></div>
</body>
<script>// 1 1) 点击span   ul出现select.onclick = function (e) {// 阻止事件冒泡e.stopPropagation();sub.style.display = "block";};// 2. 2) 点击document  ul 消失document.onclick = function () {sub.style.display = "none";};// 3) 通过事件委托的方式 把点击事件添加给ul 获取当前li里面的内容,把内容填到span中sub.onclick = function (e) {// 通过事件目标进行判断   e.target// 判断当前的事件目标是不是li 是的话就执行代码if (e.target.nodeName === "LI") {select.innerHTML = e.target.innerHTML;}};
</script>

效果图

请添加图片描述

案例3:表格即时编辑

<body><table border="1"><tr><td>11111111111111</td><td>11111111111111</td><td>11111111111111</td><td>11111111111111</td><td>11111111111111</td></tr><tr><td>11111111111111</td><td>11111111111111</td><td>11111111111111</td><td>11111111111111</td><td>11111111111111</td></tr><tr><td>11111111111111</td><td>11111111111111</td><td>11111111111111</td><td>11111111111111</td><td>11111111111111</td></tr><tr><td>11111111111111</td><td>11111111111111</td><td>11111111111111</td><td>11111111111111</td><td>11111111111111</td></tr></table>
</body>
<script>var tdList = document.querySelectorAll("td");tdList.forEach(function (td) {td.onclick = function () {// 当td里面有一个input的时候就不需要触发下面的代码// 当td里面没有input的时候就需要触发下面的代码// "td里面没有子元素的时候"  td.children.length === 0if (td.children.length === 0) {var str = `<input type='text' value=${td.innerHTML}>`;td.innerHTML = str;}// 怎么获取输入框td.children[0].onblur = function () {// 输入框失去焦点var value = td.children[0].value;td.innerHTML = value;};};});
</script>

效果图

请添加图片描述

结束语

希望对您有一点点帮助,如有错误欢迎小伙伴指正。
👍点赞:您的赞赏是我前进的动力!
⭐收藏:您的支持我是创作的源泉!
✍评论:您的建议是我改进的良药!
一起加油!!!💪💪💪


http://www.ppmy.cn/news/933726.html

相关文章

《自己动手设计物联网》序 | justjavac

很久之前读过一本关于芯片技术的书籍&#xff0c;在书的前言中作者讲述了一个故事。大意是这位教授在某次讲座中说到&#xff1a;“以后芯片的数量肯定是现在的几十倍&#xff0c;到时候我们都会享受到各种芯片强大的计算能力。” 这时一位听众当场起来反驳他道&#xff1a;“难…

Java设计模式之模板模式

1. 模板模式介绍 1、模板模式即模板方法模式自定义了一个操作中的算法骨架&#xff0c;而将步骤延迟到子类中&#xff0c;使得子类可以不改变一个算法的结构&#xff0c;可以自定义该算法的某些特定步骤&#xff1b; 2、父类中提取了公共的部分代码&#xff0c;便于代码复用&am…

《自己动手设计物联网》已在各大书城有售

号外号外&#xff0c;《自己动手设计物联网》已经在各大书城有售啦~ 购买地址如下&#xff1a; 亚马逊&#xff1a;https://www.amazon.cn/dp/B01IBZWTWW&#xff08;戳阅读原文即可访问&#xff09; 京东&#xff1a;http://item.jd.com/11946585.html&#xff08;复制到浏览器…

没有人能随随便便成功,但没有必要活得像尘埃一样卑微

1. 我敢打赌&#xff0c;你一定对小罗伯特唐尼饰演的钢铁侠印象深刻。这个天赋异禀的纨绔子弟在被恐怖分子袭击后&#xff0c;不断改进升级他的盔甲&#xff0c;然后“躲进去”化身钢铁侠&#xff0c;从而作为一名义务警察来保卫世界和平。不过无所不能、正义凛然的钢铁侠只能…

你还记得那些曾经为腾讯企鹅军团做的贡献吗?

深圳市腾讯计算机系统有限公司成立于1998年11月&#xff0c;居然比我还小七八岁。企鹅军团目前世界500强排名237位&#xff0c;截止今日市值32583.72亿&#xff0c;全球市值排名第8位&#xff0c;而我目前身家好几十块&#xff0c;你们呢&#xff1f; 从最初的移动通讯地位——…

一切的闹闹哄哄,只是他在水帘洞躲避风沙那晚做的一个梦

送同学走之后&#xff0c;我在路边默默的站了有五分钟&#xff0c;突然觉得我无处可去&#xff0c;有一种深入骨髓的悲哀和无奈&#xff0c;然后我就想起了一个命题&#xff0c;“如今的你&#xff0c;何去何从&#xff01;”我不知道为什么会突然想到这样一个命题&#xff0c;…

Ubuntu开机自启动设置

一、创建执行脚本 这里有两个程序所以编写了两个脚本&#xff0c;第一脚本(master.sh)&#xff1a; gnome-terminal -- bash -c "source /home/zyy/anaconda3/bin/activate wood2;cd /home/zyy/pycharmProject/master_program;python main.py > /home/zyy/pycharmProj…

21.Java 抽象类

抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。 由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类 在 Java 中抽象类表示的是一种继承关系,…