• js随笔--关于事件


    事件流

    事件流描述的是从页面中接收事件的顺序;

    事件冒泡:事件开始时由最具体的元素(最内层)逐级向上传播到较不具体的节点(文档);

    事件捕获:事件开始时由相对不具体的元素最快接收到事件,而最具体的元素最后接收到事件。

    书中的解释比较绕,其实我比较粗暴的理解就是,冒泡就像水中的波纹传播,从触发点开始向外扩展;而捕获则像给皇帝传递消息,皇帝才是消息的目标,但消息要从城门到宫门到殿门一路传过来,最后才到皇帝手中。

    DOM事件流

    “DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段处于目标阶段事件冒泡阶段。

    事件处理程序

    事件处理程序:对用户或浏览器自身执行的某种动作(事件)作出响应的函数;名字以on开头,比如onclick, onload, onmouseover等;

    为事件指定事件处理程序的方式包括:

    1. 在HTML元素对象的同名属性中指定,可以是可执行的代码或调用已定义的函数。

      这种方式能够在执行时创建动态函数,可以直接访问事件对象及其属性。但缺点是易产生页面与程序的加载时差导致不可用、以及浏览器解析差异,且内容与行为不能分离;

    2. 在脚本中将元素的事件处理程序对应属性设置为一个函数(DOM0级),常见比如element.onclick = function

      这种方式中,事件处理程序在元素的作用域中执行,this引用当前指定元素;添加的事件处理函数可使用element.onclick = null移除;

    3. 使用addEventListener()方法指定。

      可添加多个事件处理程序,且都在其依附的元素的作用域中执行;
      移除函数可使用removeEventListener(),必须使用与添加时相同的函数名称,添加的匿名函数无法移除;

    4. IE8及更早版本中使用attachEvent()detachEvent()方法添加和移除事件处理程序;
      使用attachEvent()方法添加的事件在全局作用域中执行,只支持事件冒泡。

    跨浏览器解决方案:

    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;
            }
        } 
    }
    

    这里的添加和移除事件处理程序在所有浏览器中都可用,但是没有考虑IE事件处理程序的作用域问题,如果handler中涉及this则需要小心。

    事件对象

    当事件在DOM触发,事件处理程序执行,会产生event对象,包含了事件类型、元素等相关信息;一旦事件处理程序执行完成,event对象会被销毁。不同浏览器对event的支持方式不同。

    因为事件处理程序的作用域与指定它的方式有关,在事件处理程序内部,this并不始终等于事件目标(只有在事件处理函数直接指定给该目标且依赖此目标作用域执行时,thistarget(或srcElement)才是一致的)。

    例如绑定在body的事件处理函数,点击其内部的子元素,点击事件冒泡到body触发该函数;此时点击的目标是这个子元素,即事件对象的target,但body的事件处理函数因为是绑定在body上,其内部的this指向body.

    可以通过红皮书中的案例EventUtil对象实现跨浏览器增删事件处理程序及获取事件对象和目标对象。

    var EventUtil = {
        getEvent: function (event) {
            return event? event : window.event;
        },
        getTarget: function (event) {
            return event.target || event.srcElement;
        }
    }
    

    事件委托

    通过使用跨浏览器方案获取当前事件对象和目标对象,也能方便地实现事件委托--不必依靠对每个目标分别指定事件处理程序,只要在最外层元素指定的事件处理程序中,指定对于不同的target需要执行什么动作就可以了,这样对于内存优化和性能优化都有益。

    一个事件委托的例子:

    // HTML中,box2 为 body, 内含 box1, 及 box1 的子元素 box;
          document.body.onclick = function (event) {
            event = EventUtil.getEvent(event);
            var target = EventUtil.getTarget(event);
            switch (target.id) {
              case "box":
                target.style.backgroundColor = "lightgreen";
                alert("this is box");
                break;
              case "box1":
                target.style.backgroundColor = "yellow";
                alert("this is box1")
                break;
              case "box2":
                target.style.backgroundColor = "purple";
                break;
              //对box2本身也可以直接用default
              // default:
              //   target.style.backgroundColor = "purple";
            }
            document.body.onclick = null;
          };
    
    

    每当将事件处理程序指定给元素时,运行中的浏览器代码与支持页面交互的JavaScript代码之间就会建立一个连接。这种连接越多,页面执行起来就越慢;

    为了优化内存与性能,在移除页面上的元素前,先手动删除其带有的事件处理程序,否则就算这个元素被移除,它的事件处理程序占有的内存可能无法被回收。


    生如夏花般绚烂,死如秋叶般静美
  • 相关阅读:
    Python协程
    Python3常用标准库
    温故而知新--day3
    温故而知新--day2
    解决 WPF 绑定集合后数据变动界面却不更新的问题
    WPF 消息框 TextBox 绑定新数据时让光标和滚动条跳到最下面
    C# 枚举转列表
    真・WPF 按钮拖动和调整大小
    使用 GB28181.Solution + ZLMediaKit + MediaServerUI 进行摄像头推流和播放
    将 .NET Framework 项目转换为 .NET Standard 项目
  • 原文地址:https://www.cnblogs.com/muTing/p/9094339.html
Copyright © 2020-2023  润新知