zoukankan      html  css  js  c++  java
  • javascript 事件相关使用总结01

    javascript 事件相关使用总结01

    这里总结一下js事件相关的经验。

    addEventLinstener()介绍

    注册事件最基础的函数是这个
    target.addEventListener(type, listener[, useCapture]);
    这个有一些可以注意的地方
    1.第二个参数它需要的是一个实现了EventListener接口的对象。但是也可以传递一个函数,最常见的就是传一个匿名函数
    2.第三个useCapture参数指明是事件传递是自下向上冒泡,还是从上到下传递。
     
    先总结一下第一点的问题
    最常见的用法
    var btn01 = document.getElementById("btn01");
    btn01.addEventListener("click", function() {
        console.log(this);
    });

    或者

    function func() {console.log("func");}
     
    var btn01 = document.getElementById("btn01");
    btn01.addEventListener("click", func);
    前一种是传递匿名函数,后一种是函数名。有什么区别?
     
    匿名函数无法用removeEventListener移出事件的注册。后者可以
    var btn01 = document.getElementById("btn01");
    btn01.addEventListener("click", func);
    btn01.removeEventListener("click", func);

    注意:需要移出的注册事件,addEventListener和removeEventListener的参数必须一样。

     
    用匿名函数方式,每个匿名函数被看作一个独立的函数,即便匿名函数内容一样。
    在下面这种情况下它比函数名方式更加占内存。
    //对所有div注册一个点击事件
    var divs = document.getElementsByTagName("div");
    for (var i=0; i<divs.length; i++) {
        divs[i].addEventListener("click", function() {
            func();
        });
    }
     
    另外一个很重要的地方就是匿名函数方式每次注册都是独立的。例如
    btn01.addEventListener("click", function() {
        console.log(this);
    });
    btn01.addEventListener("click", function() {
        console.log(this);
    });

    这样点击事件被看作两个有两个回调注册,会执行两次。

     
    而后者函数名方式,则被看做是同样的回调注册。只注册一次,回调函数代码也只执行一次。
    btn01.addEventListener("click", c);
    btn01.addEventListener("click", c);

     

    与jquery相关的问题。

    如果用jquery注册的话,不管是不是匿名函数,每次注册都是生效的。例如
    $(document).ready(function() {
        $("#btn01").click(func);
        $("#btn01").click(func);
    });

    func函数会执行两次。这个是和addEventListener方式不一样的地方之一。用jquery的时候这个问题还是很容易出现的。

     

    EventListener接口的用法

    只需要一个有handleEvent方法的对象即可。例如
    var events = {
        handleEvent : function(event) {
            switch (event.type) {
                case 'click':
                    //......
                    break;
                case 'dbclick':
                    //......
                    break;
                default:
                    break;
            }
        }
    }
    btn01.addEventListener("click", events, false);
    btn01.addEventListener("dblclick", events, false);
    这样点击和双击事件都会执行handleEvent方法,再根据event.type类型做不同的分支。
    这种做法的好处就是更加面向对象一点,需要处理的数据可以由同一的对象管理。例如以下一个简单的例子
     1 function BtnHandler(element) {
     2     this.element = element;
     3     this.name = "button";
     4    
     5     this.handleEvent = function(event) {
     6         switch(event.type) {
     7             case 'click':
     8                 this.clickHandler(event);
     9                 break;
    10             case 'dblclick':
    11                 this.dblclickHandler(event);
    12                 break;
    13         }
    14     };
    15     this.clickHandler = function(event) {
    16         console.log("clickHandler");
    17     }
    18     this.dblclickHandler = function(event) {
    19         console.log("dblclickHandler");
    20     }
    21    
    22     element.addEventListener('click', this, false);
    23     element.addEventListener('dblclick', this, false);
    24 }
    25 //注册
    26 BtnHandler(btn01);

     

    第二个点useCapture参数。

    1.true为Capture方式,由外向里顺序执行。
    2.false为Bubbling冒泡方式,由里向外冒泡。默认它是false
     
    事件传递机制不多说了,有许多文章可以参考。 这里说说与它相关的有两个标准的接口。
    stopPropagation和preventDefault
    stopPropagation很简单就是阻止事件继续传递。
    而preventDefault原本是用来标记事件被取消了的。但是注意preventDefault调用后事件仍然会继续传递。
    我发现的preventDefault唯一的用处就在移动设备上。有一些移动设备会出现“点穿现象”,
    例如一个div层在下面,上面再盖一个div层(只是位置上覆盖,DOM树结构不是上下级关系,排除事件冒泡的影响)。上层DIV响应点击事件后如果执行力从DOM树中移出的操作,这种情况下下面的DIV也会响应到click事件。
    这个时候使用event.preventDefault()便可以避免这种“点穿影响”。但是注意preventDefault会像它名字一样阻止浏览器的默认行为。例如按钮的点击特效等。
     
    旧方式注册事件注意点
    1.直接html写的。
    <button id="btn01" onclick="func();">btn01</button>
    function func() {
        console.log(this); //这里的this是全局的window
    }

    这种使用的比较少,但是要注意它的回调函数里面没有绑定this。也就是它回调里面的this指向全局的window

     
    2. 属性方式的写法
    btn01.onclick = function() {}; 
    这种写法在一些浏览器上可能不支持。并且它只能为某一个事件添加一个回调。
    btn01.onclick = func01;
    btn01.onclick = func02;

    这样的click事件只能注册最后一个回调函数。

    ready onload介绍 

    onload的作用是指元素装载完成后的回调,一般用在body上和image上。并不是所有的元素都有这个回调,支持的元素有以下。
    <body>, <frame>, <frameset>, <iframe>, <img>, <link>, <script>
    例如
    <body onload="load();"><img onload="func();" src="xx" /> 
    js代码中的一些内置对象也有此回调。例如image, window对象。例如
    var div01 = document.getElementById("div01");
    
    var image = new Image();
    
    image.onload = function() {
    
        console.log("img onload");
    
    };
    
    image.src = "1.jpg";
    
    div01.appendChild(image);
    一个要点是body上注册的onload事件会等待所有的资源加载完后执行。单个img里面的则是自己加载完就执行。
    我们使用的时候往往用jquery的ready。这个更好用。
    $(document).ready(function() {
    
    }
    有什么不同呢,
    1.body onload会等待图片,静态文件等都加载完成之后执行。ready只是等dom树和js装载完(包含自执行的js代码执行完成)。
    自执行的代码例子如下
    <script>
    
    (function() {
    
        //......这里就是自执行的代码了,也就是一装载就开始执行。
    
    })();
    
    </script>

    如果有耗时操作的话。例如下例。ready也是会等到这些执行完成后再响应。这一点需要注意一下。

    (function() {
    
        var sum = 0;
    
        for (var i=0; i< 1000000; i++) {
    
            sum += i;
    
        }
    
        console.log(sum);
    
    })();
    注意:不能用setTimeout或者异步代码来模拟耗时操作,概念不一样。
     
    所以ready会比onload更早响应,并且使用也更加合理。我们只需要js和dom完了就可以写js代码逻辑来,不必要非要等图片等加载完。
     
    2.onload注册多个回调不方便。用jquery的ready就不一样了(前面也提到过用jquery注册的,那怕是相同的函数也都会被单独执行)。
    用onload多个回调函数写法这样,不是很方便。
    <body onload="load();load2();load3();">
    3.另外body的onload和jquery的ready不能同时使用,同时注册onload会不响应。
    如果需要同时用到body的onload和ready的回调时机可以使用window的onload取代。它的响应时机跟body的onload差不多。并且window和body的onload同时注册body的也不响应。
    (function() {
    
        window.onload = function() {
    
            console.log("window.onload");
    
        };
    
    })();

    或者

    $(document).ready(function() {
    
        $(window).load(function() {
    
            console.log("jquery window load");
    
        });
    
    }); 

    事件委托处理 

    如果有动态的添加的dom元素或者说有许多相同的元素需要绑定同样的事件。则用事件委托则方便许多。
    例如一个div里面动态添加了许多个button.
    $(document).ready(function() {
       
        var div01 = document.getElementById("div01");
        for (var i=0; i<10; i++) {
            var btn = document.createElement("button");
            btn.innerHTML = "btn" + i;
     btn.addEventListener("click", function() {
         //.......
     });
            div01.appendChild(btn);
        }
    });
    如果添加button的代码是某个程序运行中执行的。则上述方式有两个问题,第一注册事件代码需要添加按钮后执行,并且添加的内容可能根据不同情况而不一样,
    这样可能会导致一些代码的重复而变得不好维护。
     
    第二,更加占用内存。尤其如果使用的是匿名函数的方式注册的话。
     
    事件委托就是利用事件冒泡,将事件注册到父元素上,这样就子元素不管是不是动态添加的,或者多少个都可以响应到。如果需要用到事件源则可以利用事件的event.target属性分辨出来那个元素。
    div01.addEventListener("click", function(event) {
        console.log(event.target.innerHTML);
    });
    这个有jqeury包装好的方法可用live()和delegate()
    live是将事件绑定在DOM的根节点上。所以在任意时候使用
    $("button").live("click", func);
    delegate是将事件绑定在特定的父节点上所以使用的时候要指定父节点
    $("div").delegate("button", "click", func);
  • 相关阅读:
    Thread的第四天学习
    Thread的第三天学习
    Thread的第二天学习
    Thread的第一天学习
    hibernate的简单学习(第一天)
    【转载】jxl操作excel 字体 背景色 合并单元格 列宽等 .
    MySql学习
    sqlserver 数据库隔离级别,数据库死锁
    高并发操作同一条数据,更新丢失数据问题(重复转账,票超卖,订单扣库存问题)
    T4
  • 原文地址:https://www.cnblogs.com/laozhbook/p/javascript_event_summary_01.html
Copyright © 2011-2022 走看看