zoukankan      html  css  js  c++  java
  • 由事件面试题引发的总结

    1、描述下js里面的【事件的三个阶段】

    2、IE和W3C不同绑定事件解绑事件的方法有什么区别,参数分别是什么,以及事件对象e有什么区别

    3、【事件的代理/委托】的原理以及优缺点

    4、写原生js【实现事件代理】,并要求兼容浏览器

    5、事件如何派发

    6、JS事件模型与事件流介绍一下,事件代理用过吗?自定义事件,事件广播和分发

    7、如何使用事件,以及IE和标准DOM事件模型之间存在的差别。

    当面试时,问到这些问题时,问问自己是否能答的出来?

    事件与事件流

      不管总结什么、还是复习什么,概念从定义出发总是没错的。在《Javascript高级程序设计》中,是这么说的"事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间",也就是说事件就是js与html之间的交互实现者。

      而事件流描述的是从页面中接收事件的顺序。而这儿就有两种事件流,后面详述。

    事件三个阶段

    可以记住这个非常了不起的demo:https://wanliyuan.github.io/blog/testFunction.html (也是网上看到的)、非常清晰得展示了三个阶段的过程。

    三个阶段分别是事件捕获、处于目标阶段、事件冒泡。

    DOM2级事件规定的事件流就包括这个阶段。首先先发生的是事件捕获,为截获事件提供了机会。然后就是实际的目标接收到事件,最后就是冒泡阶段,可以在这个阶段对事件作出相应。

    五种事件处理程序

      先来知道什么是事件处理程序。

    <input type="button" id="btn" value="点击" onclick="show(this)">
    function show(obj){
        console.log(obj.value);
    }
    

      这个show就是事件处理程序/事件侦听器(-----响应事件的函数)。  

      1、HTML事件处理程序

      其实这种方式,相信前端的小伙伴们见得太多、也写的太多了。它是在HTML中定义的事件处理程序包括了执行的具体动作,或者调用页面别的地方定义的脚本,例如下面的代码:

    <input type="button" value="点击" onclick="alert(11)">
    
    <input type="button" value="点击" onclick="show(this)">
    function show(obj){
        console.log(obj.value);
    }
    

     但是这种方式导致html与js的代码耦合度太高,也是大多数开发人员摈弃的原因。

      2、DOM0级事件处理程序

    通过Javascript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。

            var btn = document.getElementById("btn");
            btn.onclick = function(){
                alert(this.id);
            }
    

    删除事件是:btn.onclick = null;

    以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理,并且这时候的事件处理程序是在元素的作用域中进行,里面的this就是当前元素。

      3、DOM2级事件处理程序

    DOM2级事件是通过addEventListener和removeEventListener来处理指定和删除事件处理程序的操作,接受三个参数(事件名、作为事件处理程序的函数,布尔值)。布尔值为true,表示在捕获阶段调用事件处理程序,若是false,则在冒泡阶段处理。

            var btn = document.getElementById("myBtn");
            btn.addEventListener("click",function(){
                alert(this.id);
            },false);
            btn.addEventListener("click",function(){
                alert("Hello world");
            },false);
    

    大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器。 通过removeEventListener删除事件处理程序时,必须使用相同参数,主要是那个函数名,必须跟addEventListener一样才有效。

    btn.addEventListener("click",show,false)
    btn.removeEventListener("click",show,false)

      4、IE事件处理程序

    IE事件处理程序跟DOM2的类似,有两个方法attachEvent和detachEvent,不过这儿的参数只有两个:事件处理程序名称与事件处理程序函数。因为IE8以及更早的版本只支持事件冒泡,所以通过attachEvent添加的事件处理程序都会被添加到冒泡阶段。

    var btn = document.getElementById("myBtn");
            btn.attachEvent("onclick",function(){
                alert("clicked");
            });
         btn.attachEvent("onclick",function(){
                alert("Hello world");
            });

    IE事件处理程序跟DOM2基本的区别:第一个参数是onclick、给同一个按钮添加两个不同的事件处理程序,是以相反的顺序被触发(Hello world -> clicked)

    IE事件处理程序跟DOM0基本的区别事件处理程序的作用域是window(this==window)

    通过detachEvent移除事件处理程序也一样,第二个参数要传跟attachEvent一样的名儿。          

     5、跨浏览器处理程序

    这儿的跨浏览器的处理程序,其实就是融合了DOM2级和IE的事件处理程序,以做到兼容大多数浏览器,而且只关注冒泡阶段。

        var eventUtil = {
            addHandler:function(element,type,handler){
                if(element.addEventListener){
                    element.addEventListener(type,handler,false);
                }else if(element.attachEvent){
                    element.attachEvent("on"+type,handler);
                }else{
                    element["on"+type] = handler;
                }
            },
            removeHandler:function(element,type,handler){
                if(element.removeEventListener){
                    element.removeEventListener(type,handler,false);
                }else if(element.detachEvent){
                    element.detachEvent("on"+type,handler);
                }else{
                    element["on"+type] = null;
                }
            }
        }
    

      

    三种事件对象

    事件对象就是在触发dom上事件时产生的,它包含所有与事件有关的信息,如下图。所有浏览器都支持event对象,但是支持方式不同,所有才有三种事件对象。

    1、DOM中的事件对象

    兼容DOM的浏览器都会将一个event对象传入到事件处理程序中,无论是DOM0级还是DOM2级,都会传入event对象中。

    2、IE中的事件对象

    与访问DOM中的event对象不同,访问IE的event有几种方式,取决于指定事件处理程序的方法。

    若是DOM0级添加事件处理程序时,event对象作为window对象的一个属性存在。

            var btn = document.getElementById("myBtn");
            btn.onclick = function(){
                var event = window.event;
                alert(event.type);
            }
    

      

    若是使用attachEvent添加,就会有event对象作为参数被传入事件处理程序函数。不过也可以通过window对象来访问event对象,跟DOM0级一样。

            var btn = document.getElementById("myBtn");
            btn.attachEvent("click",function(event){
                alert(event.type);
            });
    

      

    若是HTML指定事件处理程序,也还可以通过event变量访问event对象(跟DOM0级的事件模型一样)

    <input type="button" value="点击" onclick="alert(event.type)">
    

      

    3、跨浏览器的事件对象

    var EventUtil = {
                addHandler:function(element,type,handler){
                    //省略
                },
                getEvent: function (event) {
                    return event ? event : window.event;
                },
                getTarget:function(event){
                    return event.target || event.srcElement;
                },
                preventDefault:function(evnt){
                    if(event.preventDefault){
                        event.preventDefault();
                    }else{
                        event.returnValue = false;
                    }
                },
                removeHandler:function(element,type,handler){
                    //省略
                },
                stopPropagation:function(event) {
                    if(event.stopPropagation){
                        event.stopPropagation;
                    }else{
                        event.cancelBubble = true;
                    }
                }
            }
    

      

    事件代理/事件委托

      每个函数都是对象,都会占用内存;内存中的对象越多,性能越差。事先对指定所有事件处理程序而导致的dom访问次数,会延迟整个页面的交互就绪事件。所以就有了事件委托,对“事件处理程序过多”的解决方案是事件委托。

        var item1 = document.getElementById("goSomewhere");
        var item2 = document.getElementById("doSomething");
        var item3 = document.getElementById("sayHi");
        EventUtil.addHandler(item1,"click",function(event){
            location.href = "http://www.baidu.com";
        });
        EventUtil.addHandler(item2,"click",function(event){
            document.title = "test";
        });
        EventUtil.addHandler(item3,"click",function(event){
            alert("Hi");
        })
    

    这个是给三个li添加事件处理程序,通过事件委托的如下:

         var list = document.getElementById("myLinks");
         EventUtil.addHandler(list,"click",function(event){
             event = EventUtil.getEvent(event);
             var target = EventUtil.getTarget(event);
    
             switch(target.id){
                 case "goSomewhere":
                     location.href = "http://www.baidu.com";
                     break;
                 case "doSomething":
                     document.title = "test";
                     break;
                 case "sayHi":
                     alert("Hi");
                     break;
             }
         })
    

    这个就只是添加了一个事件处理程序,用来处理页面上发生的某种特定类型的事件,提升了整体性能,Live Demo。  

    currentTarget与target

    currentTarget是事件处理程序当前正在处理的那个元素,target是事件目标。

            var btn2 = document.getElementById("btn2");
            btn2.onclick = function(e){
                console.log(e.currentTarget==this); //true
                console.log(e.target==this);    //true
            }
            document.body.onclick = function(e){
                console.log(e.currentTarget==this);  //true
                console.log(e.target==this);  //false
                console.log(e.currentTarget===document.body);  //false
                console.log(this===document.body);  //false
                console.log(e.target===btn2);  //false
            }  
    

      

  • 相关阅读:
    Redis 之order set有序集合结构及命令详解
    Redis 之set集合结构及命令详解
    Redis 之list链表结构及命令详解
    Redis 之string结构及命令详解
    Redis 通用key操作命令
    Redis 在Linux下的安装
    Entity FrameWork 操作使用详情
    Linux 之常用操作指令详解
    Linux 之根目录介绍
    php 加密解密函数封装
  • 原文地址:https://www.cnblogs.com/wanliyuan/p/5718180.html
Copyright © 2011-2022 走看看