Web前端Javascript笔记(5)事件
1. 什么是事件:事件是指发生并得到处理的操作
JavaScript中的事件是由访问web页面的用户引起的一系列操作,例如,用户的点击操作,JavaScript中有两种事件模型:内联模型,脚本模型。
内联模型:是一种传统简单的事件处理方法,在内联模型中,事件处理函数是HTML标签的一个属性,用于处理指定事件。特点:是和html代码混写在一起的。
脚本模型:将事件绑定与HTML代码分离开来:
事件的绑定方式:内联模式,脚本模式
在开发中,推荐使用外联(脚本)模式,这样可以将HTML于CSS完全分离
事件类型:
1. 鼠标事件
click: 单击
dblclick:双击
mouseover:鼠标移入,在经过元素子节点的时候也会触发
mouseout:鼠标移出
mousemove: 鼠标移动 (不停的触发)
mousedown:鼠标按下
mouseup:鼠标抬起
mouseenter: 鼠标移入 ,在经过元素子节点的时候不会触发
mouseleave: 鼠标移除
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script rel="script" src="../JavaScript/tool.js"></script> <script> window.onload = function(){ let btn = $("btn1"); btn.ondblclick = function () { alert("double click"); }; btn.onmouseover = function () { this.style.background = "#996e27"; }; btn.onmouseout = function () { this.style.background = "white"; }; let cnt = 0; let box = $("box"); box.onmousemove = function () { this.innerHTML = cnt++; } } </script> <style> #box{ width: 200px; height: 200px; background: red; } </style> </head> <body> <button id="btn1">按钮</button> <div id="box">0</div> </body> </html>
效果如下所示:
2.键盘事件(一般绑定在表单元素或者window)
keydown:键盘按下,如果不松开的话,会一直触发事件
keyup:键盘抬起
keypress:键盘按下,只支持字符键
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script rel="script" src="../JavaScript/tool.js"></script> <script> window.onload = function(){ let i = 0; window.onkeydown = function () { document.title = (i++).toString(); }; window.onkeyup = function () { document.title = "抬起" }; window.onkeypress = function (key) { // 传入的参数:可以得到具体的按键值 alert(key.code); } } </script> </head> <body> </body> </html>
3.HTML事件
a. window事件
load:当页面加载完毕后会触发的事件
unload:当页面解构的时候会触发的事件,例如刷新页面,或者关闭页面 ,只支持IE浏览器
scroll:页面滚动的时候触发事件
resize:窗口大小发生变化的时候触发的事件
b. 表单事件
blur : 失去焦点
focus :获得焦点
select:当在输入框内选中文本的时候会触发的事件
change: 当对输入框的文本进行修改且失去焦点的时候会触发事件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script rel="script" src="../JavaScript/tool.js"></script> <script> window.onload = function(){ let input_tag = $("username"); input_tag.onblur = function(){ alert("失去焦点"); }; input_tag.onfocus = function () { alert("获得焦点"); }; input_tag.onchange = function () { alert("内容修改"); }; input_tag.onselect = function () { alert("内容选中"); }; } </script> </head> <body> <input id="username" type="text" placeholder="请输入用户名"> </body> </html>
【注】下面两个自能添加到form元素上
submit: 当点击submit上的按钮时才能出发
reset: 当点击reset上的按钮时才能出发
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script rel="script" src="../JavaScript/tool.js"></script> <script> window.onload = function(){ let form = $("userInfo"); let input_box = form.firstElementChild; form.onsubmit = function () { if(!input_box.value){ alert("用户名不能为空"); } else { alert("注册成功"); } }; form.onreset = function () { input_box.value = ""; alert("重置") }; } </script> </head> <body> <form id="userInfo"> <input type="text" placeholder="请输入"> <input type="submit"> <input type="reset"> </form> </body> </html>
事件对象:
在上述的事件绑定的过程中,当元素与标签之间的事件绑定一旦完成的时候,系统会自动生成一个事件对象,当事件触发的时候,系统会去调用相应的事件函数,此时,系统会将事件对象当作第一个参数传入。
例如:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script rel="script" src="../JavaScript/tool.js"></script> <script> function show(){ alert(arguments.length); alert(arguments[0]); } window.onload = function(){ let button_tag = $("btn"); button_tag.onclick = show; }; </script> </head> <body> <button id="btn">按钮</button> </body> </html>
例如,在触发按钮事件之后,系统会调事件函数show()(show函数只能由系统调用),可以在show()函数中输出函数参数,可以看到,系统给show()函数传入了一个参数:
可以看到传入的是一个MouseEvent事件对象。
可以在函数申明中定义一个形参,用来接收系统传入的参数,但是此方法只有在IE8以上的浏览器中才兼容,还有一种方法,可以在定义的函数中通过window.event拿到系统传入的参数,所以可以写一个兼容不同版本浏览器的函数:
<script> function show(ev){ let e = ev || window.event; alert(e); } window.onload = function(){ let button_tag = $("btn"); button_tag.onclick = show; }; </script>
事件对象属性和方法:
a. 鼠标事件对象:
button: 表示按下的是鼠标的哪个键 0 1 2 = 【左,中,右】
获取当前鼠标位置:三种方法:(原点位置不一样)
clientX, clientY 原点位置为可视窗口的左上角,即使页面滚动了,参考原点依然是左上角的可视区域
pageX, pageY 原点位置为页面的左上角,页面滚动,相应的y坐标也会增加
screenX, screenY 原点位置为电脑屏幕的左上角,即使浏览器出了电脑屏幕,坐标的参考原点依然为屏幕左上角
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script rel="script" src="../JavaScript/tool.js"></script> <script> window.onload = function () { document.onmousedown = function (ev) { // 鼠标按下的事件 let e = ev || window.event; // 获取事件对象 alert(e.button); // 获取鼠标的按键 alert(e.clientX + "," + e.clientY); alert(e.pageX + "," + e.pageY); alert(e.screenX + "," +e.screenY); }; } </script> </head> <body> </body> </html>
案例:
可以跟随鼠标移动的提示框
所以需要实现的是:
1. 鼠标移入,展现出提示框
2. 鼠标移动,提示框随着鼠标移动
3. 鼠标移出,提示框消失
步骤:
1. 先给a标签添加鼠标移入和移除事件,再添加鼠标移入事件。
2. 在获取到鼠标的当前坐标之后,需要给坐标添加一定量的偏置,在把偏置后的坐标作为div的位置,因为div的层级高于a标签,所以如果不偏置,鼠标在div上时,就相当于移出了a标签,这样就会反复触发mouseover和mouseout事件。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script rel="script" src="../JavaScript/tool.js"></script> <script> window.onload = function () { let tag_a = document.getElementsByTagName("a"); // 所有的a标签 let content_box = $("msg"); let content_arr = ["Go for html", "go for python", "go for C++"]; for (let i=0; i<tag_a.length; i++) { tag_a[i].index = i; tag_a[i].onmouseover = function () { content_box.style.display = "block"; content_box.innerHTML = content_arr[i]; }; tag_a[i].onmouseout = function () { content_box.style.display = "none"; }; tag_a[i].onmousemove = function (position) { let pos = position || window.event; // 获取事件对象 let cord_x = pos.clientX + 5; // 添加5像素的偏置量 let cord_y = pos.clientY + 5; content_box.style.left = cord_x + "px"; content_box.style.top = cord_y + "px"; }; } } </script> <style> a{ font-size: 25px; color: blue; display: block; border: none; /*width: 200px;*/ /*height: 100px;*/ margin-left: 30px; margin-top: 100px; width: 50px; } #msg{ width: 200px; height: 80px; border: 1px solid black; display: none; background: gray; position: absolute; } </style> </head> <body> <a href="#">Html</a> <a href="#">python</a> <a href="#">c++</a> <div id="msg"></div> </body> </html>
事件对象属性:
shiftkey : 按下shift键时为true, 否则为false
altkey:按下alt键为true,否则为false
ctrlkey:
metakey:windows下为windows键
键盘事件中的属性:
keyCode也需要兼容
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script rel="script" src="../JavaScript/tool.js"></script> <script> window.onload = function () { window.onkeydown = function (ev) { let e = ev || window.event; alert(e); // 获取键码,需要考虑不同浏览器的兼容问题 let which = e.which || e.keyCode; alert(which); } } </script> </head> <body> </body> </html>
对前面的内容发布的程序进行修改,添加快捷键,在输入框中输入内容,按下ctrl+enter键,也可以发布内容:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script rel="script" src="../JavaScript/tool.js"></script> <script> window.onload = function () { let input_tag = $("input_text"); let bottom_section = $("bottom"); $("add").onclick = function () { let input_content = input_tag.value; if(!input_content){ alert("请输入内容"); } else{ // 开始创建节点 let node = document.createElement("div"); let text_node = document.createTextNode(input_content); let btn_node = document.createElement("button"); let btn_text_node = document.createTextNode("x"); btn_node.appendChild(btn_text_node); node.appendChild(text_node); node.appendChild(btn_node); node.style.background = randomColor(); bottom_section.appendChild(node); input_tag.value = ""; // 清空输入框 updateItemsButtons(); } }; $("delete").onclick = function () { let last_node = bottom_section.lastChild; bottom_section.removeChild(last_node); updateItemsButtons(); }; $("clone").onclick = function () { let last_node = bottom_section.lastChild; let clone_node = last_node.cloneNode(true); // 深拷贝 bottom_section.appendChild(clone_node); updateItemsButtons(); }; function updateItemsButtons() { // 对每条记录上的删除按钮绑定函数 let child_nodes = bottom_section.children; // 只获取div元素节点 let btn_arr = []; for(let i=0; i<child_nodes.length; i++) { btn_arr.push(child_nodes[i].firstElementChild); //console.log(child_nodes[i].children); } // 对标签绑定事件函数 for (let i=0; i<btn_arr.length; i++) { // console.log(btn_arr[i]); btn_arr[i].index = i; btn_arr[i].onclick = function () { bottom_section.removeChild(child_nodes[this.index]); } } } input_tag.onkeydown = function (ev) { // 给输入框添加快捷键 let e = ev || window.event; let key_code = e.keyCode || e.which; // 判断回车键 if(e.ctrlKey && key_code===13) { $("add").onclick(); } } } </script> <style> #container{ width: 200px; border: 1px solid black; } #top{ width: 100%; height: 30px; } #top input{ height: 20px; line-height: 30px; margin: 0 auto; } #middle{ width: 100%; height: 50px; border: none; display: flex; flex-direction: row; justify-content: space-around; background: #0f6674; } #middle button{ /*width: 25%;*/ height: 50%; align-self: center; /*margin-top: 10px;*/ } #bottom{ } #bottom div{ height: 25px; position: relative; } #bottom div button{ position: absolute; top: 1px; right: 2px; } </style> </head> <body> <div id="container"> <div id="top"> <input type="text" id="input_text" placeholder="请输入内容"> </div> <div id="middle"> <button id="add">添加</button> <button id="delete">删除</button> <button id="clone">克隆</button> </div> <div id="bottom"> <!--<div>content<button>x</button></div>--> </div> </div> </body> </html>
效果如下所示:
事件冒泡和触发对象:
事件属性target表示触发对象,只有IE8以上的浏览器兼容,需要和window.event.srcElement方法兼容使用
触发对象表示的是这个事件是由谁而触发引起的:,例如下面的div标签:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script rel="script" src="../JavaScript/tool.js"></script> <script> window.onload = function () { $("cox").onclick = function (ev) { alert(this.innerHTML); // 输出1233 // 获取触发对象 let e = ev || window.event; // 获取事件对象 let target = e.target || window.event.srcElement; // 事件对象的target属性表示触发对象 alert(target.innerHTML); } } </script> </head> <body> <div id="cox">1233</div> </body> </html>
上述的两种方法输出的都是1233,但是,实际上this 和 targe实质上是不同的。this指向的是当前的标签,而target指向的是触发事件的标签,这个标签有可能是当前的标签,也可能是当前标签的子标签,例如:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script rel="script" src="../JavaScript/tool.js"></script> <script> window.onload = function () { $("cox").onclick = function (ev) { alert(this.tagName); // 输出1233 // 获取触发对象 let e = ev || window.event; // 获取事件对象 let target = e.target || window.event.srcElement; // 事件对象的target属性表示触发对象 alert(target.innerHTML); } } </script> </head> <body> <ul id="cox"> <li>11111</li> <li>22222</li> </ul> </body> </html>
例如,this.tagName输出的是UL标签,因为UL是事件函数的主人,但是这里的target表示的具体点击的<li>标签,代表的是触发时间函数的那个对象。
事件冒泡:
存在于嵌套的标签中,当嵌套的标签内外都绑定了时间函数的时候,内部的事件函数被触发执行完毕后,外部的标签又会被触发。这就是事件冒泡。
例如,对于下面的三个<div>标签:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script rel="script" src="../JavaScript/tool.js"></script> <script> window.onload = function () { let tags = document.getElementsByTagName("div"); for (let i=0; i<tags.length; i++) { tags[i].onclick = function () { alert(this.id); } } } </script> <style> div{ padding: 30px; } #div1{ background: red; width: 200px; height: 200px; } #div2{ background: green; width: 60%; height: 60%; margin: 0 auto; } #div3{ background: blue; width: 60%; height: 60%; margin: 0 auto; } </style> </head> <body> <div id="div1"> <div id="div2"> <div id="div3"></div> </div> </div> </body> </html>
当点击div2的时候,会触发div2事件函数,之后又会触发div1事件函数。当点击div3的时候,触发div3事件函数,之后又触发div2事件函数,接着又会触发div1事件函数。
事件冒泡又称为事件流:事件由里向外,逐层触发。很多时候,并不想让浏览器发生事件冒泡,阻止事件冒泡的方法有两种:
cancelBubble = True和 stopPropagation(),这些都是事件对象的属性和方法,所以首先需要拿到事件对象:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script rel="script" src="../JavaScript/tool.js"></script> <script> window.onload = function () { let tags = document.getElementsByTagName("div"); for (let i=0; i<tags.length; i++) { tags[i].onclick = function (ev) { let e = ev || window.event; //e.cancelBubble = true; // 阻止事件冒泡 // e.stopPropagation(); // 跨浏览器兼容: stopBubble(e); alert(this.id); } } // 跨浏览器兼容 function stopBubble(e) { if(e.stopPropagation) { e.stopPropagation(); } else{ e.cancelBubble = true; } } } </script> <style> div{ padding: 30px; } #div1{ background: red; width: 200px; height: 200px; } #div2{ background: green; width: 60%; height: 60%; margin: 0 auto; } #div3{ background: blue; width: 60%; height: 60%; margin: 0 auto; } </style> </head> <body> <div id="div1"> <div id="div2"> <div id="div3"></div> </div> </div> </body> </html>
案例练习:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script rel="script" src="../JavaScript/tool.js"></script> <script> window.onload = function () { let divs = document.getElementsByTagName("div"); document.onmousemove = function (ev) { let e = ev || window.event; for (let i=divs.length-1; i>0; i--) { divs[i].style.left = divs[i-1].offsetLeft + "px"; divs[i].style.top = divs[i-1].offsetTop + "px"; } divs[0].style.left = e.clientX + "px"; divs[0].style.top = e.clientY + "px"; }; } </script> <style> *{ margin: 0; padding: 0; } div{ position: absolute; width: 10px; height: 10px; background: black; border-radius: 50%; } </style> </head> <body> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> <div></div> </body> </html>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)