JavaScript事件机制详解:焦点、冒泡、绑定与兼容处理

作者:交互手记时间:2026-10-30 18:21:20浏览:349

本文深入解析JavaScript中的事件机制,涵盖焦点获取与丢失、事件对象event的使用、事件冒泡与捕获原理,以及IE与标准浏览器的兼容处理方案。详细对比了onclick、attachEvent与addEventListener的区别,并提供了键盘事件、默认行为阻止及常见交互案例的实现方法。

焦点与事件对象基础

焦点是指元素接收用户输入的能力,但并非所有元素都能获得焦点。

为元素设置焦点主要有以下几种方式:

第一种是通过鼠标点击。

第二种是通过Tab键导航。

第三种是通过JavaScript代码控制。

以输入框提示文字为例进行说明。

onfocus事件在元素获取焦点时触发。

       element.onfocus = function(){};

onblur事件在元素失去焦点时触发。

       element.onblur = function(){};

使用obj.focus()方法可以为指定元素设置焦点。

使用obj.blur()方法可以取消指定元素的焦点。

使用obj.select()方法可以选择指定元素内的文本内容。

以方块跟随鼠标移动为例进行说明。

event是事件对象,用于存储与当前事件相关的所有信息。

当事件发生时,相关信息会临时保存在event对象中,供后续调用,类似于飞机的黑匣子。

event对象仅在事件处理函数内部调用时才有内容。

判断一个函数是否为事件处理函数,取决于它是否被事件调用,而非定义方式。

浏览器兼容性与事件对象获取

不同浏览器对event对象的处理存在兼容性问题。

       element.onclick = fn1;

在IE和Chrome浏览器中,event是一个内置的全局对象,可以直接使用。


 function fn1(){
   alert(event);
  }

在标准浏览器中,event对象通过事件处理函数的第一个参数传入。


 function fn1(ev){
    alert(ev);
 }

兼容写法如下:


  function fn1(ev){
     var ev = ev || event;
  }

clientX和clientY表示鼠标距离页面可视区的坐标距离。

事件流:冒泡与捕获

以仿select控件为例进行说明。

事件冒泡是指元素接收到事件后,将事件向上传播至父级,直至window对象。

事件捕获是指父元素先接收到事件,再传递给子元素。

注意:IE浏览器不支持事件捕获。在标准绑定中,需特别注意这一点。

事件绑定与解绑方法对比

事件绑定主要有两种实现方式。

第一种方式是直接赋值。

       element.onclick = fn1;

注意:执行oDiv.onclick = fn1;后,

再执行oDiv.onclick = fn2;

此时fn2会覆盖fn1,导致fn1无法执行。

第二种方式是使用特定的绑定方法。

IE浏览器使用obj.attachEvent(事件名称,事件函数)。

该方法不支持事件捕获。

事件名称需要包含'on'前缀。

事件函数的执行顺序:标准浏览器为正序,非标准浏览器为倒序。

在该方法中,this指向window对象。

       element.attachEvent(onclick,fn1);

标准浏览器使用obj.addEventListener(事件名称,事件函数,是否捕获)。

该方法支持事件捕获。

事件名称不需要包含'on'前缀。

事件的执行顺序为正序。

在该方法中,this指向触发该事件的对象。

          element.addEventListener(click,fn1,false);

bind函数用于封装绑定逻辑。


   function bind(obj,evname,fn){
    if(obj.addEventListener){
    obj.addEventListener(evname,fn,false);
    }else{
     obj.attachEvent('on' + evname,function(){
      fn.call(obj);
     });
    }
   }

事件取消绑定主要有两种方法。

第一种是直接赋值null。

    element.onclick = null;

第二种是使用特定的解绑方法。

IE浏览器使用obj.detachEvent(事件名称,事件函数)。

    document.detachEvent('onclick',fn1);

标准浏览器使用obj.removeEventListener(事件名称,事件函数,是否捕获)。

    document.removeEventListener('click',fn1,false); 

键盘事件与默认行为处理

键盘事件以留言本为例进行说明。

onkeydown事件在键盘按键按下时触发。

onkeyup事件在键盘按键抬起时触发。

event.keyCode返回数字类型的键盘键值。

ctrlKey、shiftKey、altKey为布尔值。

当事件触发时,如果shift、ctrl或alt键未按下,则返回false,否则返回true。

默认事件以自定义右键菜单和键盘控制div运动为例进行说明。

事件默认行为是指浏览器在事件发生时默认执行的操作。

阻止默认行为可以使用return false。

oncontextmenu事件在右键菜单显示时触发。

常见交互案例实现

具体案例如下:

方块跟随鼠标移动案例。

onmouseover事件在鼠标移入元素时触发。

注意:触发频率基于时间间隔而非像素距离,在固定间隔内无论鼠标移动多远只触发一次。


<style>
   body{
     height: 2000px;
    }
    #div{
     width:100px;
     height: 100px;
     background:red;
     position: absolute;
    }
   </style>
   <body>
    <div id="div1"></div>
   </body>
   <script>
    var oDiv = document.getElementById('div1');
    document.onmouseover = function(ev){
     var ev = ev || event;
     // 如果当滚动条滚动了(页面的头部部分隐藏了),方块是以页面定位的,而鼠标是以可视区定位的,这样就会产生bug。所以我们要加上滚动条滚动的距离
     var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
     oDIv.style.top = ev.clientX + scrollTop + 'px';
     oDIv.style.left = ev.clientY + 'px';
    }
   </script>

输入框文字提示案例。


  <style></style>
   <body>
    <input type="text" id="text1" value="请输入内容"/>
    <input type="button" id="btn" value="全选" />
   </body>
   <script>
    var oText = document.getElementById('text1');
    var oBtn = document.getElementById('btn');
    oText.onfocus = function(){
     if(this.value == '请输入内容'){
      this.value = '';
     }
    }
    oText.onblur = function(){
     if(this.value == ''){
      this.value = '请输入内容';
     }
    }
    oBtn.onclick = function(){
     oText.select();
    }
   </script>

仿select控件案例。


 <style>
    #div1{
     width: 100px;
     height: 200px;
     border: 1px solid red;
     display: none;
    }
   </style>
   <body>
    <input type="button" value="按钮" id="btn" />
    <div id="div1"></div>
    <p>ppppppppp</p>
    <p>ppppppppp</p>
    <p>ppppppppp</p>
    <p>ppppppppp</p>
    <p>ppppppppp</p>
   </body>
   <script>
   window.onload = function(){
    var oBtn = document.getElementById('btn');
     var oDiv = document.getElementById('div1');
     oBtn.onclick = function(ev){
      var ev = ev || event;
      ev.cancelBubble = true;
      oDiv.style.display = 'block';
     }
     document.onclick = function(){
      oDiv.style.display = 'none';
     }
    }
   </script>

留言本案例。


   <style></style>
   <body>
    <input type="text" id="con"/>
    <ul id="box"></ul>
   </body>
   <script>
    var oUl = document.getElementById('box');
    var oText = document.getElementById('con');
    
    document.onkeyup = function(ev){
     var ev = ev || even; 
     if(ev.keyCode != ''){
      if(ev.keyCode == 13){
       var oLi = document.createElement('li'); 
       oLi.innerHTML = oText.value;
       if(oUl.children[0]){
        oUl.insertBefore(oLi,oUl.children[0]);
       }else{
        oUl.appendChild(oLi);
       }
      } 
     }
    }
  </script>

自定义右键菜单案例。


  <style>
    body{
    height: 2000px;
    }
    #box{
     width: 100px;
     height: 200px;
     background: red;
     display: none;
     position: absolute;;
    }
   </style>
   <body>
    <div id="box"></div>
   </body>
   <script>
    var oBox = document.getElementById('box');
    document.oncontextmenu = function(ev){
     var ev = ev || event;
     var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
     var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
     oBox.style.display = 'block';
     oBox.style.top = scrollTop + ev.clientY + 'px';
     oBox.style.left = scrollLeft + ev.clientX + 'px';
 
     return false;
    }
    document.onclick = function(){
     oBox.style.display = 'none';
    }
   </script>

键盘控制div运动案例。


   <style>
    #box{
     width: 100px;
     height: 100px;
     background: red;
     position: absolute;
    }
   </style>
   <body>
    <div id="box"></div>
   </body>
   <script>
    var oBox = document.getElementById('box');
    var timer = null;
    var oLeft = false;
    var oTop = false;
    var oRight = false;
    var oBottom = false;
    // 运动一直就绪,等待按键操作
    timer = setInterval(function(){
     if(oLeft){
     oBox.style.left = oBox.offsetLeft - 10 + 'px';
     }else if(oTop){
      oBox.style.top = oBox.offsetTop - 10 + 'px';
     }else if(oRight){
      oBox.style.left = oBox.offsetLeft + 10 + 'px';
     }else if(oBottom){
      oBox.style.top = oBox.offsetTop + 10 + 'px';
     }
     // 防止溢出
     limit();
    },10); 
    // 按键按下,开始运动
    document.onkeydown = function(ev){
     var ev = ev || even;
     switch (ev.keyCode){
      case 37:
       oLeft = true;
       break;
      case 38:
       oTop = true;
       break;
      case 39:
       oRight = true;
       break;
      case 40:
       oBottom = true;
       break;
     }
    }
    // 按键抬起,停止运动
    document.onkeyup = function(ev){
     var ev = ev || even;
     switch (ev.keyCode){
      case 37:
       oLeft = false;
       break;
      case 38:
       oTop = false;
       break;
      case 39:
       oRight = false;
       break;
      case 40:
       oBottom = false;
       break;
     }
    }
    function limit(){
     // 控制左边
     if(oBox.offsetLeft <= 0){
      oBox.style.left = 0;
     }
     // 控制上边
     if(oBox.offsetTop <= 0){
      oBox.style.top = 0;
     }
     // 控制右边
     if(document.documentElement.clientWidth - oBox.offsetLeft - oBox.offsetWidth < 0){
      oBox.style.left = document.documentElement.clientWidth - oBox.offsetWidth + 'px';
     }
     // 控制下边
     if(document.documentElement.clientHeight - oBox.offsetTop - oBox.offsetHeight < 0){
      oBox.style.top = document.documentElement.clientHeight - oBox.offsetHeight + 'px';
     }
    }
   </script>

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持本站!

作者最新文章