JavaScript |(六)DOM事件 | 尚硅谷JavaScript基础实战

学习来源:尚硅谷JavaScript基础&实战丨JS入门到精通全套完整版
笔记来源:在这位大佬的基础上添加了一些东西,欢迎大家支持原创,大佬太棒了:JavaScript |(六)DOM事件 | 尚硅谷JavaScript基础&实战

JavaScript |(六)DOM事件 | 尚硅谷JavaScript基础&实战

  • ❤️ JavaScript 事件对象详解
    • 🧩 事件对象(`event`)
    • 🧩 鼠标事件
      • 📌 `onmousemove` - 监听鼠标移动
    • 🧩 鼠标点击事件
      • 📌 `onclick` - 点击事件
    • 🧩 事件对象在不同浏览器的兼容性
    • 🧩 事件监听的常用方法
  • ❤️事件的冒泡
  • ❤️事件的委派(Event Delegation)
  • ❤️事件的绑定
    • 🧩赋值绑定
    • 🧩addEventListener()
    • 🧩attachEvent()
    • 🧩bind()函数
  • ❤️事件的传播(Event Propagation)
    • 🧩 什么是事件传播?
    • 🧩 事件传播的顺序
    • 🧩 事件捕获阶段(一)
    • 🧩 事件冒泡阶段(二)
    • 🧩 `stopPropagation()` 和 `stopImmediatePropagation()`
      • 🚫 `stopPropagation()`
      • 🚫 `stopImmediatePropagation()`
    • 🧩 `preventDefault()` 阻止默认行为
  • ❤️JavaScript 拖拽实现(不使用 HTML5 Drag & Drop API)
    • 🧩 拖拽的流程
    • 🧩 手动实现拖拽
      • 💡 示例:实现一个可以随意拖动的 `div`
    • 🧩 关键技术点
        • 🔹 1. 记录鼠标相对元素的偏移量
        • 🔹 2. `event.preventDefault()` 取消默认行为
        • 🔹 3. `mousemove` 绑定到 `document`,保证鼠标移动范围
    • 🧩 限制拖拽范围
    • 🧩 拖拽应用
  • ❤️鼠标滚轮事件
    • 🧩火狐滚轮:`DOMMouseScroll`
    • 🧩其他浏览器:`onwheel`🔥
  • ❤️JavaScript 键盘事件(Keyboard Events)
    • 🧩键盘事件类型
    • 🧩键盘事件示例
      • 💡 示例:监听方向键
    • 🧩监听组合键(Ctrl / Shift / Alt)
      • 💡 示例:监听 `Ctrl + S` 进行保存
    • 🧩`event.keyCode` 的常见按键
    • 🧩`event.key` vs `event.keyCode`
    • 🧩限制输入框只能输入数字
  • ⭐️练习:上下左右控制box位置,并可通过Ctrl控制速度

❤️ JavaScript 事件对象详解

事件 是用户和浏览器之间的交互行为,例如:

  • 鼠标事件(点击、移动、滚轮)
  • 键盘事件(按键按下、松开)
  • 窗口事件(加载、关闭、调整大小)

🧩 事件对象(event

当事件触发时,浏览器会自动传递一个事件对象作为参数到事件处理函数中。这个对象包含了当前事件的所有信息(如鼠标位置、键盘按键等)。

📌 兼容性问题(IE8 及以下)

event = event || window.event;

🧩 鼠标事件

📌 onmousemove - 监听鼠标移动

📝 作用:当鼠标在元素上移动时,触发该事件。

📌 示例

document.addEventListener("mousemove", function(event) {console.log("鼠标 X 坐标:" + event.clientX);console.log("鼠标 Y 坐标:" + event.clientY);
});

📌 事件对象属性

属性作用
clientX获取鼠标指针的 水平坐标(相对于可视窗口左上角)
clientY获取鼠标指针的 垂直坐标(相对于可视窗口左上角)
pageX获取鼠标的水平坐标(相对于整个文档左上角)
pageY获取鼠标的垂直坐标(相对于整个文档左上角)
screenX获取鼠标的水平坐标(相对于屏幕左上角)
screenY获取鼠标的垂直坐标(相对于屏幕左上角)

📌 示例

document.addEventListener("mousemove", function(event) {console.log(`clientX: ${event.clientX}, clientY: ${event.clientY}`);console.log(`pageX: ${event.pageX}, pageY: ${event.pageY}`);
});

在这里插入图片描述


🧩 鼠标点击事件

📌 onclick - 点击事件

📌 示例

document.getElementById("btn").addEventListener("click", function(event) {console.log("按钮被点击了!");console.log("点击位置:" + event.clientX + ", " + event.clientY);
});

🧩 事件对象在不同浏览器的兼容性

📌 IE8 及以下的兼容性写法

document.onclick = function(event) {event = event || window.event;  // 兼容 IE8-console.log("鼠标点击:" + event.clientX + ", " + event.clientY);
};

🧩 事件监听的常用方法

📌 常见事件绑定方式

// 方式 1:HTML 内联
<button onclick="alert('按钮点击!')">点击我</button>// 方式 2:JS 直接绑定
document.getElementById("btn").onclick = function() {alert("按钮点击!");
};// 方式 3:`addEventListener`
document.getElementById("btn").addEventListener("click", function() {alert("按钮点击!");
});

addEventListener 推荐使用,支持多个监听器,不会覆盖已有的事件。
onclick 不推荐会覆盖之前的事件处理函数


事件对象 event 包含鼠标、键盘、窗口等事件的详细信息
clientX / clientY 获取鼠标在可视窗口的坐标
pageX / pageY 获取鼠标在整个文档的坐标
IE8 兼容性event = event || window.event;
推荐使用 addEventListener 绑定事件,避免 onclick 覆盖问题

这些知识点在鼠标拖拽、监听用户行为、动态界面交互等场景中都非常重要!💡

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<style type="text/css">#areaDiv {border: 1px solid black;width: 300px;height: 50px;margin-bottom: 10px;}#showMsg {border: 1px solid black;width: 300px;height: 20px;}</style>
<script type="text/javascript">window.onload = function(){//当鼠标在areaDiv中移动时,在showMsg中来显示鼠标的坐标//获取两个divvar areaDiv = document.getElementById("areaDiv");var showMsg = document.getElementById("showMsg");areaDiv.onmousemove = function(event){//解决事件对象的兼容性问题event = event || window.event;var x = event.clientX;var y = event.clientY;//在showMsg中显示鼠标的坐标showMsg.innerHTML = "x = "+x + " , y = "+y;	};};</script>
</head>
<body><div id="areaDiv"></div><div id="showMsg"></div>
</body>
</html>

在这里插入图片描述


⭐️练习:使得一个box跟着鼠标移动

  • chrome认为浏览器的滚动条是body的,可以通过body.scrollTop来获取,火狐等浏览器认为浏览器的滚动条是html的。
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title></title><style type="text/css">#box1{width: 100px;height: 100px;background-color: red;/* 开启box1的绝对定位 */position: absolute;}	</style><script type="text/javascript">window.onload = function(){//使div可以跟随鼠标移动//获取box1var box1 = document.getElementById("box1");//绑定鼠标移动事件document.onmousemove = function(event){//解决兼容问题event = event || window.event;//获取滚动条滚动的距离/** chrome认为浏览器的滚动条是body的,可以通过body.scrollTop来获取* 火狐等浏览器认为浏览器的滚动条是html的,*/var st = document.body.scrollTop || document.documentElement.scrollTop;var sl = document.body.scrollLeft || document.documentElement.scrollLeft;	//获取到鼠标的坐标/** clientX和clientY* 	用于获取鼠标在当前的可见窗口的坐标* div的偏移量,是相对于整个页面的* * pageX和pageY可以获取鼠标相对于当前页面的坐标* 	但是这个两个属性在IE8中不支持,所以如果需要兼容IE8,则不要使用*/var left = event.clientX;var top = event.clientY;//设置div的偏移量box1.style.left = left + sl + "px";box1.style.top = top + st + "px";				};			};	</script></head><body style="height: 1000px;width: 2000px;"><div id="box1"></div></body>
</html>

在这里插入图片描述

❤️事件的冒泡

  • 事件的冒泡(Bubble)
    • 所谓的冒泡指的就是事件的向上传导当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发
    • 在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡可以通过事件对象来取消冒泡。
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title></title><style type="text/css">#box1{width: 200px;height: 200px;background-color: bisque;border: 3px black solid;}#s1{background-color: salmon;border: 1px red solid;}</style><script type="text/javascript">window.onload = function(){//为s1绑定一个单击响应函数var s1 = document.getElementById("s1");s1.onclick = function(event){event = event || window.event;alert("我是span的单击响应函数");//取消冒泡//可以将事件对象的cancelBubble设置为true,即可取消冒泡event.cancelBubble = true;};//为box1绑定一个单击响应函数var box1 = document.getElementById("box1");box1.onclick = function(event){event = event || window.event;alert("我是div的单击响应函数");//event.cancelBubble = true;};//为body绑定一个单击响应函数document.body.onclick = function(){alert("我是body的单击响应函数");};};</script></head><body><div id="box1">我是box1<span id="s1">我是span</span></div></body>
</html>

在这里插入图片描述
在这里插入图片描述


❤️事件的委派(Event Delegation)

1️⃣ 什么是事件委派?

事件委派(Event Delegation)是一种利用事件冒泡机制将子元素的事件委托给父元素来处理的方法。
👉 核心思想:将事件绑定在父元素上,当子元素触发事件时,由父元素捕获并进行处理。


2️⃣ 事件委派的原理

JavaScript 事件流包括 三个阶段
1️⃣ 捕获阶段(事件从 window 逐级向下传播到目标元素)
2️⃣ 目标阶段(事件到达目标元素并触发)
3️⃣ 冒泡阶段(事件从目标元素逐级向上冒泡回 window

事件委派利用事件冒泡只需给父元素绑定事件,然后通过 event.target 确定触发事件的具体子元素。


3️⃣ 为什么使用事件委派?

减少事件绑定,提高性能(避免给多个子元素单独绑定事件)
动态元素支持(即使后续新增的子元素也能触发事件)
代码更简洁,易于管理


4️⃣ 事件委派示例

传统写法(每个子元素都绑定事件 ❌)

const items = document.querySelectorAll(".item");items.forEach(item => {item.addEventListener("click", function() {console.log("点击了:" + this.innerText);});
});

📌 缺点
1️⃣ 每个子元素都要单独绑定事件,导致性能下降。
2️⃣ 新添加的子元素不会自动拥有事件,需要手动绑定。


使用事件委派(推荐 ✅)

document.querySelector(".container").addEventListener("click", function(event) {if (event.target.classList.contains("item")) {console.log("点击了:" + event.target.innerText);}
});

📌 优点
只给父元素 .container 绑定一次事件,所有 .item 子元素都能触发
即使后续新增 .item 子元素,也能正常响应事件


5️⃣ 事件委派适用场景
动态列表(如评论区、新增按钮等)
导航菜单(如 ul > li 结构)
表单事件(如 input 输入框、复选框等)
游戏开发(如多个动态生成的角色点击事件)


6️⃣ 事件委派 VS 事件监听

对比项事件监听(普通方式)事件委派(Event Delegation)
绑定方式直接绑定到子元素绑定到父元素
事件处理数量每个子元素一个处理函数只需要一个
新添加元素需要手动绑定自动适应
性能消耗较大,事件多较小,事件少
代码可读性可能较复杂更清晰简洁
<!DOCTYPE html>
<html><head><meta charset="utf-8" /><title></title><script type="text/javascript">window.onload = function(){var u1 = document.getElementById("u1");//点击按钮以后添加超链接var btn01 = document.getElementById("btn01");btn01.onclick = function(){//创建一个livar li = document.createElement("li");li.innerHTML = "<a href='javascript:;' class='link'>新建的超链接</a>";//将li添加到ul中u1.appendChild(li);};//为ul绑定一个单击响应函数u1.onclick = function(event){event = event || window.event;//如果触发事件的对象是我们期望的元素,则执行否则不执行if(event.target.className == "link"){alert("我是ul的单击响应函数");}};};</script></head><body><button id="btn01">添加超链接</button>	<ul id="u1" style="background-color: pink;"><li><p>我是p元素</p></li><li><a href="javascript:;" class="link">超链接一</a></li><li><a href="javascript:;" class="link">超链接二</a></li><li><a href="javascript:;" class="link">超链接三</a></li></ul></body>
</html>
属性描述
bubbles返回布尔值,指示事件是否是起泡事件类型,
cancelable返回布尔值,指示事件是否可拥可取消的默认动作。
currentTarget返回其事件监听器触发该事件的元素。
eventPhase返回事件传播的当前阶段。
target返回触发此事件的元素(事件的目标节点)。
timeStamp返回事件生成的日期和时间。
type返回当前Event对象表示的事件的名称。

❤️事件的绑定

🧩赋值绑定

  • 使用对象.事件 = 函数的形式绑定响应函数。
  • 只能同时为一个元素的一个事件绑定一个响应函数,不能绑定多个,如果绑定了多个,则后边会覆盖掉前边的。
window.onload = function () {var button = document.getElementById("button");button.onclick = function () {alert(1);};button.onclick = function () {alert(2);//最后只弹出2};
};

🧩addEventListener()

  • 通过这个方法也可以为元素绑定响应函数,参数

    • 1.事件的字符串,不要on
    • 2.回调函数,当事件触发时该函数会被调用
    • 3.是否在捕获阶段触发事件,需要一个布尔值,一般都传false
  • 使用addEventListener()可以同时为一个元素的相同事件同时绑定多个响应函数,这样当事件被触发时,响应函数将会按照函数的绑定顺序执行。

  • 这个方法不支持IE8及以下的浏览器

    var btn01 = document.getElementById("btn01");
    btn01.addEventListener("click",function(){alert(1);
    },false);btn01.addEventListener("click",function(){alert(2);
    },false);btn01.addEventListener("click",function(){alert(3);
    },false);
    //先弹1,再弹2,再弹3
    

🧩attachEvent()

  • 在IE8中可以使用attachEvent()来绑定事件,只有IE8及以下的时候采用~
  • 参数
    • 1.事件的字符串,要on
    • 2.回调函数
  • 这个方法也可以同时为一个事件绑定多个处理函数,不同的是它是后绑定先执行,执行顺序和addEventListener()相反
var btn01 = document.getElementById("btn01");
btn01.attachEvent("onclick",function(){alert(1);
});btn01.attachEvent("onclick",function(){alert(2);
});btn01.attachEvent("onclick",function(){alert(3);
});

🧩bind()函数

  • 定义一个函数,用来为指定元素绑定响应函数,它用来兼容!
  • addEventListener()中的this,是绑定事件的对象,attachEvent()中的this,是window,需要统一两个方法的this。
  • 参数
    • obj:要绑定事件的对象
    • eventStr:事件的字符串(不要on)
    • callback:回调函数
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title></title><script type="text/javascript">window.onload = function(){//获取按钮对象var btn01 = document.getElementById("btn01");bind(btn01 , "click" , function(){alert(this);});};function bind(obj , eventStr , callback){if(obj.addEventListener){//大部分浏览器兼容的方式obj.addEventListener(eventStr , callback , false);}else{//IE8及以下obj.attachEvent("on"+eventStr , function(){//在匿名函数中调用回调函数callback.call(obj);});}}</script></head><body><button id="btn01">点我一下</button></body>
</html>

❤️事件的传播(Event Propagation)

  • 关于事件的传播网景公司和微软公司有不同的理解:
    • 微软公司认为事件应该是由内向外传播,也就是当事件触发时,应该先触发当前元素上的事件,然后再向当前元素的祖先元素上传播,也就说事件应该在冒泡阶段执行。
    • 网景公司认为事件应该是由外向内传播的,也就是当前事件触发时,应该先触发当前元素的最外层的祖先元素的事件,然后在向内传播给后代元素。

🧩 什么是事件传播?

事件传播是指事件在 DOM 树中传递的方式,分为三个阶段

1️⃣ 事件捕获(Event Capturing) —— 从 window 逐级向下传递到目标元素

2️⃣ 目标阶段(Target Phase) —— 事件到达目标元素,并触发事件处理函数

3️⃣ 事件冒泡(Event Bubbling) —— 事件从目标元素逐级向上传递到 window


🧩 事件传播的顺序

🔹 默认情况下,事件是按照 “捕获 → 目标 → 冒泡” 的顺序传播的。

🔹 事件先从 window 依次向下捕获到目标元素,然后在目标元素上触发事件,最后从目标元素依次冒泡回 window

📝 示例:

<div id="parent"><button id="child">点击我</button>
</div>
document.getElementById("parent").addEventListener("click", function() {console.log("父元素被点击");
});
document.getElementById("child").addEventListener("click", function() {console.log("子元素被点击");
});

执行结果
📌 点击 <button> 时的输出顺序:

子元素被点击
父元素被点击

📌 解释

1️⃣ 事件先在 <button> 触发

2️⃣ 然后向上传递到 <div>

3️⃣ 最后到达 documentwindow


🧩 事件捕获阶段(一)

🔹 事件捕获是window 逐级向下传递,直到目标元素才会触发事件。

🔹 在默认情况下,事件监听器不会在捕获阶段执行,除非手动开启。

🔹 开启事件捕获监听:在 addEventListener() 第三个参数传入 true

document.getElementById("parent").addEventListener("click", function() {console.log("父元素捕获");
}, true);
document.getElementById("child").addEventListener("click", function() {console.log("子元素点击");
});

执行结果

父元素捕获
子元素点击

📌 解释
1️⃣ parent 处于捕获阶段,先触发

2️⃣ child 处于目标阶段,后触发

3️⃣ 没有冒泡,因为 parent 监听的是捕获阶段


🧩 事件冒泡阶段(二)

🔹 事件冒泡是从目标元素逐级向上传递,最终到达 window

🔹 事件冒泡是默认行为,大多数事件都支持冒泡(如 clickfocusoutkeyup)。

🔹 可以使用 event.stopPropagation() 阻止事件继续冒泡

document.getElementById("child").addEventListener("click", function(event) {console.log("子元素被点击");event.stopPropagation(); // 阻止事件冒泡
});
document.getElementById("parent").addEventListener("click", function() {console.log("父元素被点击");
});

执行结果

子元素被点击

📌 解释

event.stopPropagation() 阻止了事件向上传播parent 不会触发事件。


🧩 stopPropagation()stopImmediatePropagation()

🚫 stopPropagation()

阻止事件冒泡,但不会阻止当前元素的其他事件监听器

document.getElementById("child").addEventListener("click", function(event) {console.log("子元素监听1");event.stopPropagation();
});
document.getElementById("child").addEventListener("click", function() {console.log("子元素监听2");
});

执行结果

子元素监听1
子元素监听2

📌 解释stopPropagation() 阻止了冒泡,但 child 本身的 click 事件仍然执行。


🚫 stopImmediatePropagation()

阻止事件冒泡,并且阻止当前元素上的其他事件监听器执行

document.getElementById("child").addEventListener("click", function(event) {console.log("子元素监听1");event.stopImmediatePropagation();
});
document.getElementById("child").addEventListener("click", function() {console.log("子元素监听2");
});

执行结果

子元素监听1

📌 解释stopImmediatePropagation() 不仅阻止了冒泡,还阻止了当前元素上的其他事件


🧩 preventDefault() 阻止默认行为

🔹 preventDefault() 用于阻止元素的默认行为,例如:

✅ 阻止 `<a>` 跳转  ✅ 阻止 `<form>` 提交  ✅ 阻止 `<input type="checkbox">` 被选中  

示例

document.querySelector("a").addEventListener("click", function(event) {event.preventDefault();  // 阻止链接跳转console.log("阻止了链接跳转");
});

📌 解释event.preventDefault() 不会影响事件传播,只是阻止默认行为。


概念作用
事件捕获事件从 window 逐级向下传播到目标元素
目标阶段事件到达目标元素并触发
事件冒泡事件从目标元素逐级向上传递到 window
stopPropagation()阻止事件冒泡
stopImmediatePropagation()阻止事件冒泡,同时阻止当前元素的其他事件监听器
preventDefault()阻止默认行为,但不影响事件传播

在这里插入图片描述

  • IE8及以下的浏览器中没有捕获阶段
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title></title><style type="text/css">#box1{width: 300px;height: 300px;background-color: yellowgreen;}#box2{width: 200px;height: 200px;background-color: yellow;}#box3{width: 150px;height: 150px;background-color: skyblue;}</style><script type="text/javascript">window.onload = function(){//分别为三个div绑定单击响应函数var box1 = document.getElementById("box1");var box2 = document.getElementById("box2");var box3 = document.getElementById("box3");bind(box1,"click",function(){alert("我是box1的响应函数")});bind(box2,"click",function(){alert("我是box2的响应函数")});bind(box3,"click",function(){alert("我是box3的响应函数")});};function bind(obj , eventStr , callback){if(obj.addEventListener){//大部分浏览器兼容的方式obj.addEventListener(eventStr , callback , false);/*如果是false,点box3会先弹box3、再box2再box1*//*若是true就是直接1,2,3,也即捕获时即触发*/}else{//IE8及以下obj.attachEvent("on"+eventStr , function(){//在匿名函数中调用回调函数callback.call(obj);});}}</script></head><body><div id="box1"><div id="box2"><div id="box3"></div></div></div></body>
</html>

❤️JavaScript 拖拽实现(不使用 HTML5 Drag & Drop API)

HTML5 提供了一套 拖拽(Drag and Drop)API,可以实现元素拖拽并放置到指定位置。拖拽操作涉及拖拽源(拖拽的元素)和放置目标(接收拖拽的区域)。

除了 HTML5 提供的 draggable API,我们也可以通过 mousedown、mousemove 和 mouseup 事件手动实现拖拽效果。


🧩 拖拽的流程

事件触发时机
mousedown鼠标按下,开始拖拽
mousemove鼠标移动,元素跟随鼠标
mouseup鼠标松开,停止拖拽

🧩 手动实现拖拽

💡 示例:实现一个可以随意拖动的 div

<style>#dragBox {width: 100px;height: 100px;background-color: red;position: absolute;top: 100px;left: 100px;cursor: grab;}
</style><div id="dragBox"></div><script>const dragBox = document.getElementById("dragBox");let offsetX = 0, offsetY = 0, isDragging = false;// 1️⃣ 鼠标按下,记录起始位置dragBox.addEventListener("mousedown", function (event) {isDragging = true;offsetX = event.clientX - dragBox.offsetLeft;offsetY = event.clientY - dragBox.offsetTop;dragBox.style.cursor = "grabbing"; // 鼠标变成抓取状态// 取消默认行为,防止拖拽文字等干扰event.preventDefault();});// 2️⃣ 鼠标移动,元素跟随鼠标document.addEventListener("mousemove", function (event) {if (isDragging) {dragBox.style.left = event.clientX - offsetX + "px";dragBox.style.top = event.clientY - offsetY + "px";}});// 3️⃣ 鼠标松开,停止拖拽document.addEventListener("mouseup", function () {isDragging = false;dragBox.style.cursor = "grab"; // 恢复鼠标样式});
</script>

🧩 关键技术点

🔹 1. 记录鼠标相对元素的偏移量
offsetX = event.clientX - dragBox.offsetLeft;
offsetY = event.clientY - dragBox.offsetTop;

这样可以保证拖拽时,鼠标始终保持在元素内部的相对位置,而不是跳跃到左上角。

🔹 2. event.preventDefault() 取消默认行为
event.preventDefault();

防止浏览器默认的文本拖拽或图片拖拽行为。

🔹 3. mousemove 绑定到 document,保证鼠标移动范围
document.addEventListener("mousemove", function (event) {...});

如果 mousemove 事件绑定在 dragBox 上,当鼠标移动太快离开 dragBox,拖拽就会失效。


🧩 限制拖拽范围

💡 如果希望元素只能在窗口内移动,可以加边界检测

document.addEventListener("mousemove", function (event) {if (isDragging) {let x = event.clientX - offsetX;let y = event.clientY - offsetY;// 限制范围let maxX = window.innerWidth - dragBox.offsetWidth;let maxY = window.innerHeight - dragBox.offsetHeight;x = Math.max(0, Math.min(x, maxX));y = Math.max(0, Math.min(y, maxY));dragBox.style.left = x + "px";dragBox.style.top = y + "px";}
});

✅ 这样就可以让 dragBox 只能在窗口范围内拖拽,不会超出边界。


🧩 拖拽应用

拖拽窗口(如 QQ 窗口效果)
拖拽排序(如 TodoList 拖动排序)
拖拽图片、文件(如上传图片)
游戏中的角色拖动


🔚 总结

方法/属性作用
mousedown鼠标按下,开始拖拽
mousemove鼠标移动,元素跟随鼠标
mouseup鼠标松开,停止拖拽
event.preventDefault()取消默认行为,防止浏览器干扰
offsetLeft / offsetTop获取元素的当前位置
window.innerWidth / innerHeight限制拖拽范围
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title></title><style type="text/css">#box1{width: 100px;height: 100px;background-color: skyblue;position: absolute;}#box2{width: 100px;height: 100px;background-color: yellow;position: absolute;left: 200px;top: 200px;}</style><script type="text/javascript">window.onload = function(){//获取box1var box1 = document.getElementById("box1");var box2 = document.getElementById("box2");var img1 = document.getElementById("img1");//开启box1的拖拽drag(box1);//开启box2的拖拽drag(box2);//开启图片的拖拽drag(img1);	};//提取一个专门用来设置拖拽的函数//参数:开启拖拽的元素function drag(obj){//当鼠标在被拖拽元素上按下时,开始拖拽  onmousedownobj.onmousedown = function(event){//设置box1捕获所有鼠标按下的事件/** setCapture()* 	- 只有IE支持,但是在火狐中调用时不会报错,* 		而如果使用chrome调用,会报错*/obj.setCapture && obj.setCapture();event = event || window.event;//div的偏移量 鼠标.clentX - 元素.offsetLeft//div的偏移量 鼠标.clentY - 元素.offsetTopvar ol = event.clientX - obj.offsetLeft;var ot = event.clientY - obj.offsetTop;//为document绑定一个onmousemove事件document.onmousemove = function(event){event = event || window.event;//当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove//获取鼠标的坐标var left = event.clientX - ol;var top = event.clientY - ot;//修改box1的位置obj.style.left = left+"px";obj.style.top = top+"px";};//为document绑定一个鼠标松开事件document.onmouseup = function(){//当鼠标松开时,被拖拽元素固定在当前位置	onmouseup//取消document的onmousemove事件document.onmousemove = null;//取消document的onmouseup事件document.onmouseup = null;//当鼠标松开时,取消对事件的捕获obj.releaseCapture && obj.releaseCapture();};return false;};}</script></head><body><div id="box1"></div><div id="box2"></div><img src="img/an.jpg" id="img1" style="position: absolute;"/></body>
</html>

❤️鼠标滚轮事件

🧩火狐滚轮:DOMMouseScroll

  • 注意:该事件需要通过addEventListener()函数来绑定
  • 火狐不支持wheelDelta这个属性,其对应用的是detail这个属性来获取滚动的方向,向上滚动 -3,向下滚动3
  • 当滚轮滚动时,如果浏览器有滚动条,滚动条会随之滚动,这是浏览器的默认行为,一般用reture false来取消,但是火狐是用addEventListener(),使用addEventListener()方法来绑定响应函数,取消默认行为不能使用return false。
  • 需要使用event来取消默认行为event.preventDefault,但是IE8对此又不支持,如果调用会直接报错,所以我们一般这样写:event.preventDefault && event.preventDefault()

🧩其他浏览器:onwheel🔥

  • wheelDelta来获取滚轮方向,当向上滚动时,其返回值为120,向下滚动时,其返回值为-120。
  • returen false来取消浏览器滚条随滚条移动的情况。
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title></title><style type="text/css">#box1{width: 100px;height: 100px;background-color: skyblue;}</style><script type="text/javascript">window.onload = function(){//获取id为box1的divvar box1 = document.getElementById("box1");box1.onmousewheel = function(event){event = event || window.event;//event.wheelDelta 可以获取鼠标滚轮滚动的方向//向上滚 120   向下滚 -120//wheelDelta这个值我们不看大小,只看正负/** 当鼠标滚轮向下滚动时,box1变长* 	当滚轮向上滚动时,box1变短*///判断鼠标滚轮滚动的方向if(event.wheelDelta > 0 || event.detail < 0){//向上滚,box1变短box1.style.height = box1.clientHeight - 10 + "px";}else{//向下滚,box1变长box1.style.height = box1.clientHeight + 10 + "px";}/** 使用addEventListener()方法绑定响应函数,取消默认行为时不能使用return false* 需要使用event来取消默认行为event.preventDefault();* 但是IE8不支持event.preventDefault();这个玩意,如果直接调用会报错*/event.preventDefault && event.preventDefault();/** 当滚轮滚动时,如果浏览器有滚动条,滚动条会随之滚动,* 这是浏览器的默认行为,如果不希望发生,则可以取消默认行为*/return false;};//为火狐绑定滚轮事件bind(box1,"DOMMouseScroll",box1.onmousewheel);};function bind(obj , eventStr , callback){if(obj.addEventListener){//大部分浏览器兼容的方式obj.addEventListener(eventStr , callback , false);}else{/** this是谁由调用方式决定* callback.call(obj)*///IE8及以下obj.attachEvent("on"+eventStr , function(){//在匿名函数中调用回调函数callback.call(obj);});}}</script></head><body style="height: 2000px;"><div id="box1"></div></body>
</html>

效果:点住box,滚轮上划变短,下滑变长


❤️JavaScript 键盘事件(Keyboard Events)

键盘事件主要用于捕获用户按下或释放键盘按键的行为,常用于 游戏控制、快捷键、自定义输入框等功能


🧩键盘事件类型

事件名称触发时机
keydown按键被按下(如果按住不放,会连续触发)
keyup按键被松开
keypress(已废弃,不建议使用)

📌 常见应用:监听方向键(↑↓←→)、Enter键、Ctrl+S 保存快捷键等。


🧩键盘事件示例

💡 示例:监听方向键

<script>document.addEventListener("keydown", function (event) {console.log("按键代码:" + event.keyCode); // 输出按键的 Unicode 编码switch (event.keyCode) {case 37: // 左箭头console.log("👈 向左移动");break;case 38: // 上箭头console.log("☝ 向上移动");break;case 39: // 右箭头console.log("👉 向右移动");break;case 40: // 下箭头console.log("👇 向下移动");break;default:console.log("按下了其他按键:" + event.keyCode);}});
</script>

🔹 按住不松手 时,keydown 会持续触发,但是第一次和第二次之间的间隔稍长,之后间隔会变短(防止误操作)。
🔹 keyup 只触发一次,用于检测按键松开的瞬间。


🧩监听组合键(Ctrl / Shift / Alt)

除了单个按键,我们还可以监听 Ctrl、Shift、Alt 是否被按下。

💡 示例:监听 Ctrl + S 进行保存

<script>document.addEventListener("keydown", function (event) {if (event.ctrlKey && event.keyCode === 83) { // Ctrl + Sconsole.log("💾 触发保存功能!");event.preventDefault(); // 阻止默认的“另存为”操作}});
</script>

✅ 这里的 event.ctrlKey 判断 Ctrl 是否被按下
event.preventDefault() 阻止浏览器默认行为(如 Ctrl + S 触发“另存为”)


🧩event.keyCode 的常见按键

按键Unicode(keyCode)
← 左箭头37
↑ 上箭头38
→ 右箭头39
↓ 下箭头40
Enter13
Space(空格)32
Backspace8
Delete46
Shift16
Ctrl17
Alt18
Esc27

🧩event.key vs event.keyCode

💡 event.key(推荐使用)可以直接返回按键的字符,而 event.keyCode 主要用于旧浏览器。

document.addEventListener("keydown", function (event) {console.log("按键 key:" + event.key); // 比如 "a"、"Enter"console.log("按键 keyCode:" + event.keyCode); // 比如 65(A)
});

📌 event.keyCode 已废弃,但仍然能用,推荐使用 event.key


🧩限制输入框只能输入数字

<input type="text" id="numInput" placeholder="只能输入数字"><script>document.getElementById("numInput").addEventListener("keydown", function (event) {// 允许:数字 0-9(keyCode 48-57 和 96-105),退格键(8),删除键(46)if (!(event.keyCode >= 48 && event.keyCode <= 57) && // 数字键!(event.keyCode >= 96 && event.keyCode <= 105) && // 小键盘数字event.keyCode !== 8 && event.keyCode !== 46) {event.preventDefault(); // 阻止输入}});
</script>

✅ 这样就可以限制 输入框只能输入数字 🎯


🔚 总结

方法/属性作用
keydown按键被按下(可连续触发)
keyup按键被松开
event.keyCode获取按键的 Unicode 编码(已废弃)
event.key获取按键的字符(推荐使用)
event.ctrlKey判断 Ctrl 是否被按下
event.shiftKey判断 Shift 是否被按下
event.altKey判断 Alt 是否被按下
event.preventDefault()阻止默认行为(如 Ctrl + S
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title></title><script type="text/javascript">window.onload = function(){document.onkeydown = function(event){event = event || window.event;//判断一个y是否被按下//判断y和ctrl是否同时被按下if(event.keyCode === 89 && event.ctrlKey){alert("ctrl和y都被按下了");}};//获取inputvar input = document.getElementsByTagName("input")[0];input.onkeydown = function(event){event = event || window.event;//使文本框中不能输入数字if(event.keyCode >= 48 && event.keyCode <= 57){//在文本框中输入内容,属于onkeydown的默认行为//如果在onkeydown中取消了默认行为,则输入的内容,不会出现在文本框中return false;}};};</script></head><body><input type="text" /></body>
</html>

⭐️练习:上下左右控制box位置,并可通过Ctrl控制速度

<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title></title><style type="text/css">#box1{width: 100px;height: 100px;background-color: skyblue;position: absolute;}</style><script type="text/javascript">//使div可以根据不同的方向键向不同的方向移动window.onload = function(){//为document绑定一个按键按下的事件document.onkeydown = function(event){event = event || window.event;//表示移动的速度var speed = 10;//当用户按了ctrl以后,速度加快if(event.ctrlKey){speed = 500;}/** 37 左* 38 上* 39 右* 40 下*/switch(event.keyCode){case 37://alert("向左"); left值减小box1.style.left = box1.offsetLeft - speed + "px";break;case 39://alert("向右");box1.style.left = box1.offsetLeft + speed + "px";break;case 38://alert("向上");box1.style.top = box1.offsetTop - speed + "px";break;case 40://alert("向下");box1.style.top = box1.offsetTop + speed + "px";break;}	};};</script></head><body><div id="box1"></div></body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/37906.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

卷积神经网络 - 梯度和反向传播算法

在卷积网络中&#xff0c;参数为卷积核中权重以及偏置。和全连接前馈网络类似&#xff0c;卷积网络也可以通过误差反向传播算法来进行参数学习。本文我们从数学角度&#xff0c;来学习卷积神经网络梯度的推导和其反向传播算法的原理。 一、梯度&#xff1a;损失函数 L 关于第 …

鸿蒙NEXT项目实战-百得知识库03

代码仓地址&#xff0c;大家记得点个star IbestKnowTeach: 百得知识库基于鸿蒙NEXT稳定版实现的一款企业级开发项目案例。 本案例涉及到多个鸿蒙相关技术知识点&#xff1a; 1、布局 2、配置文件 3、组件的封装和使用 4、路由的使用 5、请求响应拦截器的封装 6、位置服务 7、三…

【测试篇】关于allpairs实现正交测试用例保姆级讲解,以及常见的错误问题

前言 &#x1f31f;&#x1f31f;本期讲解关于测试工具相关知识介绍~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那么废话不多说…

OpenCV图像拼接(4)图像拼接模块的一个匹配器类cv::detail::BestOf2NearestRangeMatcher

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::detail::BestOf2NearestRangeMatcher 是 OpenCV 库中用于图像拼接模块的一个匹配器类&#xff0c;专门用于寻找两幅图像之间的最佳特征点匹配…

C++: AVL树(实现旋转操作)

前言 map/set容器有个共同点是&#xff1a;其底层都是按照二叉搜索树来实现的&#xff0c;但是二叉搜索树有其自身的缺陷&#xff0c;假如往树中插入的元素有序或者接近有序&#xff0c;二叉搜索树就会退化成单支树&#xff0c;时间复杂度会退化成O(N)&#xff0c;因此map、set…

OpenCV中距离公式

一、各类距离公式总结 常见距离公式 欧氏距离&#xff1a; 曼哈顿距离&#xff08;L1&#xff09;‌&#xff1a; 切比雪夫距离&#xff08;Chessboard&#xff09;‌&#xff1a; 1、点与点距离(欧氏距离) ‌二维空间‌ 设两点坐标为 P1(x1,y1)、P2(x2,y2)&#xff0c;其距离…

六十天前端强化训练之第二十四天之Vue 模板语法与 v-for 指令大师级详解

欢迎来到编程星辰海的博客讲解 看完可以给一个免费的三连吗&#xff0c;谢谢大佬&#xff01; 目录 一、模板语法与指令知识精讲 1.1 模板语法三大核心 1.2 常见指令全家福 1.3 v-for 深度解析 二、商品列表示例完整实现 2.1 完整可运行代码 2.2 代码解析 2.3 运行效果…

XSS跨站脚本攻击漏洞(Cross Site Scripting)

前提概要 本文章主要用于分享XSS跨站脚本攻击漏洞基础学习&#xff0c;以下是对XSS跨站脚本攻击漏洞的一些个人解析&#xff0c;请大家结合参考其他文章中的相关信息进行归纳和补充。 XSS跨站脚本攻击漏洞描述 跨站脚本攻击&#xff08;XSS&#xff09;漏洞是一种常见且危害较…

用ArcGIS做一张符合环评要求的植被类型图

植被类型图是环境影响评价&#xff08;环评&#xff09;中的重要图件&#xff0c;需满足数据准确性、制图规范性和信息完整性等要求。本教程将基于ArcMap平台&#xff0c;从数据准备到成果输出&#xff0c;详细讲解如何制作符合环评技术规范的植被类型图。 ArcGIS遥感解译土地…

详解string类+迭代器

迭代器 概念&#xff1a;在 C 中&#xff0c;迭代器是访问容器&#xff08;如数组、列表、向量、字符串等&#xff09;元素的一种方式。迭代器提供了一种统一的接口&#xff0c;使得你可以使用相同的代码来遍历不同类型的容器。迭代器本质上是一个指针或者指针的封装&#xff0…

Sqoop安装部署

Apache Sqoop 简介 Sqoop&#xff08;SQL-to-Hadoop&#xff09;是 Apache 开源项目&#xff0c;主要用于&#xff1a; 将关系型数据库中的数据导入 Hadoop 分布式文件系统&#xff08;HDFS&#xff09;或相关组件&#xff08;如 Hive、HBase&#xff09;。 将 Hadoop 处理后…

软件工程之软件验证计划Software Verification Plan

个人主页&#xff1a;云纳星辰怀自在 座右铭&#xff1a;“所谓坚持&#xff0c;就是觉得还有希望&#xff01;” 本文为基于ISO26262软件验证计划模板&#xff0c;仅供参考。 软件验证计划&#xff0c;包括&#xff1a; 1. 软件需求验证计划 2. 软件架构设计验证计划 3. 软件单…

Windows系统本地部署OpenManus对接Ollama调用本地AI大模型

文章目录 前言1. 环境准备1.1 安装Python1.2. 安装conda 2. 本地部署OpenManus2.1 创建一个新conda环境2.2 克隆存储库2.3 安装依赖环境 3. 安装Ollama4. 安装QwQ 32B模型5. 修改OpenManus配置文件6. 运行OpenManus7.通过网页使用OpenManus8. 安装内网穿透8.1 配置随机公网地址…

计算机网络总结

一、IP地址及子网掩码、MAC 二、DNS、ARP 三、DHCP、UDP、TCP 四、NAT、NAPT、端口、网关 五、路由器与交换机 六、OSI模型 一、IP地址及子网掩码、MAC 1.1 IP地址的作用 用来全局网络通信&#xff08;门牌号&#xff09;用来区分相同网络之间的主机 1.2 子网掩码的作用 …

MySQL0基础学习记录-下载与安装

下载 下载地址&#xff1a; &#xff08;Windows&#xff09;https://dev.mysql.com/downloads/file/?id536787 安装 直接点next&#xff0c;出现&#xff1a; 点execute 然后一直next到这页&#xff1a; next 然后需要给root设置一个密码&#xff1a; 在next。。很多页…

React基础语法速览

一、项目创建 npm create vite 这里选择react即可&#xff0c;如图&#xff1a; 二、基本文件说明 react函数式编程时&#xff0c;用的是JSX语法进行开发的&#xff0c;这里注意&#xff0c;return时只能有一个根标签&#xff1b; 三、React核心语法 1.插值功能 插值可以使用…

IT工具 | node.js 进程管理工具 PM2 大升级!支持 Bun.js

P(rocess)M(anager)2 是一个 node.js 下的进程管理器&#xff0c;内置负载均衡&#xff0c;支持应用自动重启&#xff0c;常用于生产环境运行 node.js 应用&#xff0c;非常好用&#x1f44d; &#x1f33c;概述 2025-03-15日&#xff0c;PM2发布最新版本v6.0.5&#xff0c;这…

teaming技术

一.介绍 在CentOS 6与RHEL 6系统中&#xff0c;双网卡绑定采用的是bonding技术。到了CentOS 7&#xff0c;不仅能继续沿用bonding&#xff0c;还新增了teaming技术。在此推荐使用teaming&#xff0c;因其在查看与监控方面更为便捷 。 二.原理 这里介绍两种最常见的双网卡绑定…

SpringSecurity配置(自定义认证过滤器)

文末有本篇文章的项目源码文件可供下载学习 在这个案例中,我们已经实现了自定义登录URI的操作,登录成功之后,我们再次访问后端中的API的时候要在请求头中携带token,此时的token是jwt字符串,我们需要将该jwt字符串进行解析,查看解析后的User对象是否处于登录状态.登录状态下,将…

【机器学习-模型评估】

“评估”已建立的模型 在进行回归和分类时&#xff0c;为了进行预测&#xff0c;定义了预测函数fθ(x) 然后根据训练数据求出了预测函数的参数θ(即对目标函数进行微分&#xff0c;然后求出参数更新表达式的操作) 之前求出参数更新表达式之后就结束了。但是&#xff0c;其实我…