JavaScript事件处理

在IE 3.0和Netscape 2.0浏览器中开始出现事件。DOM 2规范开始标准化DOM事件,直到2004年发布DOM 3.0时,W3C才完善事件模型。目前,所有主流浏览器都支持DOM 2事件模块。IE8及其早期版本还继续使用IE事件模块。

1、事件基础

1.1、事件模型

在浏览器发展历史中,出现以下4种事件处理模型:

  • 基本事件模型:也称为DOM 0事件模型。它是浏览器初期出现的一种比较简单的事件模型,主要通过HTML事件属性,为指定标签绑定事件处理函数。由于这种模型应用比较广泛,获得了所有浏览器的支持,目前依然比较流行。但是这种模型对于HTML文档标签依赖严重,不利于JavaScript独立开发。
  • DOM事件模型:由W3C制定,是目前标准的事件处理模型。除了IE怪异模式不支持外,符合标准的浏览器都支持该模型。DOM事件模型包括DOM 2事件模块和DOM 3事件模块,DOM 3事件模块为DOM 2事件模块的升级版,较DOM 2事件模块略有完善,主要是新增加一些事情类型,以适应移动设备的开发需要,但大部分规范和用法保持一致。
  • IE事件模型:IE 4.0及其以上版本浏览器支持,与DOM事件模型相似,但用法不同。
  • Netscape事件模型:由Netscape 4浏览器实现,在Netscape 6中停止支持。

1.2、事件流

事件流就是多个节点对象对同一个事件进行响应的先后顺序,主要包括以下3种类型:

1.冒泡型

事件从最特定的目标向最不特定的目标(document对象)触发,也就是事件从下向上进行响应,这个传递过程被形象地称为冒泡。

2.捕获型

事件从最不特定的目标(document对象)开始触发,然后到最特定的目标,也就是事件从上向下进行响应。

3.混合型

W3C的DOM事件模型支持捕获型和冒泡型两种事件流,其中捕获型事件流先发生,然后发生冒泡型事件流。两种事件流会触及DOM中的所有层级对象,从document对象开始,最后返回document对象结束。

因此,可以把事件传播的整个过程分为3个阶段:

  • 捕获阶段:事件从document对象沿着文档树向下传播到目标节点,如果目标节点的任何一个上级节点注册了相同事件,那么事件在传播的过程中就会首先在最接近顶部的上级节点执行,依次向下传播。
  • 目标阶段:注册在目标节点的事件被执行。
  • 冒泡阶段:事件从目标节点向上触发,如果上级节点注册了相同的事件,将会逐级响应,依次向上传播。

1.3、绑定事件

在基本事件模型中,JavaScript支持两种绑定方式。

1.静态绑定

把JavaScript脚本作为属性值,直接赋予事件属性。

【示例1】把JavaScript脚本以字符串的形式传递给onclick属性,为<button>标签绑定click事件。当单击按钮时,就会触发click事件,执行这行JavaScript脚本:

    <button onclick="alert('你单击了一次!');">按钮</button>

2.动态绑定

使用DOM对象的事件属性进行赋值。

【示例2】使用document.getElementById()方法获取button元素,然后把一个匿名函数作为值传递给button元素的onclick属性,以实现事件绑定操作:

    <button id="btn">按钮</button>
    <script>
    var button = document.getElementById("btn");
    button.onclick = function(){
        alert("你单击了一次!");
    }
    </script>

可以在脚本中直接为页面元素附加事件,不破坏HTML结构,比上一种方式灵活。

1.4、事件处理函数

事件处理函数是一类特殊的函数,与函数直接量结构相同,主要任务是实现事件处理,为异步调用,由事件触发进行响应。

事件处理函数一般没有明确的返回值。不过在特定事件中,用户可以利用事件处理函数的返回值影响程序的执行,如单击超链接时,禁止默认的跳转行为。

【示例1】为form元素的onsubmit事件属性定义字符串脚本,设计当文本框中输入值为空时,定义事件处理函数返回值为false,这样将强制表单禁止提交数据:

    <form id="form1" name="form1" method="post" action="http://www.mysite.cn/" onsubmit="if(this.elements[0].value.length==0)
return false;">
        姓名:<input id="user" name="user" type="text" />
        <input type="submit" name="btn" id="btn" value="提交" />
    </form>

在上面代码中,this表示当前form元素,elements[0]表示姓名文本框,如果该文本框的value.length属性值长度为0,表示当前文本框为空,则返回false,禁止提交表单。

事件处理函数不需要参数。在DOM事件模型中,事件处理函数默认包含event参数对象,event对象包含事件信息,在函数内进行传播。

【示例2】为按钮绑定一个单击事件。在这个事件处理函数中,参数e为形参,响应事件之后,浏览器会把event对象传递给形参变量e,再把event对象作为一个实参进行传递,读取event对象包含的事件信息,在事件处理函数中输出当前源对象节点名称。实现效果如下图所示:

    <button id="btn">按    钮</button>
    <script>
    var button = document.getElementById("btn");
    button.onclick = function(e){
        var e = e || window.event;                                //获取事件对象
        document.write(e.srcElement ? e.srcElement : e.target);   //获取当前单击对象的标签名
    }
    </script>

在这里插入图片描述
【示例3】定义当单击按钮时改变当前按钮的背景色为红色,其中this关键字表示button按钮对象:

    <button id="btn" onclick="this.style.background='red';">按钮
</button>

也可以使用下面一行代码表示:

    <button id="btn" onclick="(event.srcElement?event.srcElement:
event.target).style.background='red';">按钮</button>

1.5、注册事件

在DOM事件模型中,通过调用对象的addEventListener()方法注册事件,用法如下:

    element.addEventListener(String type, Function listener, boolean useCapture);

参数说明如下:

  • type:注册事件的类型名。事件类型与事件属性不同,事件类型名没有on前缀。例如,对于事件属性onclick来说,所对应的事件类型为click。
  • listener:监听函数,即事件处理函数。在指定类型的事件发生时将调用该函数。在调用这个函数时,默认传递给它的唯一参数是event对象。
  • useCapture:它是一个布尔值。如果为true,则指定的事件处理函数将在事件传播的捕获阶段触发;如果为false,则事件处理函数将在冒泡阶段触发。

提示:使用addEventListener()方法能够为多个对象注册相同的事件处理函数,也可以为同一个对象注册多个事件处理函数。为同一个对象注册多个事件处理函数对于模块化开发非常有用。

【示例1】为段落文本注册两个事件:mouseover和mouseout。当鼠标移到段落文本上面时会显示为蓝色背景,而当鼠标移出段落文本时会自动显示为红色背景。这样就不需要破坏文档结构为段落文本增加多个事件属性:

    <p id="p1">为对象注册多个事件</p>
    <script>
    var p1 = document.getElementById("p1");            //捕获段落元素的句柄
    p1.addEventListener("mouseover", function(){
        this.style.background = 'blue';
    } , true);                                         //为段落元素注册第1个事件处理函数
    p1.addEventListener("mouseout", function(){
        this.style.background = 'red';
    }, true);                                          //为段落元素注册第2个事件处理函数
    </script>

IE事件模型使用attachEvent()方法注册事件,用法如下:

    element.attachEvent(etype,eventName)

参数说明如下:

  • etype:设置事件类型,如onclick、onkeyup、onmousemove等。
  • eventName:设置事件名称,也就是事件处理函数。

【示例2】为段落标签

标签注册两个事件:mouseover和mouseout,设计当鼠标经过时,段落文本背景色显示为蓝色,当鼠标移开之后,背景色显示为红色:

    <p id="p1">IE事件注册</p>
    <script>
    var p1 = document.getElementById("p1");         //捕获段落元素
    p1.attachEvent("onmouseover", function(){
        p1.style.background = 'blue';
    });                                             //注册mouseover事件
    p1.attachEvent("onmouseout", function(){
        p1.style.background = 'red';
    });                                             //注册mouseout事件
    </script>

提示:使用attachEvent()注册事件时,其事件处理函数的调用对象不再是当前事件对象本身,而是window对象,因此事件函数中的this就指向window,而不是当前对象,如果要获取当前对象,应该使用event的srcElement属性。

注意,IE事件模型中的attachEvent()方法第一个参数为事件类型名称,但需要加上on前缀,而使用addEventListener()方法时,不需要这个on前缀,如click。

1.6、销毁事件

在DOM事件模型中,使用removeEventListener()方法可以从指定对象中删除已经注册的事件处理函数。用法如下:

    element.removeEventListener(String type, Function listener, boolean useCapture);

参数说明参阅addEventListener()方法参数说明。

【示例1】在下面示例中,分别为按钮a和按钮b注册click事件,其中按钮a的事件函数为ok(),按钮b的事件函数为delete_event()。在浏览器中预览,单击“点我”按钮,将弹出一个对话框,在删除之前这个事件是一直存在的。在单击“删除事件”按钮之后,“点我”按钮将失去任何效果:

    <input id="a" type="button" value="点我" />
    <input id="b" type="button" value="删除事件" />
    <script>
    var a = document.getElementById("a");             //获取按钮a
    var b = document.getElementById("b");             //获取按钮b
    function ok(){                                    //按钮a的事件处理函数
        alert("您好,欢迎光临!");
    }
    function delete_event(){                          //按钮b的事件处理函数
        a.removeEventListener("click",ok,false);      //移出按钮a的click事件
    }
    a.addEventListener("click",ok,false);             //默认为按钮a注册事件
    b.addEventListener("click",delete_event,false);   //默认为按钮b注册事件
    </script>

在这里插入图片描述
提示:removeEventListener()方法只能够删除addEvent-Listener()方法注册的事件。如果直接使用onclick等直接写在元素上的事件,将无法使用removeEventListener()方法删除。

当临时注册一个事件时,可以在处理完毕之后迅速删除它,这样能够节省系统资源。

IE事件模型使用detachEvent()方法注销事件,用法如下:

    element.detachEvent(etype,eventName)

参数说明参阅attachEvent()方法参数说明。

由于IE怪异模式不支持DOM事件模型,为了保证页面的兼容性,开发时需要兼容两种事件模型以实现在不同浏览器中具有相同的交互行为。

1.7、使用event对象

event对象由事件自动创建,记录了当前事件的状态,如事件发生的源节点、键盘按键的响应状态、鼠标指针的移动位置、鼠标按键的响应状态等信息。event对象的属性提供了有关事件的细节,其方法可以控制事件的传播。

2级DOM Events规范定义了一个标准的事件模型,它被除了IE怪异模式以外的所有现代浏览器所实现,而IE定义了专用的、不兼容的模型。简单比较两种事件模型:

  • 在DOM事件模型中,event对象被传递给事件处理函数,但是在IE事件模型中,它被存储在window对象的event属性中。
  • 在DOM事件模型中,event类型的各种子接口定义了额外的属性,它们提供了与特定事件类型相关的细节;在IE事件模型中,只有一种类型的event对象,它用于所有类型的事件。

下面列出了2级DOM事件标准定义的event对象属性,如下表所示。注意,这些属性都是只读属性。
在这里插入图片描述
下面列出了2级DOM事件标准定义的event对象方法,如下表所示,IE事件模型不支持这些方法:
在这里插入图片描述

1.8、委托事件

事件委托(delegate)也称为事件托管或事件代理,就是把目标节点的事件绑定到祖先节点上。这种简单而优雅的事件注册方式是基于事件传播过程中,逐层冒泡总能被祖先节点捕获。

委托的好处:优化代码,提升运行性能,真正把HTML和JavaScript分离,也能防止在动态添加或删除节点过程中,注册事件丢失的现象。

【示例1】使用一般方法为列表结构中每个列表项目绑定click事件,单击列表项目,将弹出提示对话框,提示当前节点包含的文本信息。但是,当我们为列表框动态添加列表项目之后,新添加的列表项目没有绑定click事件,这与我们的愿望相反:

    <button id="btn">添加列表项目</button>
    <ul id="list">
        <li>列表项目1</li>
        <li>列表项目2</li>
        <li>列表项目3</li>
    </ul>
    <script>
    var ul=document.getElementById("list");
    var lis=ul.getElementsByTagName("li");
    for(var i=0;i<lis.length;i++){
        lis[i].addEventListener('click',function(e){
            var e = e || window.event;
            var target = e.target || e.srcElement;
            alert(e.target.innerHTML);
        },false);
    }
    var i = 4;
    var btn=document.getElementById("btn");
    btn.addEventListener("click",function(){
        var li = document.createElement("li");
        li.innerHTML = "列表项目" + i++;
        ul.appendChild(li);
    });
    </script>

在这里插入图片描述
【示例2】下面示例借助事件委托技巧,利用事件传播机制,在列表框ul元素上绑定click事件,当事件传播到父节点ul上时,捕获click事件,然后在事件处理函数中检测当前事件响应节点类型,如果是li元素,则进一步执行下面代码,否则跳出事件处理函数,结束响应:

    <button id="btn">添加列表项目</button>
    <ul id="list">
        <li>列表项目1</li>
        <li>列表项目2</li>
        <li>列表项目3</li>
    </ul>
    <script>
    var ul=document.getElementById("list");
    ul.addEventListener('click',function(e){
        var e = e || window.event;
        var target = e.target || e.srcElement;
        if(e.target&&e.target.nodeName.toUpperCase()=="LI"){     /*判断目标事件是否为li*/
            alert(e.target.innerHTML);
        }
    },false);
    var i = 4;
    var btn=document.getElementById("btn");
    btn.addEventListener("click",function(){
        var li = document.createElement("li");
        li.innerHTML = "列表项目" + i++;
        ul.appendChild(li);
    });
    </script>

当页面存在大量元素,并且每个元素注册了一个或多个事件时,可能会影响性能。访问和修改更多的DOM节点,程序就会更慢,特别是事件连接过程都发生在load(或DOMContentReady)事件中时,对任何一个富交互网页来说,这都是一个繁忙的时间段。另外,浏览器需要保存每个事件句柄的记录,也会占用更多内存。

2、实战

2.1、鼠标拖曳

鼠标事件是Web开发中最常用的事件类型,鼠标事件类型详细说明如下表所示:
在这里插入图片描述
【示例】下面示例演示了如何综合应用各种鼠标事件实现页面元素拖放操作的设计过程。实现拖放操作设计,需要解决以下几个问题:

  • 定义拖放元素为绝对定位,以及设计事件的响应过程。这个比较容易实现。
  • 清楚几个坐标概念:单击鼠标时的指针坐标、移动中当前鼠标的指针坐标、松开鼠标时的指针坐标、拖放元素的原始坐标、拖动中的元素坐标。
  • 算法设计:单击鼠标时,获取被拖放元素和鼠标指针的位置,在移动中实时计算鼠标偏移的距离,并利用该偏移距离加上被拖放元素的原坐标位置,获得拖放元素的实时坐标。

如下图所示,其中变量ox和oy分别记录按下鼠标时被拖放元素的横、纵坐标值,它们可以通过事件对象的offsetLeft和offsetTop属性获取。变量mx和my分别表示按下鼠标时,鼠标指针的坐标位置。而event.mx和event.my是事件对象的自定义属性,用它们来存储当鼠标移动时鼠标指针的实时位置。
在这里插入图片描述
当获取了上面3对坐标值之后,就可以动态计算拖动中元素的实时坐标位置,即x轴值为ox +event.mx – mx,y轴值为oy + event.my – my。当释放鼠标按钮时,则可以释放事件类型,并记下松开鼠标指针时拖动元素的坐标值,以及鼠标指针的位置,留待下一次拖放操作时调用。

完整拖放操作的示例代码如下:

    <div id="box" ></div>
    <script>
                                                             //初始化拖放对象
    var box = document.getElementById("box");                //获取页面中被拖放元素的引用指针
    box.style.position = "absolute";                         //绝对定位
    box.style.width = "160px";                               //定义宽度
    box.style.height = "120px";                              //定义高度
    box.style.backgroundColor = "red";                       //定义背景色
                                                             //初始化变量,标准化事件对象
    var mx, my, ox, oy;                                      //定义备用变量
    function e(event){                                       //定义事件对象标准化函数
      if( ! event){                                          //兼容IE事件模型
          event = window.event;
          event.target = event.srcElement;
          event.layerX = event.offsetX;
          event.layerY = event.offsetY;
      }
      event.mx = event.pageX || event.clientX + document.body.scrollLeft;
                                                             //计算鼠标指针的x轴距离
      event.my = event.pageY || event.clientY + document.body.scrollTop;
                                                             //计算鼠标指针的y轴距离
      return event;                                          //返回标准化的事件对象
    }
                                                             //定义鼠标事件处理函数
    document.onmousedown = function(event){                  //按下鼠标时,初始化处理
      event = e(event);                                      //获取标准事件对象
      o = event.target;                                      //获取当前拖放的元素
      ox = parseInt(o.offsetLeft);                           //拖放元素的x轴坐标
      oy = parseInt(o.offsetTop);                            //拖放元素的y轴坐标
       mx = event.mx;                                        //按下鼠标指针的x轴坐标
       my = event.my;                                        //按下鼠标指针的y轴坐标
      document.onmousemove = move;                           //注册鼠标移动事件处理函数
      document.onmouseup = stop;                             //注册松开鼠标事件处理函数
    }
    function move(event){                                    //鼠标移动处理函数
      event = e(event);
      o.style.left = ox + event.mx - mx  + "px";             //定义拖动元素的x轴距离
      o.style.top = oy + event.my - my + "px";               //定义拖动元素的y轴距离
    }
    function stop(event){                                    //松开鼠标处理函数
      event = e(event);
      ox = parseInt(o.offsetLeft);                           //记录拖放元素的x轴坐标
      oy = parseInt(o.offsetTop);                            //记录拖放元素的y轴坐标
       mx = event.mx ;                                       //记录鼠标指针的x轴坐标
       my = event.my ;                                       //记录鼠标指针的y轴坐标
      o = document.onmousemove = document.onmouseup = null;  //释放所有操作对象
    }
    </script>

2.2、鼠标移动

在下面实例中分别为3个嵌套的div元素定义了mouseover和mouseout事件处理函数,这样从外层的父元素中移动到内部的子元素中时,将会触发父元素的mouseover事件类型,但是不会触发mouseout事件类型。

    <div>
        <div>
            <div>盒子</div>
        </div>
    </div>
    <script>
    var div = document.getElementsByTagName("div");        //获取3个嵌套的div元素
    for(var i=0;i<div.length;i++){                         //遍历嵌套的div元素
        div[i].onmouseover = function(e){                  //注册移过事件处理函数
            this.style.border = "solid blue";
        }
        div[i].onmouseout = function(){                    //注册移出事件处理函数
            this.style.border = "solid red";
        }
    }
    </script>

2.3、鼠标定位

当事件发生时,获取鼠标的位置是很重要的事件。由于浏览器的不兼容性,不同浏览器分别在各自事件对象中定义了不同的属性,说明如下表所示。这些属性都以像素值定义了鼠标指针的坐标,但是它们参照的坐标系不同,导致准确计算鼠标的位置比较麻烦。
在这里插入图片描述
【示例】下面介绍如何配合使用多种鼠标坐标属性,以实现兼容不同浏览器的鼠标定位设计方案。

首先,来看看screenX和screenY属性。这两个属性获得了所有浏览器的支持,应该说是最优选用属性,但是它们的坐标系是计算机屏幕,也就是说,以计算机屏幕左上角为定位原点。这对于以浏览器窗口为活动空间的网页来说,没有任何价值。因为不同的屏幕分辨率、不同的浏览器窗口大小和位置都使在网页中定位鼠标成为一件很困难的事情。

其次,如果以document对象为坐标系,则可以考虑选用pageX和pageY属性,实现在浏览器窗口中进行定位。这对于设计鼠标跟随是一个好主意,因为跟随元素一般都以绝对定位的方式在浏览器窗口中移动,在mousemove事件处理函数中把pageX和pageY属性值传递给绝对定位元素的top和left样式属性即可。

IE事件模型不支持pageX和pageY属性,为此还需寻求兼容IE的方法。再看看clientX和clientY属性是以window对象为坐标系,且IE事件模型支持它们,可以选用它们。不过考虑Window等对象可能出现的滚动条偏移量,所以还应加上相对于window对象的页面滚动的偏移量。

    var posX = 0, posY = 0;                         //定义坐标变量初始值
    var event = event || window.event;              //标准化事件对象
    if(event.pageX || event.pageY){                 //如果浏览器支持该属性,则采用它们
        posX = event.pageX;
        posY = event.pageY;
    }
    else if(event.clientX || event.clientY){        //否则,如果浏览器支持该属性,则采用它们
        posX = event.clientX + document.documentElement.scrollLeft +
        document.body.scrollLeft;
        posY = event.clientY + document.documentElement.scrollTop +
        document.body.scrollTop;
    }

在上面代码中,先检测pageX和pageY属性是否存在,如果存在则获取它们的值;如果不存在,则检测并获取clientX和clientY属性值,然后加上document.documentElement和document.body.对象的scrollLeft和scrollTop属性值,这样在不同浏览器中就获得了相同的坐标值。

2.4、键盘监控

当用户操作键盘时会触发键盘事件,键盘事件主要包括下面3种类型。

  • keydown:在键盘上按下某个键时触发。如果按住某个键,会不断触发该事件,但是Opera浏览器不支持这种连续操作。该事件处理函数返回false时,会取消默认的动作(如输入的键盘字符,在IE和Safari浏览器下还会禁止keypress事件响应)。
  • keypress:按下某个键盘键并释放时触发。如果按住某个键,会不断触发该事件。该事件处理函数返回false时,会取消默认的动作(如输入的键盘字符)。
  • keyup:释放某个键盘键时触发。该事件仅在松开键盘时触发一次,不是一个持续的响应状态。

键盘事件定义了很多属性,如下表所示。利用这些属性可以精确控制键盘操作。键盘事件属性一般只在键盘相关事件发生时才会存在于事件对象中,但是ctrlKey和shiftKey属性除外,因为它们可以在鼠标事件中存在。例如,当按下ctrl或shift键时单击鼠标操作:
在这里插入图片描述
【示例】ctrlKey和shiftKey属性可存在于键盘和鼠标事件中,表示键盘上的Ctrl和Shift键是否被按住。下面示例能够监测Ctrl和Shift键是否被同时按下。如果同时按下,且鼠标单击某个页面元素,则会把该元素从页面中删除:

    document.onclick = function(e){
        var e = e || window.event;             //标准化事件对象
        var t = e.target || e.srcElement;      //获取发生事件的元素,兼容IE和DOM
        if(e.ctrlKey && e.shiftKey)            //如果同时按下Ctrl和Shift键
            t.parentNode.removeChild(t);       //移出当前元素
    }

2.5、键盘移动对象

keyCode和charCode属性使用比较复杂,但是它们在实际开发中又比较常用,故比较这两个属性在不同事件类型和不同浏览器中的表现是非常必要的,如下表所示。读者可以根据需要有针对性地选用事件响应类型和引用属性值。
在这里插入图片描述
某些键的可用性不是很确定,如PageUp和Home键等。不过常用的功能键和字符键都是比较稳定的,如下表所示:
在这里插入图片描述
【示例】下面示例演示了如何使用方向键控制页面元素的移动效果:

    <div id="box"></div>
    <script>
    var box = document.getElementById("box");             //获取页面元素的引用指针
    box.style.position = "absolute";                      //色块绝对定位
    box.style.width = "20px";                             //色块宽度
    box.style.height = "20px";                            //色块高度
    box.style.backgroundColor = "red";                    //色块背景
    document.onkeydown = keyDown;                         //在document对象中注册keyDown事件处理函数
    function keyDown(event){                              //方向键控制元素移动函数
        var event = event || window.event;                //标准化事件对象
        switch(event.keyCode){                            //获取当前按下键盘键的编码
        case 37 :                                         //按下左箭头键,向左移动5个像素
            box.style.left = box.offsetLeft - 5  + "px";
            break;
        case 39 :                                         //按下右箭头键,向右移动5个像素
            box.style.left = box.offsetLeft + 5 + "px";
            break;
        case 38 :                                         //按下上箭头键,向上移动5个像素
            box.style.top = box.offsetTop  - 5 + "px";
            break;
        case 40 :                                         //按下下箭头键,向下移动5个像素
            box.style.top = box.offsetTop  + 5 + "px";
            break;
        }
        return false
    }
    </script>

在上面示例中,首先获取页面元素,然后通过CSS脚本控制元素绝对定位、大小和背景色。然后在document对象上注册鼠标按下事件类型处理函数,在事件回调函数keyDown()中侦测当前按下的方向键,并决定定位元素在窗口中的位置。其中元素的offsetLeft和offsetTop属性可以存取它在页面中的位置。

2.6、页面监控

页面事件主要包括与页面相关的操作响应,常用事件类型说明如下:

  • oad事件在页面完全加载完毕的时候触发。
  • unload事件在从当前浏览器窗口内移动文档的位置时触发。
  • resize事件在浏览器窗口被重置时触发。
  • scroll事件在浏览器窗口内移动文档的位置时触发。
  • error事件在JavaScript代码发生错误时触发。

【示例】在下面示例中,控制红色小盒子始终位于窗口内坐标为(100px,100px)的位置。

    <div id="box"></div>
    <script>
    var box = document.getElementById("box");
    box.style.position = "absolute";
    box.style.backgroundColor = "red";
    box.style.width = "200px";
    box.style.height = "160px";
    window.onload = f;                              //页面初始化时固定其位置
    window.onscroll = f;                            //当文档位置发生变化时重新固定其位置
    function f(){                                   //元素位置固定函数
        box.style.left = 100 + parseInt(document.body.scrollLeft) + "px";
        box.style.top = 100 + parseInt(document.body.scrollTop) + "px";
    }
    </script>
    <div style="height:2000px;width:2000px;"></div>

还有一种方法,就是利用settimeout()函数实现每间隔一定时间校正一次元素的位置,不过这种方法的损耗比较大,不建议选用。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

deepstream生成pipeline拓扑图的方法

deepstream生成pipeline拓扑图的方法 1、前期工作1.1 安装dot 2、使用命令行生成2.1、添加环境变量2.2 、运行管道2.3 、使用dot 生成png图片 3、在c中使用3.1、添加代码3.2、运行代码3.3 、使用dot 生成png图片 4、在python中使用4.1、添加代码4.2 、使用dot 生成png图片 1、前…

【机器学习基础】机器学习入门(2)

&#x1f680;个人主页&#xff1a;为梦而生~ 关注我一起学习吧&#xff01; &#x1f4a1;专栏&#xff1a;机器学习 欢迎订阅&#xff01;后面的内容会越来越有意思~ &#x1f4a1;往期推荐&#xff1a;【机器学习基础】机器学习入门&#xff08;1&#xff09; &#x1f4a1;…

设计模式之工厂模式 ( Factory Pattern )(1)

其他设计模式也会后续更新… 设计模式其实需要有一定开发经验才好理解&#xff0c;对代码有一定的设计要求&#xff0c;工作中融入才是最好的 工厂模式 ( Factory Pattern ) 工厂模式&#xff08;Factory Pattern&#xff09;提供了一种创建对象的最佳方式 工厂模式在创建对…

“ChatGPT 之父”暗讽马斯克;传安卓版本与鸿蒙将不再兼容;PICO 裁撤游戏工作室团队丨 RTE 开发者日报 Vol.83

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

ubuntu开机系统出错且无法恢复。请联系系统管理员。

背景&#xff1a; ubuntu22.04.2命令行&#xff0c;执行自动安装系统推荐显卡驱动命令&#xff0c;字体变大&#xff0c;重启后出现如下图错误&#xff0c;无法进入系统&#xff0c;无法通过CTRLALTF1-F3进入TTY模式。 解决办法&#xff1a; 1.首先要想办法进入系统&#xff…

VMware 虚拟机开启后黑屏问题的解决方式

很好&#xff0c;现在是vm 虚拟机节目的连续剧了 首先&#xff0c;我们安装好了&#xff0c;vm软件。 其次&#xff0c;我们在vm中创建了虚拟机。 再其次&#xff0c;我们解决了&#xff0c;开启虚拟机计算机自动重启的问题。 最后我们遇到了这个问题&#xff1a;虚拟机开启后整…

CSDN的规范、检测文章质量、博客等级好处等等(我也是意外发现的,我相信很多人还不知道,使用分享给大家!)

前言 都是整理官方的文档&#xff0c;方便自己查看和检查使用&#xff0c;以前我也不知道。后来巧合下发现的&#xff0c;所以分享给大家&#xff01; 下面都有官方的链接&#xff0c;详情去看官方的文档。 大家严格按照官方的规范去记录自己工作生活中的文章&#xff0c;很快…

AP/PF PLASMA电源维修等离子变频电源PF23V-A1-138

维修包括&#xff1a;PECVD、MOCVD、IONIMP,PLASMA的设备电源,包括直流、高压、脉冲、射频、微波、匹配器、RPSC、CHILLER等。电源维修的时候&#xff0c;需要检测一下各功率器件是否存在击穿短路&#xff0c;例如电源整流桥堆、开关管、高频大功率整流管、浪涌电流的大功率电阻…

东莞松山湖数据中心|莞服务器托管的优势

东莞位于珠江三角洲经济圈&#xff0c;交通便利&#xff0c;与广州、深圳等大城市相邻&#xff0c;而且东莞是中国重要的制造业基地&#xff0c;有众多的制造业和科技企业集聚于此&#xff0c;随着互联网和数字化时代的到来&#xff0c;企业都向数字化转型&#xff0c;对于信息…

将请求映射到servlet的规则

参考资源 详情可以参考&#xff1a;https://jakarta.ee/specifications/servlet/6.0/jakarta-servlet-spec-6.0.html#mapping-requests-to-servlets URL路径的使用 web容器接收到客户端的请求&#xff0c;决定转发给哪个web应用。被选中的web 应用必须具有最长的上下文&…

【LittleXi】C程序预处理、编译、汇编、链接步骤

【LittleXi】C程序预处理、编译、汇编、链接步骤 C程序 #include<stdio.h> int main(){int x1,y1;printf("xy%d",xy); }1、预处理 将头文件引入进来、除去注释、宏定义下放 执行指令 g -E esc.c -o esc.i 2、编译 将处理好的代码编译为汇编代码.s 执行…

测试行业爬了7年,从功能测试到高级测试,工资也翻了好几倍

我在测试行业爬了7年。从功能测试到现在成为高级测试&#xff0c;我的工资也翻了好几倍。 入门阶段&#xff08;功能测试&#xff09; 个人认为&#xff0c;测试的前景还不错&#xff0c;只要你肯努力&#xff1b;刚出来的时候在鹅厂做外包功能测试。每天都很悠闲。点了两年&a…

Cesium深入浅出之自定义材质

引子 做为一名技术宅却没有能拿得出手的技术无疑是最可悲的事情。三年前&#xff0c;当我第一次接触Cesium的时候就被它强大和炫丽所折服&#xff0c;最关键的是它还是开源的。以前我一直是机械地敲着业务代码&#xff0c;好像计算机程序就只能干这点事情一样&#xff0c;而 C…

基于缎蓝园丁鸟算法优化概率神经网络PNN的分类预测 - 附代码

基于缎蓝园丁鸟算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于缎蓝园丁鸟算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于缎蓝园丁鸟优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针…

[CANN训练营]UART通信笔记

文章目录 前言一、前提知识1.串行通信2.并行通信3.单工、半双工、全双工通信3.1单工通信3.2半双工通信3.3全双工通信 4.补充&#xff1a;通信速率 二、UART通信1.UART通信2.UART工作原理 总结 前言 在ROS学习中&#xff0c;我们在入门基础除了ROS的小乌龟外&#xff0c;在通信…

【云栖2023】林伟:大数据AI一体化的解读

本文根据2023云栖大会演讲实录整理而成&#xff0c;演讲信息如下&#xff1a; 演讲人&#xff1a;林伟 | 阿里云研究员&#xff0c;阿里云计算平台事业部首席架构师&#xff0c;阿里云人工智能平台PAI和大数据开发治理平台DataWorks负责人 演讲主题&#xff1a;大数据AI一体化…

UMI4 AntDesignProV5 如何修改favicon 及放置的位置(AntDesignProV5 V4对比)

项目场景&#xff1a; 修改系统的favicon.ico AntDesignProV4 修改方式 因为在V4版本中&#xff0c;有根目录文件&#xff0c;可在文件中直接指定&#xff1a; <!-- document.ejs --><head><link rel"icon" type"image/x-icon" href&quo…

一篇揭秘Linux高性能服务epoll 的本质

导语 epoll接口是为解决Linux内核处理大量文件描述符而提出的方案。该接口属于Linux下多路I/O复用接口中select/poll的增强。其经常应用于Linux下高并发服务型程序&#xff0c;特别是在大量并发连接中只有少部分连接处于活跃下的情况 (通常是这种情况)&#xff0c;在该情况下能…

卫星位置解算

武大GPS原理及应用 1.广播星历&#xff08;预报星历&#xff09; 预报星历所得的轨道精度有限&#xff0c;精度在2m左右。 2.精密星历 P 、卫星PRN、卫星在地心地固坐标系坐标&#xff08;与wgs84有点差别&#xff09;、卫星钟差。 通过内插或者拟合来获取任意时刻的卫星位…

python---数据库操作

python的错误和异常 异常&#xff1a; 运行期检测到的错误被称为异常。 try语句按照如下方式工作&#xff1a; 首先&#xff0c;执行try子句&#xff08;在关键字try和关键字except之间的语句&#xff09; 如果没有异常发生&#xff0c;忽略except子句&#xff0c;try子句执…