事件
一、键盘事件
- 键盘事件可以给表单元素绑定,该事件是针对当前表单元素,光标在input框里的时候,才会触发该事件
- 如果給window、body绑定键盘事件,则在哪里敲击键盘都会触发该事件
- div、p、….等,不能绑定该事件
- 表单元素才有value属性
/*+ 键盘事件可以给表单元素绑定,该事件是针对当前表单元素,光标在input框里的时候,才会触发该事件+ 如果給window、body绑定键盘事件,则在哪里敲击键盘都会触发这件+ div、p、....等,不能绑定该事件*/// 表单元素才有value属性let inp = document.getElementById("inp");inp.onkeydown = function () { // this.value 获取的是上一次input框里的值 console.log("键盘按下", this.value);}// onkeypress 是键盘按下状态的事件inp.onkeypress = function () { // this.value 获取的是上一次input框里的值 console.log("键盘", this.value);}inp.onkeyup = function () { // this.value 获取的是目前输入input框里的最新的值,因为数执行的时候,内容已经输入了。 console.log("键盘抬起", this.value);}
二、事件对象
1、keyCode 码
// keyCode 键盘上每个按键的键码值document.body.onkeyup = function (ev) { console.log(ev); console.log("当前按键的keyCode码: " + ev.keyCode);}
推箱子案例
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; } .box { width: 200px; height: 200px; background-color: green; border-radius: 10px; position: absolute; left: 0; right: 0; top: 0; bottom: 0; } </style></head><body> <div class="box"> </div> <script> let box = document.querySelector(".box"), keycode, css = getComputedStyle(box); let left = parseFloat(css.left); let top1 = parseFloat(css.top); let right = parseFloat(css.right); let bottom = parseFloat(css.bottom); document.body.onkeydown = function (ev) { let winH = document.documentElement.clientHeight; let winW = document.documentElement.clientWidth; let boxH = box.offsetHeight; let boxW = box.offsetWidth; let boxT = box.offsetTop; let boxL = box.offsetLeft; keycode = ev.keyCode; switch (keycode) { case 37: if (boxL > 0) { left -= 10; } break; case 38: if (boxT > 0) { top1 -= 10; } break; case 39: if (winW - boxW - boxL > 0) { left += 10; } break; case 40: if (winH - boxH - boxT > 0) { top1 += 10; } break; } box.style.left = left + "px"; box.style.top = top1 + "px"; } </script></body>
2、坐标属性
/* * 相对于当前浏览器的可视窗口的位置:clientX、clientY * 相对于当前盒子的位置:offsetX、offsetY * 相对于当前的body的位置:pageX、pageY * target:目标源,当前点击的是哪个元素元素,target就是谁 * type:事件类型 * 阻止事件的默认行为 * e.cancelBubble:阻止事件的默认冒泡传播 (e.cancelBubble = true // 有兼容) * e.stopPropagation:阻止事件的默认冒泡传播(e.stopPropagation();) * e.preventDefault(); // 阻止事件的默认行为 * e.returnValue = false// 阻止事件的默认行为 有兼容 */// 1、无边框的盒子box.onclick = function (ev) { // ev事件 console.log(ev); // 鼠标在盒子中点击时距离浏览器body的x坐标值 console.log("距离浏览器左边框: " + ev.clientX); // 鼠标在盒子中点击时距离浏览器body的y坐标值 console.log("距离浏览器上边框: " + ev.clientY); // 鼠标在盒子中点击时距离当前盒子最左侧的值(不包含边框) console.log("距离当前盒子左内边框: " + ev.offsetX); // 鼠标在盒子中点击时距离当前盒子最上侧的值(不包含边框) console.log("距离当前盒子上内边框: " + ev.offsetY); // 鼠标在盒子中点击时距离当前盒子最左侧的值 console.log("距离body的左内边框: " + ev.pageX); // 鼠标在盒子中点击时距离当前盒子最上侧的值 console.log("距离body的上内边框: " + ev.pageY);}// 2、有边框的盒子box2.onclick = function (ev) { // ev事件 console.log(ev); // 鼠标在盒子中点击时距离浏览器body的x坐标值 console.log("距离浏览器左边框: " + ev.clientX); // 鼠标在盒子中点击时距离浏览器body的y坐标值 console.log("距离浏览器上边框: " + ev.clientY); // 鼠标在盒子中点击时距离当前盒子最左侧的值(不包含边框) console.log("距离当前盒子左内边框: " + ev.offsetX); // 鼠标在盒子中点击时距离当前盒子最上侧的值(不包含边框) console.log("距离当前盒子上内边框: " + ev.offsetY);}
自定义右击菜单栏案例
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>自定义菜单栏</title> <style> * { margin: 0; padding: 0; } ul { list-style: none; } .box { width: 100px; background-color: red; border-radius: 8px; position: absolute; display: none; } </style></head><body> <div class="box" id="box"> <ul> <li>1</li> <li>2</li> <li>3</li> <li>4</li> </ul> </div> <script> window.oncontextmenu = function (ev) { let colors = ["red", "green", "orange", "lawngreen", "aliceblue", "aquamarine"]; let num; let newArr = []; let lis = document.querySelectorAll(".box li"); for (let i = 0; i < 4; i++) { num = Math.round(Math.random() * 4); if (newArr.includes(colors[num])) { i--; } else { newArr.push(colors[num]); } } // 1、关闭默认菜单栏 ev.returnValue = false; // 2、自定义菜单栏显示 box.style.display = "block"; for (let i = 0; i < newArr.length; i++) { lis[i].style.background = newArr[i]; } // 3、获取鼠标右击时的坐标 let x = ev.clientX; let y = ev.clientY; console.log(x, y) // 4、x,y給盒子定位 box.style.left = x + "px"; // 单位一定写!!!! box.style.top = y + "px"; } </script></body>
三、事件的传播机制
- 所有的事件触发时,首先执行捕获阶段();
- 其次进入目标阶段(找到目标的阶段,该阶段没有先捕获后冒泡,而是先绑定谁,就先执行谁);
- 最后执行冒泡阶段。
1、事件的冒泡(由里向外冒泡)
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>事件的默认传播机制</title> <style> div { width: 200px; height: 200px; background-color: sienna; border-radius: 8px; display: flex; justify-content: center; align-items: center; margin: 20px auto; } div.inner { width: 150px; height: 150px; background-color: red; border-radius: 8px; } div.center { width: 80px; height: 80px; background-color: lightcyan; border-radius: 8px; } </style></head><body> <div class="outer"> <div class="inner"> <div class="center"></div> </div> </div> <script> let outer = document.querySelector(".outer"); let center = document.querySelector(".center"); let inner = document.querySelector(".inner"); // DOM1级绑定事件 /* // 输出的ev.target 都是center的div outer.onclick = function (ev) { console.log("1outer"); console.dir("触发源target: " + ev.target); } inner.onclick = function (ev) { console.log("2inner"); console.dir("触发源target: " + ev.target); } center.onclick = function (ev) { console.log("3center"); console.dir("触发源target: " + ev.target); } */ // DOM2级绑定事件 function fn1() { console.log("1outer"); } function fn2() { console.log("2inner"); } function fn3() { console.log("3center"); } outer.addEventListener("click", fn1); center.addEventListener("click", fn3); inner.addEventListener("click", fn2); </script></body>
2、事件的捕获机制(从外往里捕获)
<body> <div class="outer"> <div class="inner"> <div class="center"></div> </div> </div> <script> let outer = document.querySelector(".outer"); let center = document.querySelector(".center"); let inner = document.querySelector(".inner"); // DOM2级绑定事件 function fn1() { console.log("outer 冒泡"); } function fn2() { console.log("inner 冒泡"); } function fn3() { console.log("center 冒泡"); } function fn11() { console.log("outer 捕获"); } function fn22() { console.log("inner 捕获"); } function fn33() { console.log("center 捕获"); } /* * addEventListener第三个参数(默认false) * false --- 冒泡 * true --- 捕获 */ outer.addEventListener("click", fn1); outer.addEventListener("click", fn11, true); center.addEventListener("click", fn3); center.addEventListener("click", fn33, true); inner.addEventListener("click", fn2); inner.addEventListener("click", fn22, true); </script></body>
四、事件的委托
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>事件委托</title></head><body> <ul id="box"> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> </ul> <script> /* let list = document.querySelectorAll("#box li"); for (let i = 0; i < list.length; i++) { list[i].onclick = function () { console.log(this.innerText); } } */ // 利用事件委托 绑定点击事件,实现打印每一个点击元素的文本值 let box = document.querySelector("#box"); box.onclick = function (ev) { console.log(ev); console.log(ev.toElement.innerText); } </script></body>
五、鼠标跟随案例
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>鼠标跟随</title> <style> * { margin: 0; padding: 0; } .box { width: 200px; height: 200px; background-color: lightslategray; border-radius: 8px; position: relative; margin: 50px auto; } .mark { width: 50px; height: 50px; background-color: red; border-radius: 8px; position: absolute; cursor: move; } </style></head><body> <div class="box" id="box"> <!-- <div class="mark" id="mark"> 光标 </div> --> </div> <script> // 光标移入事件 let mark; box.onmouseenter = function () { mark = document.createElement("div"); mark.classList.add("mark"); mark.id = "mark"; box.appendChild(mark); } // 光标移动事件 box.onmousemove = function (ev) { let curLeft = ev.clientX - box.offsetLeft - mark.offsetHeight / 2; let curTop = ev.clientY - box.offsetTop - mark.offsetWidth / 2; // console.log(ev.clientX, box.offsetLeft); // 判断盒子的坐标位置,不让其移出大盒子 let maxLeft = box.offsetWidth - mark.offsetWidth; let maxTop = box.offsetHeight - mark.offsetHeight; if (curLeft <= 0) curLeft = 0; else if (curLeft >= maxLeft) curLeft = maxLeft; if (curTop <= 0) curTop = 0; else if (curTop > maxTop) curTop = maxTop; mark.style.left = curLeft + "px"; mark.style.top = curTop + "px"; } // 光标移出事件 box.onmouseleave = function () { box.removeChild(mark); } </script></body>