Home  >  Article  >  Web Front-end  >  JavaScript event binding and in-depth_basic knowledge

JavaScript event binding and in-depth_basic knowledge

WBOY
WBOYOriginal
2016-05-16 16:04:271066browse

Event binding is divided into two types:

One is traditional event binding (inline model/script model); content of the previous chapter;
One is modern event binding (DOM2-level model); modern event binding provides more powerful functions based on traditional event binding;
1. Problems with traditional event binding

// 脚本模型将一个函数赋值给一个事件处理函数;
  var box = document.getElementById('box');  // 获取元素;
  box.onclick = function(){          // 元素点击触发事件;
    alert('Lee');
  }

// 问题一:一个事件处理函数触发两次事件;
  window.onload = function(){         // 第一组程序;
    alert('Lee');
  }
  window.onload = function(){         // 第二组程序;
    alert('Mr.Lee');
  }
  // PS:当两组程序同时执行的时候,后面一个会把前面一个完全覆盖;
  // 导致前面的window.onload完全失效了;
// 解决方案:
  window.onload = function(){         // 第一组事件处理程序,会被覆盖;
    alert('Lee');
  }
  if(typeof window.onload == 'function'){   // 判断之前是否有window.onload;
    var saved = null;            // 创建一个保存器;
    saved = window.onload;          // 把之前的window.onload保存起来;
  }
  window.onload = function(){         // 下一个要执行的事件;
    // saved()=window.onload = function
    if(saved)saved();            // 判断之前是否有事件,如果有则先执行之前保存的事件;
    alert('Mr.Lee');             // 执行本事件的代码;
  }
// 问题二:事件切换器
  box.onclick = boBlue;             // 第一次执行toBlue();
  function toRed(){
    this.className = 'red';
    this.onclick = toBlue;          // 第三次执行roBlue(),然后来回切换;
  }
  function toBlue(){
    this.className = 'blue';
    this.onclick = toRed;          // 第二次执行toRed();
  }
  // 这个切换器在扩展的时候,会出现一些问题:
  1.如果增加一个执行函数,那么会被覆盖;
  box.onclick = toAlert;            // 被增加的函数;
  box.onclick = toBlue;            // toAlert被覆盖了;

  2.如果解决覆盖问题,就必须包含同时执行;
  box.onclick = function(){          // 包含进去,但可读性降低;
    toAlert();                // 第一次不会被覆盖,但第二次又被覆盖;
    toBlue.call(this);            // 还必须把this传递到切换器里;
  }
// 综上三个问题:覆盖问题/可读性问题/this传递为题;
// 我们创建一个自定义事件处理函数;
  function addEvent(obj,type,fn){       // 取代传统事件处理函数;
    var saved = null;            // 保存每次触发的事件处理函数;
    if(typeof obj['on'+type] == 'function'){// 判断是不是存在事件;
      saved = obj['on'+type];       // 如果有,保存起来;
    }
    obj['on'+type] = function(){      // 然后执行;
      if(saved)saved();          // 执行上一个;
      fn.call(this);           // 执行函数,把this传递进去;
    }
  }
  addEvent(window,'load',function(){
    alert('Lee');              // 可以执行;
  });
  addEvent(window.'load',function(){
    alert('Mr.Lee');            // 可以执行;
  })

// 用自定义事件函数注册到切换器上查看效果:
  addEvent(window,'load',function(){
    var box = document.getElementById('box');
    addEvent(box,'click',toBlue);
  });
  function toRed(){
    this.className = 'red';
    addEvent(this,'click',toBlue);
  }
  function toBlue(){
    this.className = 'blue';
    addEvent(this,'click',toRed);

Two W3C event handling functions
// "DOM2-level events" defines two methods for adding and removing event handlers: addEventListener() and removeEventListener();

// 所有DOM节点中都包含这两个方法,并且它们都接收3个参数:事件名/函数/冒泡或捕获的布尔值(true表示捕获,false表示冒泡);
  window.addEventListener('load',function(){
    alert('Lee');
  },false);
  window.addEventListener('load',function(){
    alert('Mr.Lee');
  },false);
  // PS:W3C的事件绑定好处:1.不需要自定义了;2.可以屏蔽相同的函数;3.可以设置冒泡和捕获;
  window.addEventListener('load',init,false);    // 第一次执行了;
  window.addEventListener('load',init,false);    // 第二次被屏蔽了;
  function init(){
    alert('Lee');
  }

// 事件切换器
  window.addEventListener('load',function(){
    var box = document.getElementById('box');
    box.addEventListener('click',function(){    // 不会被覆盖/误删;
      alert('Lee');
    },false);
    box.addEventListener('click',toBlue,false);  // 引入切换;
  },false);

  function toRed(){
    this.className = 'red';
    this.removeEventListener('click',toRed,false); // 移除事件处理函数;
    this.addEventListener('click',toBlue,false);  // 添加需要切换的事件处理函数; 
  }

  function toBlue(){
    this.className = 'blue';
    this.removeEventListener('click',toBlue,false);
    this.addEventListener('click',toRed,false);
  }

// 设置冒泡和捕获阶段
  document.addEventListener('click',function(){
    alert('document');
  },true);                    // 设置为捕获;

  document.addEventListener('click',function(){
    alert('Lee');
  },false);                    // 设置为冒泡;

Three IE event handling functions
//IE implements two methods similar to those in DOM: attachEvent() and detachEvent();

//These two methods receive the same parameters: event name and function;

// 在使用这两组函数的时候,区别:
// 1.IE不支持捕获,只支持冒泡;
// 2.IE添加事件不能屏蔽重复的函数;
// 3.IE中的this指向的是window而不是DOM对象;
// 4.在传统事件上,IE是无法接受到event对象的;但使用了attachEvent()却可以;
  window.attachEvent('onload',function(){
    var box = document.getElementById('box');
    box.attachEvent('onclick',toBlue);
  });

  function toRed(){
    var that = window.event.srcElement;
    that.className = 'red';
    that.detachEvent('onclick',toRed);
    that.attachEvent('onclick',toBlue);
  }

  function toBlue(){
    var that = window.event.srcElement;
    that.className = 'blue';
    that.detachEvent('onclick',toBlue);
    that.attachEvent('onclick',toRed);
  }
  // PS:IE不支持捕获;
  // IE不能屏蔽;
  // IE不能传递this,可以call过去;

// 在传统绑定上,IE是无法像W3C那样通过传参接受event对象;但如果使用了attachEvent()却可以;
  box.onclick = function(evt){
    alert(evt);                // undefined;
  }

  box.attachEvent('onclick',function(evt){
    alert(evt);                // object;
    alert(evt.type);              // click;
  });

// 兼容IE和W3C的事件切换器函数;
  function addEvent(obj,type,fn){        // 添加事件处理程序兼容;
    if(obj.addEventListener){
      obj.addEventListener(type,fn);
    }else if(obj.attachEvent){
      obj.attachEvent('on'+type,fn);
    }
  }

  function removeEvent(obj,type,fn){      // 移除事件处理程序兼容;
    if(obj.removeEventListener){
      obj.removeEventListener(type,fn);
    }esle if(obj.detachEvent){
      obj.detachEvent('on'+type,fn);
    }
  }

  function getTarget(evt){           // 得到事件目标;
    if(evt.target){
      return evt.target;
    }else if(window.event.srcEleemnt){
      return window.event.srcElement;
    }
  }

Four Event Object Supplement

1.relatedTarget
// 这个属性可以在mouseover和mouseout事件中获取从哪里移入和从哪里移出的DOM对象;
  box.onmouseover = function(evt){      // 鼠标移入box;
    alert(evt.relatedTarget);        // 获取移入box之前的那个元素;
  }
  box.onmouseout = function(evt){       // 鼠标移出box;
    alert(evt.relatedTarget);        // 获取移出box之后到的那个元素;
  }

// IE提供了两组与之对应的属性:fromElement和toElement;
// 兼容函数
  function getEarget(evt){
    var e = evt || window.event;      // 得到事件对象;
    if(e.srcElement){            // 如果支持srcElement,表示IE;
      if(e.type == 'mouseover'){     // 如果是over事件;
        return e.fromeElement;     // 就使用from;
      }else if(e.type == 'mouseout'){   // 如果是out;
        return e.toElement;       // 就使用to;
      }
    }else if(e.relatedTarget){       // 如果支持relatedTarget,表示W3C;
      return e.relatedTarget;
    }
  }

2. Default behavior of blocking events

// 一个超链接的默认行为就点击然后跳转到指定的页面;
// 那么阻止默认行为就可以屏蔽跳转的这种操作,而实现自定义操作;
// 取消事件默认行为还有一种不规范的做法,就是返回false;
  link.onclick = function(){
    alert('Lee');            
    return false;              // 直接返回false,就不会跳转了;
  }
  // PS:虽然return false;可以实现这个功能,但有漏洞;
  // 第一:代码必须写到最后,这样导致中间的代码执行后,有可能执行不到return false;
  // 第二:return false写到最前那么之后的自定义操作就失败了;
  // 解决方案:在最前面就阻止默认行为,并且后面还能执行代码;
  function preDef(evt){            // 跨浏览器兼容阻止默认行为;
    var e = evt || window.event;
    if(e.preventDefault){
      e.preventDefault();         // W3C,阻止默认行为;
    }else{
      e.returnValue = false;        // IE,阻止默认行为;
    }
  }
3.上下文菜单事件contextmenu
// 当我们右击网页的时候,会自动出现windows自带的菜单;
// 那么我们可以使用contextmenu事件来修改我们指定的菜单;但前提是把右击的默认行为取消;
  addEvent(window,'load',function(){
    var text = docuemnt.getElementById('text');
    addEvent(text,'contextmenu',function(evt){    // 添加右键菜单事件处理程序;
      var e = evt || window.event;
      preDef(e);                  // 阻止默认行为函数;
      var menu = document.getElementById('menu');  // 找到自定义的menu对象;
      menu.style.left = e.clientX+'px';       // 确定自定义menu在屏幕上的位置;
      menu.style.top = e.clientX+'px';
      menu.style.visibility = 'visible';      // 设置自定义menu的属性为可见;
      addEvent(document,'click',function(){     // 给document添加单击事件处理程序;
        docuemnt.getElementById('myMenu').style.visibility = 'hidden';  //将自定义的menu隐藏;
      });
    });
  });

4. Pre-unload event beforeunload

// 这个事件可以帮助在离开本页的时候给出相应的提示;"离开"或"返回"操作;
  addEvent(window.'beforeunload',function(evt){
    var evt = event || window.event;
    var message = '是否离开此页?';
    evt.returnValue = message;
    return message;
  });

5. Mousewheel and DOMMouseScroll

// 用于获取鼠标上下滚轮的距离;
  addEvent(docuemnt,'mousewheel',function(evt){    // 非Firefox;
    alert(getWD(evt));
  });
  addEvent(docuemnt,'DOMMouseScroll',function(evt){  // Firefox;
    alert(getWD(evt));
  });
 
  function getWD(evt){
    var e = evt || window.event;
    if(e.wheelDelta){                // mousewheel事件的滚动值保存在wheelDelta里;
      return e.wheelDelta;
    }else if(e.detail){               // DOMMouseScroll事件的滚动值保存在detail里;
      return -evt.detail*30;            // 保持计算的统一;
    }
  }
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn