事件
一、键盘事件
- 键盘事件可以给表单元素绑定,该事件是针对当前表单元素,光标在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>