JS - 事件处理:鼠标移动监听事件、div块跟随鼠标移动事件、事件的绑定、实现拖拽效果

本文主要是介绍JS - 事件处理:鼠标移动监听事件、div块跟随鼠标移动事件、事件的绑定、实现拖拽效果,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在DOM中,每个HTML元素都可以绑定各种事件,例如点击事件(click)、鼠标移入事件(mouseover)、键盘按下事件(keydown)等。当事件发生时,可以触发相应的事件处理程序(事件监听器),执行特定的操作。

常见的事件处理方式包括:

  • HTML事件处理程序:直接在HTML元素上使用事件属性(比如onclick、onmouseover)来指定事件处理函数。
    <button onclick="myFunction()">Click me</button>
    
  • DOM属性事件处理程序:通过JavaScript代码为DOM元素的事件属性赋值来指定事件处理函数。
    document.getElementById("myButton").onclick = function() {// 事件处理逻辑
    };
    
  • DOM方法事件处理程序:使用addEventListener()方法或attachEvent()方法(在IE中)来为元素添加事件监听器。
    document.getElementById("myButton").addEventListener("click", function() {// 事件处理逻辑
    });
    
  • 事件委托:将事件处理程序绑定在父元素上,通过事件冒泡的机制来处理子元素的事件,提高性能和代码简洁度。
    document.getElementById("parentElement").addEventListener("click", function(event) {if (event.target.tagName === 'BUTTON') {// 处理按钮点击事件}
    });
    
  • 第三方库或框架:许多JavaScript库和框架(如jQuery、React、Vue等)提供了自己的事件绑定机制,简化了事件处理的操作。

事件处理程序通常是一个JavaScript函数,可以在事件发生时被调用执行。事件对象(Event Object)会被传递给事件处理程序,包含了关于事件的详细信息,比如事件类型、触发的元素等。

鼠标移动监听事件

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</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: 50px;margin-bottom: 10px;}</style><script type="text/javascript">window.onload=function(){//当鼠标在areaDiv中移动时,在showMsg中来显示鼠标的坐标//来获取两个divvar areaDiv=document.getElementById("areaDiv");var showMsg=document.getElementById("showMsg");//onmousemove//该事件将会在鼠标元素移动中被触发//事件对象//当事件的响应函数触发时,浏览器每次都会将一个事件对象作为实参传递进响应函数//在事件对象当中封装了当前事件相关的一切信息,比如,鼠标的坐标,键盘哪个键本按下,鼠标滚轮滚动的方向areaDiv.onmousemove=function(event){//IE8中,响应函数处罚时,浏览器不会传递事件对象//在IE8及以下的浏览器中,是将事件对象作为window对象的属性保存的//即window.event.clientX和window.event.client//console.log(event);//在showMsg中显示鼠标移动的坐标//clientX返回当前事件触发时,鼠标指针的水平坐标//clientY返回当前事件触发时,鼠标指针的垂直坐标var x=event.clientX;var y=event.clientY;//console.log("x="+x+",y="+y);showMsg.innerHTML="x="+x+",y="+y;};};</script>
</head>
<body><div id="areaDiv"></div><div id="showMsg"></div>
</body>
</html>

在这里插入图片描述

div块跟随鼠标移动事件

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style type="text/css">#box1{width:30px;height: 30px;background-color: red;/*开启绝对定位*/position:absolute;}html{cursor: url('https://npm.elemecdn.com/akilar-candyassets/cur/arrow.cur'),auto !important;}</style><script type="text/javascript">window.onload=function(){//使div可以跟随鼠标移动//获取box1var box1=document.getElementById("box1");//锁定鼠标移动事件document.onmousemove=function(event){//获取鼠标的坐标//鼠标坐标定位是相对于当前浏览器框的定位//clientX和clientY是相当于浏览器框的定位//pageX和pageY是相对于页面的定位//var left=event.clientX;//var top=event.clientY;var left=event.pageX;var top=event.pageY;//pageX和page这两个属性在IE8中不支持,所以如果需要兼容IE8,就不能使用//设置div的偏移量box1.style.left=left+"px";box1.style.top=top+"px";};//获取box2var box2=document.getElementById("box2");box2.onmousemove=function(event){event.cancelBubble=true;};};</script>
</head>
<body style="height: 1000px;width: 2000px;"><div id="box2" style="width: 500px;height: 500px;background-color: #bfa;"></div><div id="box1"></div>
</body>
</html>

事件的冒泡

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style type="text/css">#box1{width: 200px;height: 200px;background-color: yellowgreen;}#s1{background-color: yellow;}</style><script type="text/javascript">window.onload=function(){//事件的冒泡//所谓的冒泡指的就是事件上的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发//在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡,可以通过事件对象取消冒泡//为s1绑定一个单击响应函数var s1=document.getElementById("s1");s1.onclick=function(event){console.log("我是span的单击响应函数");//取消冒泡//可以将事件对象的cancelBubble设置为true,即可取消event.cancelBubble=true;};//为box1绑定一个单击响应函数var box1=document.getElementById("box1");box1.onclick=function(event){console.log("我是box1的单击响应函数");//取消冒泡event.cancelBubble=true;};//为body绑定一个单击响应函数document.body.onclick=function(){console.log("我是body的单击响应函数");};};</script>
</head>
<body><div id="box1">我是box1<span id="s1">我是span</span></div>
</body>
</html>

事件的委托

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script type="text/javascript">window.onload=function(){//点击按钮以后添加超链接var btn01=document.getElementById("btn01");var u1=document.getElementById("u1");btn01.onclick=function(){//console.log("添加一个超链接");//创建一个livar li=document.createElement("li");li.innerHTML="<a href='javascript:;'>新建的超链接class='link'</a>";//将li添加到ul中u1.appendChild(li);};//为每一个超链接都绑定一个单击响应函数//为每一个超链接都绑定一个单击响应函数,这种操作比较麻烦//而且这些操作只能为已有的超链接设置事件,而新添加的超链接必须重新绑定/*//获取所有的avar allA=document.getElementsByTagName("a");//遍历for(var i=0;i<allA.length;i++){console.log(allA[i]);allA[i].οnclick=function(){console.log("我是a的单击响应函数");};}*///我们希望只绑定一次事件,即可应用到所有的元素上.即时元素时后面添加的//我们可以尝试将其绑定给元素的共同的祖先元素//事件的委派//指将事件统一绑定给元素的共同的祖先元素,这样当后台元素上的事件被触发时,会一直冒泡祖先元素//从而通过祖先元素的响应函数来处理事件//事件委培利用了冒泡,通过委派可以减少事件绑定的次数,提高程序的性能//给ul绑定一个单击响应函数//这样ul的子元素全都有单击响应函数u1.onclick=function(event){//这样绑定存在一个缺点,UI存在的区域全是判定区域,随便点击都能触发事件//所以需要定一个标准,如果触发事件的对象睡我们期望的元素,则继续执行,否则不执行//console.log("我是a的单击响应函数");//先检查一下target属性//event中的targe表示的触发事件的对象//确定target是被点击的对象if(event.target.className == "link"){console.log("我是ul的单击响应函数");}};};</script>
</head>
<body><button id="btn01">添加超链接</button><br><ul id="u1"><li>我是li文档</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>

事件的绑定

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script type="text/javascript">window.onload=function(){//点击按钮以后弹出一个内容var btn01=document.getElementById("btn01");//使用 对象.事件=函数的形式绑定响应函数//他只能同时为一个元素的一个事件绑定一个响应函数,不能绑定多个,不然会出现覆盖/*btn01.οnclick=function(){console.log("1");}//为btn01绑定第二个单击响应函数,这样会造成函数覆盖btn01.οnclick=function(){console.log("2");}*///addEventListener()//通过这个方法也可以为元素绑定响应函数//参数: 1.事件的字符串,要把on舍去 2.回调函数,当事件触发时,该函数会被调用// 3.是否在捕获阶段触发事件,需要一个布尔值,一般都传false//使用它可以同时为一个元素的相同事件同时绑定多个响应函数//当事件被触发时,响应函数将会按照函数的绑定顺序执行btn01.addEventListener("click",function(){console.log(123);},false);btn01.addEventListener("click",function(){console.log(456);},false);};</script>
</head>
<body><button id="btn01">点我一下</button>
</body>
</html>

事件的传播

事件传播是指当事件发生在DOM元素上时,该事件如何在DOM树中传播到其他元素的过程。事件传播分为三个阶段:捕获阶段(capturing phase)、目标阶段(target phase)和冒泡阶段(bubbling phase)。这三个阶段统称为事件流(event flow)。

  • 捕获阶段:事件从最外层的祖先元素向目标元素传播的阶段。在捕获阶段中,事件会依次经过祖先元素,直到达到目标元素。

  • 目标阶段:事件达到目标元素后,在目标元素上触发相应的事件处理程序。

  • 冒泡阶段:事件从目标元素开始,沿着DOM树向外传播的阶段。在冒泡阶段中,事件会依次经过目标元素的祖先元素,直到达到最外层的祖先元素。

在事件传播过程中,可以通过事件处理程序的第三个参数来控制事件的传播方式。如果第三个参数为true,则表示在捕获阶段处理事件;如果为false(默认值),则表示在冒泡阶段处理事件。

事件传播的机制使得可以在DOM树的不同层次上捕获和处理事件,同时也提供了事件委托(event delegation)的可能性。通过在祖先元素上绑定事件处理程序,可以在冒泡阶段捕获子元素上的事件,减少事件处理程序的数量,提高性能和代码简洁度。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style type="text/css">#box1{width: 300px;height: 300px;background-color: green;}#box2{width: 200px;height: 200px;background-color: yellow;}#box3{width: 150px;height: 150px;background-color: blue;}</style><script type="text/javascript">window.onload=function(){//分别为三个div绑定单击响应函数var box1=document.getElementById("box1");var box2=document.getElementById("box2");var box3=document.getElementById("box3");//事件的传播//关于事件的传播网景公司和微软公司有不同的理解//微软公司认为事件应该是由内向外传播,也就是事件触发时,先触发当前元素上的事件//然后再向当前元素的祖先元素上传播,事件应该在冒泡阶段执行//网景公司认为事件应该是在由外向内传播,也就是当事件触发时,应该先触发当前元素的最外层的祖先元素的事件//然后再向内传播给后代元素//最后是W3C综合两个公司的方案,将事件传播分成了三个阶段//1.捕获阶段 由最外层的祖先元素向目标元素进行事件的捕获,但默认此时不会触发事件//2.目标阶段 事件捕获到目标元素,捕获结束开始在目标元素上触发事件//3.冒泡阶段 事件从目标元素向他的祖先元素传递,依次触发祖先元素上的事件//如果希望在捕获阶段触发事件,可以将addEventListener()的第三个参数设置为true//一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是falsebox1.addEventListener("click",function(){console.log("我是box1的响应函数");},false);box2.addEventListener("click",function(){console.log("我是box2的响应函数");},false);box3.addEventListener("click",function(){console.log("我是box3的响应函数");},false);}/*function bind(obj,eventStr,callback){if(obj.addEventListener){obj.addEventListener(event,callback,false);}else{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>

在这里插入图片描述

拖拽效果实现1

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style type="text/css">#box1{width: 100px;height: 100px;background-color: red;position: absolute;}#box2{width: 100px;height: 100px;background-color: yellow;position: absolute;left: 200px;top: 200px;}</style><script type="text/javascript">window.onload=function(){//拖拽box1元素//拖拽的流程//1.当鼠标在被拖拽元素上按下时,开始拖拽 onmousedown//2.当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove//3.当鼠标松开时,被拖拽元素固定在当前位置 onmouseup//获取box1var box1=document.getElementById("box1");/*var box1Style=getComputedStyle(box1,null)console.log(box1Style.height);console.log(box1Style.width);*///为box1绑定一个鼠标按下事件box1.onmousedown=function(event){//div的水平偏移量 鼠标.clentX-元素.offsetLeft//div的垂直偏移量 鼠标.clentY-元素.offsetTovar ol=event.clientX - box1.offsetLeft;var ot=event.clientY - box1.offsetTop;//给document绑定一个onmousemovedocument.onmousemove=function(event){//console.log(event);//当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove//获取鼠标的坐标var left=event.clientX-ol;var top=event.clientY-ot;//修改box1的位置box1.style.left=left+"px";//横纵坐标加一个-50,能使鼠标移动点固定在元素中间box1.style.top=top+"px";};//为元素绑定一个鼠标松开事件document.onmouseup=function(){//当鼠标松开时,被拖拽元素固定在当前位置 onmouseup//取消document的onmousemove事件document.onmousemove=null;//取消document的onmouseup事件document.onmouseup=null;};//当我们拖拽一个网页中的内容时,该浏览器会默认去搜索引擎中搜索内容//此时会导致拖拽功能的异常,这个是浏览器的默认行为//如果不希望发生这个行为,则可以通过return false来取消默认行为return false;//IE8不兼容};}</script>
</head>
<body><!--谷歌浏览器Ctrl+A全选页面内容然后拖动,不会出现连带元素一起拖动的情况-->我是一段文字<div id="box1"></div><div id="box2"></div>
</body>
</html>

在这里插入图片描述

拖拽效果实现图片拖拽

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style type="text/css">#box1{width: 100px;height: 100px;background-color: red;position: absolute;}#box2{width: 100px;height: 100px;background-color: yellow;position: absolute;left: 200px;top: 200px;}#图一{width: 300px;height: 300px;}</style><script type="text/javascript">//元素拖拽代码一个一个定义过于麻烦,可以尝试进行封装//提取一个专门用来设置拖拽的函数,拖拽英文trag//传递一个参数:开启拖拽的元素objfunction drag(obj){obj.onmousedown=function(event){//div的水平偏移量 鼠标.clentX-元素.offsetLeft//div的垂直偏移量 鼠标.clentY-元素.offsetTovar ol=event.clientX - obj.offsetLeft;var ot=event.clientY - obj.offsetTop;//给document绑定一个onmousemove document.onmousemove=function(event){//console.log(event);//当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove//获取鼠标的坐标var left=event.clientX-ol;var top=event.clientY-ot;//修改box1的位置obj.style.left=left+"px";//横纵坐标加一个-50,能使鼠标移动点固定在元素中间obj.style.top=top+"px";};//为元素绑定一个鼠标松开事件document.onmouseup=function(){//当鼠标松开时,被拖拽元素固定在当前位置 onmouseup//取消document的onmousemove事件document.onmousemove=null;//取消document的onmouseup事件document.onmouseup=null;};//当我们拖拽一个网页中的内容时,该浏览器会默认去搜索引擎中搜索内容//此时会导致拖拽功能的异常,这个是浏览器的默认行为//如果不希望发生这个行为,则可以通过return false来取消默认行为return false;//IE8不兼容};}window.onload=function(){//拖拽的流程//1.当鼠标在被拖拽元素上按下时,开始拖拽 onmousedown//2.当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove//3.当鼠标松开时,被拖拽元素固定在当前位置 onmouseup//获取box1var box1=document.getElementById("box1");var box2=document.getElementById("box2");var img1=document.getElementById("图一");drag(box1);drag(box2); drag(img1);};</script>
</head>
<body><!--谷歌浏览器Ctrl+A全选页面内容然后拖动,不会出现连带元素一起拖动的情况-->我是一段文字<div id="box1"></div><div id="box2"></div><img id="图一" src="./photo (1).png" style="position: absolute;">
</body>
</html>

效果如图

请添加图片描述

实现滚动事件

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style type="text/css">#box1{width: 100px;height: 100px;background-color: red;}</style><script type="text/javascript">window.onload=function(){//获取id为box1的divvar box1=document.getElementById("box1");//为box1绑定一个鼠标滚轮滚动的事件onmousewheel//火狐只支持DOMMouseScroll事件box1.onmousewheel=function(event){//当鼠标滚轮向下滚动时,box1变长//当滚轮向上滚动时,box1变短//console.log("滚了");//判断鼠标滚轮滚动的方向//event.wheelDelta 可以获取鼠标滚轮滚动的方向向上滚是120,向下滚是-120//wheelDelta这个值我们不看大小,只看正负//console.log(event.wheelDelta);if(event.wheelDelta >0){//向上滚,box1变短//console.log("向上滚");box1.style.height=box1.clientHeight-10+"px";}else{//向下滚,box2变长//console.log("向下滚");box1.style.height=box1.clientHeight+10+"px";}//当滚轮滚动时,如果浏览器有滚动条,那么就会随着滚动条滚动//这是浏览器的默认行为,如果不希望发生,则可以取消该行为return false;//但此时不能把鼠标滚轮绑定在document上};//另一种方法/*box1.addEventListener("mousewheel",function(){console.log("滚了");},false);*///此方法可以用event.preventDefault();来处理//但是IE8不能支持此方法};</script>
</head>
<body style="height: 2000px;"><div id="box1"></div>
</body>
</html>

实现一个键盘监听事件

请添加图片描述

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style type="text/css">#box1{width: 100px;height: 100px;background-color: red;}</style><script type="text/javascript">window.onload=function(){//key是指键盘字符//keyCode是指键盘字符代码//获取input1var input1=document.getElementById("input1");//键盘事件//onkeydown 按键被按下//对于onkeydown来说 如果一直按着某个按键不松手,则事件会被一直触发//当onkeydown连续触发时,第一次和第二次之间会间隔稍微长一点,其他的会非常快//防止误操作的发生//onkeyup 按键被松开 但他不会被连续触发,只能一次一次触发//键盘事件一般都会绑定给一些可以获取到焦点的对象(也就是可以获取光标的对象)或者是document//如何知道键盘敲击的是什么字符?需要使用eventdocument.onkeydown=function(event){//console.log("按键被按下了");//console.log(event.keyCode);/*if(event.keyCode === 89){console.log("y被按下了");}*///除了keyCode,事件对象中还提供了几个属性//altKey ctrlKey shiftKey//这三个用来判断alt ctrl shift是否同时被按下if(event.keyCode === 89 && event.ctrlKey){//console.log("ctrl和y都被按下了");}};document.onkeyup=function(event){//console.log("按键被松开了");};//给input1绑定键盘事件input1.onkeydown=function(event){//console.log(event.keyCode);//如果增加return false//那么文本框将无法输入字符,但是控制台依旧会显示字符的keyCode码//在文本框输入内容,属于onkeydown的默认行为//如果再onkeydown中取消了默认行为,则输入的内容,不会出现在文本框中//return false;//如何使文本框中不能输入数字//数字值在48-57和96-105之间/*if((event.keyCode>=48 && event.keyCode<=57) || (event.keyCode>=96 && event.keyCode<=105)){console.log("无法输入数字");return false;}*/};};</script>
</head>
<body><!--<div id="box1"></div>-->文本框<input type="text" id="input1">
</body>
</html>

键盘控制div移动

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style type="text/css">#box1{width: 100px;height: 100px;background-color: red;position: absolute;}</style><script type="text/javascript">//使div可以根据不同的方向键向不同的方向移动//按左键,div向左移//按右键,div向右移//key是键盘字符 keyCode是键盘字符代码window.onload=function(){var box1=document.getElementById("box1");//开启一个定时器,来控制div的移动var speed=20;//创建一个变量表示方向var dir;//通过修改dir来影响移动的方向setInterval(function(){switch(dir){case "ArrowUp"://console.log("向上");box1.style.top=box1.offsetTop-speed+"px";break;case "ArrowRight"://console.log("向右");box1.style.left=box1.offsetLeft+speed+"px";break;case "ArrowDown"://console.log("向下");box1.style.top=box1.offsetTop+speed+"px";break;case "ArrowLeft"://console.log("向左");box1.style.left=box1.offsetLeft-speed+"px";break;}},30);//先给documment绑定一个按键按下事件document.onkeydown=function(event){dir=event.key;//当用户按了ctrl时,速度加快if(event.ctrlKey){speed=50;}else{speed=20;}};//当按键松开时,div不再移动document.onkeyup=function(){//设置方向为0dir=0;};};</script>
</head>
<body><div id="box1"></div>
</body>
</html>

HTML实现一个俄罗斯方块

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>es6-重构俄罗斯方块(基于canvas)</title><style type="text/css">#tetris{ margin: 10px 250px;}</style>
</head>
<body><canvas width="700" height="525" id="tetris"></canvas><div id="text" style='color: red;font-size: 30px;'>当前分数:0</div><script type="text/javascript">/*** [一个完整的俄罗斯方块类 design by magic_xiang]* @param  {number} side     [每个方块边长(px),默认35]* @param  {number} width     [一行包含的方块数(个),默认20]* @param  {number} height     [一列包含的方块数(个),默认15]* @param  {number} speed     [方块下落移动速度(ms),默认400]*/class tetris{constructor(side=35, width=20, height=15, speed=400){this.side = side            // 每个方块边长this.width = width            // 一行包含的方块数this.height = height        // 一列包含的方块数this.speed = speed             // 方块下落移动速度this.num_blcok                // 当前方块类型的数字变量this.type_color                // 当前颜色类型的字符串变量this.ident                    // setInterval的标识this.direction = 1            // 方块方向,初始化为1,默认状态    this.grade = 0                // 用来计算分数this.over = false            // 游戏是否结束this.arr_bX = []            // 存放当前方块的X坐标this.arr_bY = []            // 存放当前方块的Y坐标this.arr_store_X = []        // 存放到达底部所有方块的X坐标this.arr_store_Y = []        // 存放到达底部所有方块的Y坐标this.arr_store_color = []    // 存放到达底部所有方块的颜色this.paints = document.getElementById('tetris').getContext('2d')//获取画笔self = this}// 封装paints方法,让代码更简洁paintfr(x, y, scale=1){this.paints.fillRect(x*this.side, y*this.side, scale*this.side, scale*this.side)}// 游戏开始gameStart(){this.init()this.run()}// 初始化工作init(){this.initBackground()this.initBlock()}// 方块自动下落run(){this.ident = setInterval("self.down_speed_up()", this.speed)}// 初始化地图initBackground(){this.paints.beginPath()this.paints.fillStyle='#000000'        //地图填充颜色为黑色for(let i = 0; i < this.height; i++){for(let j = 0; j < this.width; j++){this.paintfr(j, i)}}this.paints.closePath()}// 初始化方块的位置和颜色initBlock(){this.paints.beginPath()this.createRandom('rColor')        //生成颜色字符串,this.paints.fillStyle = this.type_colorthis.createRandom('rBlock')        //生成方块类型数字this.arr_bX.forEach((item, index) => {this.paintfr(item, this.arr_bY[index], 0.9)})this.paints.closePath()}// 利用数组画方块drawBlock(color){this.paints.beginPath()this.paints.fillStyle = colorthis.arr_bX.forEach((item, index) => {this.paintfr(item, this.arr_bY[index], 0.9)})this.paints.closePath()}// 画已经在定位好的方块drawStaticBlock(){this.arr_store_X.forEach((item, index) => {this.paints.beginPath()this.paints.fillStyle = this.arr_store_color[index]this.paintfr(item, this.arr_store_Y[index], 0.9)this.paints.closePath()})}// 生成随机数返回方块类型或颜色类型createRandom(type){let temp = this.width/2-1if (type == 'rBlock'){         //如果是方块类型this.num_blcok = Math.round(Math.random()*4+1)switch(this.num_blcok){case 1:this.arr_bX.push(temp,temp-1,temp,temp+1)this.arr_bY.push(0,1,1,1)breakcase 2:this.arr_bX.push(temp,temp-1,temp-1,temp+1)this.arr_bY.push(1,0,1,1)breakcase 3:this.arr_bX.push(temp,temp-1,temp+1,temp+2)this.arr_bY.push(0,0,0,0)breakcase 4:this.arr_bX.push(temp,temp-1,temp,temp+1)this.arr_bY.push(0,0,1,1)breakcase 5:this.arr_bX.push(temp,temp+1,temp,temp+1)this.arr_bY.push(0,0,1,1)break}}if (type == 'rColor'){                         //如果是颜色类型let num_color = Math.round(Math.random()*8+1) switch(num_color){case 1:this.type_color='#3EF72A'breakcase 2:this.type_color='yellow'breakcase 3:this.type_color='#2FE0BF'breakcase 4:this.type_color='red'breakcase 5:this.type_color='gray'breakcase 6:this.type_color='#C932C6'breakcase 7:this.type_color= '#FC751B'breakcase 8:this.type_color= '#6E6EDD'breakcase 9:this.type_color= '#F4E9E1'break}}}// 判断方块之间是否碰撞(下),以及变形时是否越过下边界judgeCollision_down(){for(let i = 0; i < this.arr_bX.length; i++){if (this.arr_bY[i] + 1 == this.height){ //变形时是否越过下边界return false} if (this.arr_store_X.length != 0) {    //判断方块之间是否碰撞(下)for(let j = 0; j < this.arr_store_X.length; j++){if (this.arr_bX[i] == this.arr_store_X[j]) {if (this.arr_bY[i] + 1 == this.arr_store_Y[j]) {return false}}}}    }return true}//判断方块之间是否碰撞(左右),以及变形时是否越过左右边界judgeCollision_other(num){for(let i = 0; i < this.arr_bX.length; i++){if (num == 1) {            //变形时是否越过右边界if (this.arr_bX[i] == this.width - 1) return false}if (num == -1) {                //变形时是否越过左边界if (this.arr_bX[i] == 0)return false}if (this.arr_store_X.length != 0) {                    //判断方块之间是否碰撞(左右)for(let j = 0; j < this.arr_store_X.length; j++){if (this.arr_bY[i] == this.arr_store_Y[j]) {if (this.arr_bX[i] + num == this.arr_store_X[j]) {return false}}}}}return true;}//方向键为下的加速函数down_speed_up(){let flag_all_down = trueflag_all_down = this.judgeCollision_down()if (flag_all_down) {this.initBackground()for(let i = 0; i < this.arr_bY.length; i++){this.arr_bY[i] = this.arr_bY[i] + 1}}else{for(let i=0; i < this.arr_bX.length; i++){this.arr_store_X.push(this.arr_bX[i])this.arr_store_Y.push(this.arr_bY[i])this.arr_store_color.push(this.type_color)}this.arr_bX.splice(0,this.arr_bX.length)this.arr_bY.splice(0,this.arr_bY.length)this.initBlock()}this.clearUnderBlock()this.drawBlock(this.type_color)this.drawStaticBlock()this.gameover()}//方向键为左右的左移动函数move(dir_temp){this.initBackground()if (dir_temp == 1) {                    //右let flag_all_right = trueflag_all_right = this.judgeCollision_other(1)if (flag_all_right) {for(let i = 0; i < this.arr_bY.length; i++){this.arr_bX[i] = this.arr_bX[i]+1}}}else{let flag_all_left = trueflag_all_left = this.judgeCollision_other(-1)if (flag_all_left) {for(let i=0; i < this.arr_bY.length; i++){this.arr_bX[i] = this.arr_bX[i]-1}}}this.drawBlock(this.type_color)this.drawStaticBlock()}//方向键为空格的变换方向函数up_change_direction(num_blcok){ if (num_blcok == 5) {return}let arr_tempX = []let arr_tempY = []//因为不知道是否能够变形成功,所以先存储起来for(let i = 0;i < this.arr_bX.length; i++){    arr_tempX.push(this.arr_bX[i])arr_tempY.push(this.arr_bY[i])}this.direction++//将中心坐标提取出来,变形都以当前中心为准let ax_temp = this.arr_bX[0]    let ay_temp = this.arr_bY[0]this.arr_bX.splice(0, this.arr_bX.length)            //将数组清空 this.arr_bY.splice(0, this.arr_bY.length)if (num_blcok == 1) {switch(this.direction%4){case 1:this.arr_bX.push(ax_temp,ax_temp-1,ax_temp,ax_temp+1)this.arr_bY.push(ay_temp,ay_temp+1,ay_temp+1,ay_temp+1)breakcase 2:this.arr_bX.push(ax_temp,ax_temp-1,ax_temp,ax_temp)this.arr_bY.push(ay_temp,ay_temp,ay_temp-1,ay_temp+1)breakcase 3:this.arr_bX.push(ax_temp,ax_temp-1,ax_temp,ax_temp+1)this.arr_bY.push(ay_temp,ay_temp,ay_temp+1,ay_temp)breakcase 0:this.arr_bX.push(ax_temp,ax_temp,ax_temp,ax_temp+1)this.arr_bY.push(ay_temp,ay_temp-1,ay_temp+1,ay_temp)break}}if (num_blcok == 2) {switch(this.direction%4){case 1:this.arr_bX.push(ax_temp,ax_temp-1,ax_temp-1,ax_temp+1)this.arr_bY.push(ay_temp,ay_temp,ay_temp-1,ay_temp)breakcase 2:this.arr_bX.push(ax_temp,ax_temp,ax_temp,ax_temp-1)this.arr_bY.push(ay_temp,ay_temp-1,ay_temp+1,ay_temp+1)breakcase 3:this.arr_bX.push(ax_temp,ax_temp-1,ax_temp+1,ax_temp+1)this.arr_bY.push(ay_temp,ay_temp,ay_temp,ay_temp+1)breakcase 0:this.arr_bX.push(ax_temp,ax_temp,ax_temp,ax_temp+1)this.arr_bY.push(ay_temp,ay_temp-1,ay_temp+1,ay_temp-1)break}}if (num_blcok == 3) {switch(this.direction%4){case 1:this.arr_bX.push(ax_temp,ax_temp-1,ax_temp+1,ax_temp+2)this.arr_bY.push(ay_temp,ay_temp,ay_temp,ay_temp)breakcase 2:this.arr_bX.push(ax_temp,ax_temp,ax_temp,ax_temp)this.arr_bY.push(ay_temp,ay_temp-1,ay_temp+1,ay_temp+2)breakcase 3:this.arr_bX.push(ax_temp,ax_temp-1,ax_temp+1,ax_temp+2)this.arr_bY.push(ay_temp,ay_temp,ay_temp,ay_temp)breakcase 0:this.arr_bX.push(ax_temp,ax_temp,ax_temp,ax_temp)this.arr_bY.push(ay_temp,ay_temp-1,ay_temp+1,ay_temp+2)break}}if (num_blcok == 4) {switch(this.direction%4){case 1:this.arr_bX.push(ax_temp,ax_temp-1,ax_temp,ax_temp+1)this.arr_bY.push(ay_temp,ay_temp,ay_temp+1,ay_temp+1)breakcase 2:this.arr_bX.push(ax_temp,ax_temp,ax_temp+1,ax_temp+1)this.arr_bY.push(ay_temp,ay_temp+1,ay_temp,ay_temp-1)breakcase 3:this.arr_bX.push(ax_temp,ax_temp,ax_temp-1,ax_temp+1)this.arr_bY.push(ay_temp,ay_temp-1,ay_temp,ay_temp-1)breakcase 0:this.arr_bX.push(ax_temp,ax_temp,ax_temp+1,ax_temp+1)this.arr_bY.push(ay_temp,ay_temp-1,ay_temp,ay_temp+1)break}}if (! (this.judgeCollision_other(-1) && this.judgeCollision_down() && this.judgeCollision_other(1)  )) {            //如果变形不成功则执行下面代码this.arr_bX.splice(0, this.arr_bX.length)             this.arr_bY.splice(0, this.arr_bY.length)for(let i=0; i< arr_tempX.length; i++){this.arr_bX.push(arr_tempX[i])this.arr_bY.push(arr_tempY[i])}}this.drawStaticBlock()}//一行满了清空方块,上面方块Y坐标+1clearUnderBlock(){//删除低层方块let arr_row=[]let line_numif (this.arr_store_X.length != 0) {for(let j = this.height-1; j >= 0; j--){for(let i = 0; i < this.arr_store_color.length; i++){if (this.arr_store_Y[i] == j) {arr_row.push(i)}}if (arr_row.length == this.width) {line_num = jbreak}else{arr_row.splice(0, arr_row.length)}}}if (arr_row.length == this.width) {//计算成绩gradethis.grade++document.getElementById('text').innerHTML = '当前成绩:'+this.gradefor(let i = 0; i < arr_row.length; i++){this.arr_store_X.splice(arr_row[i]-i, 1)this.arr_store_Y.splice(arr_row[i]-i, 1)this.arr_store_color.splice(arr_row[i]-i, 1)}//让上面的方块往下掉一格for(let i = 0; i < this.arr_store_color.length; i++){if (this.arr_store_Y[i] < line_num) {this.arr_store_Y[i] = this.arr_store_Y[i]+1}}}}//判断游戏结束gameover(){for(let i=0; i < this.arr_store_X.length; i++){if (this.arr_store_Y[i] == 0) {clearInterval(this.ident)this.over = true}}}}let tetrisObj = new tetris()tetrisObj.gameStart()//方向键功能函数document.onkeydown = (e) => {   if (tetrisObj.over)returnswitch(e.keyCode){case 40:  // 方向为下tetrisObj.down_speed_up()breakcase 32:  // 空格换方向tetrisObj.initBackground()        //重画地图tetrisObj.up_change_direction(tetrisObj.num_blcok)tetrisObj.drawBlock(tetrisObj.type_color)breakcase 37:  // 方向为左tetrisObj.initBackground()tetrisObj.move(-1)tetrisObj.drawBlock(tetrisObj.type_color)breakcase 39:  // 方向为右tetrisObj.initBackground()tetrisObj.move(1)tetrisObj.drawBlock(tetrisObj.type_color)break}    }</script>
</body>
</html>

HTML实现一个贪吃蛇

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>html5实现贪吃蛇小游戏</title>
<style>
#myCanvas {box-shadow: 0 0 6px #000;
}
</style>
</head>
<body>
<br/><br/><br/>
<input type="button" value="开始游戏" onclick="beginGame();"><br/><br/><br/>
<canvas id="myCanvas" width="450" height="450"></canvas><script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var w = 15; //格子宽、高
var snaLen = 6; //初始长度
var snake = []; //身体长度
for (var i = 0; i < snaLen; i++) {snake[i] = new cell(i, 0, 39);
}
var head = snake[snaLen - 1]; //头部
//初始食物
var foodx = Math.ceil(Math.random() * 28 + 1);
var foody = Math.ceil(Math.random() * 28 + 1);
var food = new Food(foodx, foody);
//食物
function Food(x, y) {this.x = x;this.y = y;return this;
}//身体
function cell(x, y, d) {this.x = x;this.y = y;this.d = d;return this;
}//动作
function draw() {ctx.clearRect(0, 0, 450, 450);//画布局//      for(var i = 0; i < 30; i++){//          ctx.strokeStyle = "#ccc";//线条颜色//          ctx.beginPath();//          ctx.moveTo(0,i*w);//          ctx.lineTo(450,i*w);//          ctx.moveTo(i*w,0);//          ctx.lineTo(i*w,450);//          ctx.closePath();//          ctx.stroke();//      }//画蛇身for (var j = 0; j < snake.length; j++) {ctx.fillStyle = "green";if (j == snake.length - 1) {ctx.fillStyle = "red";}ctx.beginPath();ctx.rect(snake[j].x * w, snake[j].y * w, w, w);ctx.closePath();ctx.fill();ctx.stroke();}//出现食物drawFood();//吃到食物if (head.x == food.x && head.y == food.y) {initFood();food = new Food(foodx, foody);//重新出现食物drawFood();//增加蛇的长度  有些小瑕疵,蛇身增长时应该是身体增长,而不是在蛇头上增长var newCell = new cell(head.x, head.y, head.d);switch (head.d) {case 40:newCell.y++;break; //下case 39:newCell.x++;break; //右case 38:newCell.y--;break; //上case 37:newCell.x--;break; //左}snake[snake.length] = newCell;head = newCell;//head = }
}
//随机初始化食物
function initFood() {foodx = Math.ceil(Math.random() * 28 + 1);foody = Math.ceil(Math.random() * 28 + 1);for (var i = 0; i < snake.length; i++) {if (snake[i].x == foodx && snake[i].y == foody) {initFood();}}
}
//画食物
function drawFood() {//绘制食物ctx.fillStyle = "orange";ctx.beginPath();ctx.rect(food.x * w, food.y * w, w, w);ctx.closePath();ctx.fill();
}
draw();
//监听键盘事件
document.onkeydown = function(e) {//下40 , 右边39,左边37,上38  键盘事件var keyCode = e.keyCode;if (head.d - keyCode != 2 && head.d - keyCode != -2 && keyCode >= 37 && keyCode <= 40) {moveSnake(keyCode);}
}
//控制蛇移动方向
function moveSnake(keyCode) {var newSnake = [];var newCell = new cell(head.x, head.y, head.d); //头//身体for (var i = 1; i < snake.length; i++) {newSnake[i - 1] = snake[i];}newSnake[snake.length - 1] = newCell;newCell.d = keyCode;switch (keyCode) {case 40:newCell.y++;break; //下case 39:newCell.x++;break; //右case 38:newCell.y--;break; //上case 37:newCell.x--;break; //左}snake = newSnake;head = snake[snake.length - 1];checkDeath();draw();
}
//游戏规则
function checkDeath() {//超出边框if (head.x >= 30 || head.y >= 30 || head.x < 0 || head.y < 0) {alert("Game over!");window.location.reload();}//咬到自己for (var i = 0; i < snake.length - 1; i++) {if (head.x == snake[i].x && head.y == snake[i].y) {alert("Game over!");window.location.reload();}}
}
//蛇自动走
function moveClock() {moveSnake(head.d);
}
var isMove = false;
function beginGame() {!isMove && setInterval(moveClock, 300);isMove = true;
}</script></body>
</html>

这篇关于JS - 事件处理:鼠标移动监听事件、div块跟随鼠标移动事件、事件的绑定、实现拖拽效果的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/910442

相关文章

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

禁止平板,iPad长按弹出默认菜单事件

通过监控按下抬起时间差来禁止弹出事件,把以下代码写在要禁止的页面的页面加载事件里面即可     var date;document.addEventListener('touchstart', event => {date = new Date().getTime();});document.addEventListener('touchend', event => {if (new

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P