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

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

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

  • HTML事件处理程序 :直接在HTML元素上使用事件属性(比如onclick、onmouseover)来指定事件处理函数。

    html 复制代码
    <button onclick="myFunction()">Click me</button>
  • DOM属性事件处理程序 :通过JavaScript代码为DOM元素的事件属性赋值来指定事件处理函数。

    js 复制代码
    document.getElementById("myButton").onclick = function() {
        // 事件处理逻辑
    };
  • DOM方法事件处理程序 :使用addEventListener()方法或attachEvent()方法(在IE中)来为元素添加事件监听器。

    js 复制代码
    document.getElementById("myButton").addEventListener("click", function() {
        // 事件处理逻辑
    });
  • 事件委托 :将事件处理程序绑定在父元素上,通过事件冒泡的机制来处理子元素的事件,提高性能和代码简洁度。

    js 复制代码
    document.getElementById("parentElement").addEventListener("click", function(event) {
        if (event.target.tagName === 'BUTTON') {
            // 处理按钮点击事件
        }
    });
  • 第三方库或框架:许多JavaScript库和框架(如jQuery、React、Vue等)提供了自己的事件绑定机制,简化了事件处理的操作。

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

鼠标移动监听事件

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">
    #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中来显示鼠标的坐标
        //来获取两个div
        var 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块跟随鼠标移动事件

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: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可以跟随鼠标移动
        //获取box1
        var 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";
        };

        //获取box2
        var 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>

事件的冒泡

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>

事件的委托

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("添加一个超链接");

            //创建一个li
            var li=document.createElement("li");
            
            li.innerHTML="<a href='javascript:;'>新建的超链接class='link'</a>";

            //将li添加到ul中
            u1.appendChild(li);
        };
        
        //为每一个超链接都绑定一个单击响应函数
        //为每一个超链接都绑定一个单击响应函数,这种操作比较麻烦
        //而且这些操作只能为已有的超链接设置事件,而新添加的超链接必须重新绑定

        /*
        //获取所有的a
        var 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>

事件的绑定

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)的可能性。通过在祖先元素上绑定事件处理程序,可以在冒泡阶段捕获子元素上的事件,减少事件处理程序的数量,提高性能和代码简洁度。

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: 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
        //一般情况下我们不会希望在捕获阶段触发事件,所以这个参数一般都是false
        box1.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

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;
    }
    </style>

    <script type="text/javascript">
        window.onload=function()
        {
            //拖拽box1元素
            //拖拽的流程
            //1.当鼠标在被拖拽元素上按下时,开始拖拽 onmousedown
            //2.当鼠标移动时被拖拽元素跟随鼠标移动 onmousemove
            //3.当鼠标松开时,被拖拽元素固定在当前位置 onmouseup
            
            //获取box1
            var 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-元素.offsetTo
                var ol=event.clientX - box1.offsetLeft;
                var ot=event.clientY - box1.offsetTop;

                //给document绑定一个onmousemove
                document.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>

拖拽效果实现图片拖拽

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
        //传递一个参数:开启拖拽的元素obj
        function drag(obj)
        {
            obj.onmousedown=function(event)
            {
                //div的水平偏移量 鼠标.clentX-元素.offsetLeft
                //div的垂直偏移量 鼠标.clentY-元素.offsetTo
                var 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
            
            //获取box1
            var 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>

实现滚动事件

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的div
        var 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>

实现一个键盘监听事件

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是指键盘字符代码
        //获取input1
        var input1=document.getElementById("input1");
        //键盘事件
        //onkeydown 按键被按下
        //对于onkeydown来说 如果一直按着某个按键不松手,则事件会被一直触发
        //当onkeydown连续触发时,第一次和第二次之间会间隔稍微长一点,其他的会非常快
        //防止误操作的发生
        //onkeyup 按键被松开 但他不会被连续触发,只能一次一次触发
        //键盘事件一般都会绑定给一些可以获取到焦点的对象(也就是可以获取光标的对象)或者是document

        //如何知道键盘敲击的是什么字符?需要使用event
        document.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移动

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;
    }
    </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()
        {
            //设置方向为0
            dir=0;
        };
    };
    </script>
</head>
<body>
    <div id="box1"></div>
</body>
</html>

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_color
                this.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 = color
                this.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-1
 
                if (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)
                            break
                        case 2:
                            this.arr_bX.push(temp,temp-1,temp-1,temp+1)
                            this.arr_bY.push(1,0,1,1)
                            break
                        case 3:
                            this.arr_bX.push(temp,temp-1,temp+1,temp+2)
                            this.arr_bY.push(0,0,0,0)
                            break
                        case 4:
                            this.arr_bX.push(temp,temp-1,temp,temp+1)
                            this.arr_bY.push(0,0,1,1)
                            break
                        case 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'
                            break
                        case 2:
                            this.type_color='yellow'
                            break
                        case 3:
                            this.type_color='#2FE0BF'
                            break
                        case 4:
                            this.type_color='red'
                            break
                        case 5:
                            this.type_color='gray'
                            break
                        case 6:
                            this.type_color='#C932C6'
                            break
                        case 7:
                            this.type_color= '#FC751B'
                            break
                        case 8:
                            this.type_color= '#6E6EDD'
                            break
                        case 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 = true
                flag_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 = true
                    flag_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 = true
                    flag_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)
                            break
                        case 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)
                            break
                        case 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)
                            break
                        case 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)
                            break
                        case 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)
                            break
                        case 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)
                            break
                        case 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)
                            break
                        case 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)
                            break
                        case 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)
                            break
                        case 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)
                            break
                        case 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)
                            break
                        case 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)
                            break
                        case 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坐标+1
            clearUnderBlock(){
                //删除低层方块
                let arr_row=[]
                let line_num
                if (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 = j
                            break
                        }else{
                            arr_row.splice(0, arr_row.length)
                        }
                    }
                }
                     
                if (arr_row.length == this.width) {
                    //计算成绩grade
                    this.grade++
                     
                    document.getElementById('text').innerHTML = '当前成绩:'+this.grade
                    for(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)
                return
 
            switch(e.keyCode){
                case 40:  // 方向为下
                    tetrisObj.down_speed_up()
                    break
                case 32:  // 空格换方向
                    tetrisObj.initBackground()        //重画地图
                    tetrisObj.up_change_direction(tetrisObj.num_blcok)
                    tetrisObj.drawBlock(tetrisObj.type_color)
                    break
                case 37:  // 方向为左
                    tetrisObj.initBackground()
                    tetrisObj.move(-1)
                    tetrisObj.drawBlock(tetrisObj.type_color)
                    break
                case 39:  // 方向为右
                    tetrisObj.initBackground()
                    tetrisObj.move(1)
                    tetrisObj.drawBlock(tetrisObj.type_color)
                    break
            }    
        }
 
    </script>
</body>
</html>

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>
相关推荐
迷雾漫步者6 分钟前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-33 分钟前
验证码机制
前端·后端
燃先生._.2 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖3 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
m0_748235243 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240253 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar3 小时前
纯前端实现更新检测
开发语言·前端·javascript
寻找沙漠的人4 小时前
前端知识补充—CSS
前端·css
GISer_Jing4 小时前
2025前端面试热门题目——计算机网络篇
前端·计算机网络·面试