• 事件


    前言
    近期手头的项目需要覆盖到移动终端,公司的移动终端版本未引入任何开源JS库。没了jQuery,开发效率低了很多,更要命的是很多基础知识遗忘的厉害,于是又一次翻出了那本《高级JavaScript程序设计》,整理以前的读书笔记形成以下内容。
     
    一、DOM事件流
    DOM2级事件规定的事件流包含三个阶段:捕获、到达目标、冒泡。
    IE8及更早版本不支持DOM事件流(主要是不支持捕获)。所有浏览器都支持事件冒泡。
     
    二、DOM0级事件处理程序
    (1)添加事件处理程序
    每个元素(包括window、document)都有自己的事件处理程序属性,这些属性通常全部小写,例如onclick。将属性的值设置为函数,就可指定事件处理程序。如:
    var btn = document.getElementById("myBtn");
    btn.onclick = function(){aelrt('clicked');};
    (2)删除事件处理程序
    btn.onclick = null;
    (3)优点
    兼容性好
    (3)缺点
    无法为同一个事件类型指定多个事件处理程序,后设置的事件处理程序将覆盖前一个。
    (4)需要注意作用域问题
    事件处理程序是在元素的作用域中运行,this指针指向的是当前元素。
    btn.onclick = function(){aelrt(this.id);}; // "myBtn"
     
    三、DOM2级事件处理程序
    (1)添加与移除事件处理程序
    addEventListener、removeEventListener 所有DOM节点都包含这两个方法,接受3个参数:事件类型、处理函数、是否在捕获阶段触发函数。true表示在捕获阶段调用事件处理程序,false表示在冒泡阶段调用事件处理程序
    var btn = document.getElementById("myBtn");
    btn.addEventListener('click', function(){alert(this.id)}, false);
    btn.addEventListener('click', function(){alert('hello world!')}, false);
     
    btn.removeEventListener('click', function(){alert('hello world!')}, false);// 无法移除
    (2)同一个事件类型指定多个事件处理程序
    执行顺序与调用addEventListener绑定事件处理程序的顺序相同,与第三个参数的值无关。如:
     function bubbleHandle(){
      console.log('bubbleHandle bubbleHandle bubbleHandle!!');
     } 
    function fetchHandle(){
      console.log('fetchHandle fetchHandle fetchHandle!!');
     }
     var eventflowEle = document.getElementById("eventflow");
     eventflowEle.addEventListener('click', bubbleHandle, false);
     eventflowEle.addEventListener('click', fetchHandle, true);
     //eventflowEle.addEventListener('click', bubbleHandle, true);
     //eventflowEle.addEventListener('click', fetchHandle, false); 
     
    以上代码总是会打印:
    fetchHandle fetchHandle fetchHandle!!
    'bubbleHandle bubbleHandle bubbleHandle!!
    (3)作用域问题
    与DOM0级事件一样,事件处理程序是在元素的作用域中运行,this指正执行的是当前元素
    (4)通过匿名函数添加的事件处理程序将无法被移除
     
    常规做法,为了兼容各种浏览器,最好将事件处理程序添加到事件流的冒泡阶段。
     
    四、IE事件处理程序
    (1)添加与移除事件处理程序
    attachEvent、detachEvent
    var btn = document.getElementById("myBtn");
    btn.attachEvent('onclick', function(){alert(this.id)}); // undefined
    btn.detachEvent('onclick', function(){alert(this.id)}); // 无法移除
    IE8及早期版本不支持事件捕获,所以通过attachEvent添加的事件处理程序将在冒泡阶段被调用。
     
    (2)同一个事件类型指定多个事件处理程序
    执行顺序与调用attachEvent绑定事件处理程序的顺序相反
    var btn = document.getElementById("myBtn");
    btn.attachEvent('onclick', function(){alert('hello world!')}); 
    btn.attachEvent('onclick', function(){alert('cliked!!')});
    弹窗顺序:
    cliked!!
    hello world!
     
    (3)作用域问题
    与DOM0级事件不一样,事件处理程序是全局作用域中运行,this指针指向的是window对象
     
    (4)通过匿名函数添加的事件处理程序将无法被移除
     
    (5)事件类型要加"on",如onclick
     
    写一段跨浏览器绑定事件处理程序的代码:
    var EventUtil = {
         addHandle : function(ele, type, handle){
             if(ele.addEventListener){
                 ele.addEventListener(type, handle, false);// 默认在事件冒泡阶段触发事件处理程序,第三个参数默认为false
             }else if(ele.attachEvent){
                 ele.attachEvent('on'+type, handle);
             }else{
                 ele['on'+type] = handle;
             }
         },
         removeHandle : function(ele, type, handle){
             if(ele.removeEventListener){
                 ele.removeEventListener(type, handle, false);
             }else if(ele.detachEvent){
                 ele.detachEvent('on'+type, handle);
             }else{
                 ele['on'+type] = null;
             }
         }
     };
     
     function bubbleHandle(){
      alert('bubbleHandle bubbleHandle bubbleHandle!!');
     }
     var ele = document.getElementById('eventflow');
     EventUtil.addHandle(ele, 'click', bubbleHandle);
     setTimeout(function(){
      EventUtil.removeHandle(ele, 'click', bubbleHandle);
     }, 3000);
     
    五、事件对象
    (1)DOM中的事件对象
    兼容DOM的浏览器会将事件对象(event)传入到事件处理程序中。DOM0级,DOM2级都会传event对象
    var btn = document.getElementById("myBtn");
    btn.onclick = function(event){alert(event.type)}; // "click"
    btn.addEventListener('click', function(event){alert(event.type)}, false); // "click"
     
    currentTarget与target
    currentTarget 绑定事件处理程序的DOM元素
    target 事件的目标元素
    事件处理程序中的this始终等于currentTarget
    function bubbleHandle(event){
      console.log(event.currentTarget === this); // true
      console.log(event.target === document.getElementById('eventflow')); // true
     }
     var ele = document.body;
     EventUtil.addHandle(ele, 'click', bubbleHandle);
    应用场景:事件委托,将事件处理程序绑定在父级容器上,通过event.target判断用户单击的是哪一个DOM元素。
     
    阻止事件冒泡
    我们同时为body与body中的按钮绑定了单击事件,我们希望在单击按钮的时候不要触发body的事件处理程序,这时候就需要在按钮的事件处理程序中阻止事件冒泡(同时也取消了事件捕获):
    event.stopPropagation()
     
    阻止默认行为
    event.preventDefault()
     
    event对象将在事件处理程序结束之后被销毁
     
    (2)IE中的事件对象
    通过属性赋值的方式添加事件处理程序,可通过window.event获取事件对象:
    var mybtn = document.getElementById("mybtn");
    mybtn.onclick = fucntion(){alert(window.event.type);} // 'click'
     
    通过attachEvent方式添加的事件处理程序,可通过参数传递的方式获取事件对象
    var mybtn = document.getElementById("mybtn");
    mybtn.attachEvent('onclick', function(event){alert(event.type)});// 'click'
     
    srcElement
    事件目标。与DOM中的target属性相同
    var mybtn = document.getElementById("mybtn");
    mybtn.onclick = fucntion(){alert(window.event.srcElement === this);} // true
    mybtn.attachEvent('onclick', function(event){alert(event.srcElement === this)});// false 这里的this指向的是window对象
     
    阻止事件冒泡
    event.cancelBubble()
     
    阻止默认行为
    event.returnValue = false;
    应用场景:给A标签绑定单击事件时需要阻止浏览器的默认跳转行为
     
    写一段跨浏览器获取事件对象的代码:
    var EventUtil = {
         addHandle : function(ele, type, handle){
             if(ele.addEventListener){
                 ele.addEventListener(type, handle, false);// 默认在事件冒泡阶段触发事件处理程序,第三个参数默认为false
             }else if(ele.attachEvent){
                 ele.attachEvent('on'+type, handle);
             }else{
                 ele['on'+type] = handle;
             }
         },
         removeHandle : function(ele, type, handle){
             if(ele.removeEventListener){
                 ele.removeEventListener(type, handle, false);
             }else if(ele.detachEvent){
                 ele.detachEvent('on'+type, handle);
             }else{
                 ele['on'+type] = null;
             }
         },
         getEvent : function(event){
          return event?event : window.event;
         },
         getTarget : function(event){
          return event.target || event.srcElement;
         },
         stopPropagation : function(event){
          if(event.stopPropagation){
           event.stopPropagation();
          }else{
           event.cancelBubble();
          }
         },
         preventDefault : function(event){
          if(event.preventDefault){
           event.preventDefault();
          }else{
           event.returnValue = false;
          }
         }
     };
     
    六、事件类型:
    UI事件
    焦点事件
    鼠标事件
    滚轮事件
    文本事件
    键盘事件
     
    UI事件
    不一定与用户操作有关的事件,如window.onload、window.onunload、window.onresize、window.onscroll
    load事件
    (1)JS代码为window对象绑定onload事件,也可在body上添加onload属性
    (2)img标签也可添加onload事件。应用场景:还记我们的菊花效果么?
    在DOM出现之前,通常会用Image对象预加载图片:
    EventUtil.addHandle(window, 'load', function(event){ 
        var image = new Image();
        EventUtil.addHandle(image, 'load', function(event){ 
            console.log('iamge loaded'); 
        }); 
        image.src = 'http://images.139cm.com/subscribe//upload/2014/06/20/820//images/1407016596180_242.jpg'; 
    });
    (3)script标签也可绑定load事件。应用场景:还记得脚本文件的按需加载么?
    IE8及更早版本不支持script标签的load事件,可统一绑定onreadystatechange事件执行脚本加载后的回调。标准浏览器可绑定load事件执行回调。
     
    unload事件
    页面卸载后触发
    应用场景:清除引用,避免内存泄露
     
    resize事件
    火狐浏览器会在用户停止调整窗口大小时触发resize事件,其他浏览器在调整窗口大小的过程中不断触发。
     
    scroll事件
    文档被滚动期间重复触发
     
    焦点事件
    blur 元素失去焦点时触发,所有浏览器都支持,并且不会冒泡。
    focus 元素取得焦点时触发,所有浏览器都支持,并且不会冒泡。
     
    鼠标与滚轮事件
    click
    dblclick
    mousedown
    mouseenter
    mouseleave
    mousemove
    mouseover
    mouseup
     
    判断浏览器是否支持某一事件的方式:
    document.implementation.hasFeature("MouseEvents", "3.0")
     
    客户区坐标位置
    客户区:用户可以看到的页面的区域,不包括浏览器工具栏,不包含页面滚动的距离。
    event.clientX,event.clientY 可以获取事件发生时鼠标指针在视口中的水平和垂直坐标。
     
    页面坐标位置
    event.pageX,event.pageY
    在页面没哟滚动的情况下,pageX与clientX值相等。
    IE8及更早版本不支持pageX,pageY,需要这样获取pageX,pageY值:
    var pageX = event.pageX;
    var pageY = event.pageY;
    if(pageX === undefined){
        pageX = event.clientX + (document.body.scrollLeft || document.documentElement.scrollLeft);
    }
    if(pageY === undefined){
        pageY = event.clientY + (document.body.scrollTop || document.documentElement.scrollTop);
    }
     
    屏幕坐标位置
    事件发生时,鼠标位置相对于整个屏幕的坐标位置
    event.screenX,event.screenY
     
    修改键
    shift、ctrl、alt、meta
    DOM规定了四个属性表示这四个键的状态:shiftKey、ctrlKey、altKey、metaKey。为true时表示该键被按住
    应用场景:组合键执行事件处理程序
    $(window.document).bind('keydown', function(event){ 
        // Ctrl+Enter
        if(event.ctrlKey && event.keyCode == M139.Event.KEYCODE.ENTER){
            // TODO
        }
    });
     
    鼠标滚轮事件
    mousewheel
    IE6首先实现了该事件,现在几乎所有浏览器都支持该事件。
    EventUtil.addHandle(document, 'mousewheel', function(event){ 
        alert(event.wheelDelta);
    });
    向前滚wheelDelta的值是120的倍数
    向后滚wheelDelta的值是-120的倍数
    通常情况下我们只需要根据wheelDelta的正负号判断用户的滚动方向就行了。
    139邮箱的应用场景:云邮局杂志阅读器,滚动滚轮放大缩小图片
     
    火狐浏览器支持DOMMouseScroll事件,向前滚动时该值是-3的倍数,向后是3的倍数。
     
    推荐使用JQuery插件:jquery.plugin.mouseweel.js 解决兼容性问题
     
    键盘事件
    keydown 按住不放重复触发
    keypress 按住不放重复触发
    keyup
    139邮箱的应用场景:杂志阅读器,按住向下的方向键不松开,可连续往上移动图片。
     
    HTML5事件
    contextmenu事件 右键调出上下文菜单
    contextmenu事件是冒泡的,我们可以在document上统一绑定该事件,利用事件委托,判断用户点击的元素,显示自定义菜单。然后使用onclick事件隐藏菜单,并可通过event.clientX、event.clientY定位菜单位置。
     
    DOMContentLoaded事件
    执行时间早于window.onload,DOM树形成之后就会触发。
    IE8及更早的浏览器不支持该事件,可通过readystatechange事件实现相应的功能。
     
    readystatechange事件
    IE浏览提为DOM文档的某些部分提供了该事件。可判断document.readyState值执行相应的回调。
    uninitialized、loading、loaded、interactive、complete
    需要同时判断readyState值等于interactive或者等于complete,执行回调。
    应用场景:jQuery的$(document).ready
    <script>(IE和opera)和<link>(仅IE)也会触发readystatechange,需要同时判断readyState值等于loaded或者等于complete,执行回调
     
     
     
  • 相关阅读:
    docker~save与load的使用
    docker~从Dockerfile到Container的过程(终于算是OK了)
    docker~使用阿里加速器
    Draw2d中的布局管理器Layout比较
    利用glibc中锁结构的信息解决死锁问题
    android 利用重力感应监听 来电时翻转手机后静音。
    hdu 1754 I Hate It
    九度笔记之 1209最小邮票数
    java zip工具类
    基于XMPP实现的Openfire的配置安装+Android客户端的实现
  • 原文地址:https://www.cnblogs.com/hellohuman/p/3876586.html
Copyright © 2020-2023  润新知