JavaScript高级程序设计第四版学习--第十七章


title: JavaScript高级程序设计第四版学习–第十七章
date: 2021-5-27 10:02:37
author: Xilong88
tags: JavaScript

本章内容:
理解事件流
使用事件处理程序
了解不同类型的事件
可能出现的面试题:
1.了解过事件流吗?
2.事件冒泡?事件捕获?
3.绑定事件有哪些方法?
4.事件中target,currentTarget,this的区别?
5.H5新增的事件了解哪些?
6.事件委托?
7.事件性能问题应该注意哪些?
8.删除事件应该怎么做?
9.如何模拟事件?

总结:这章讲了事件和关于事件性能优化方面的内容.

知识点:

1.JavaScript与HTML的交互是通过事件 实现的,事件代表文档或浏览器窗口中某个有意义的时刻。可以使用仅在事件发生时执行的监听器(也叫处理程序)订阅事件。在传统软件工程领域,这个模型叫“观察者模式”

2.事件冒泡
IE事件流被称为事件冒泡 ,这是因为事件被定义为从最具体的元素(文档树中最深的节点)开始触发,然后向上传播至没有那么具体的元素(文档)。

3.事件捕获

意思是最不具体的节点应该最先收到事件,而最具体的节点应该最后收到事件。事件捕获实际上是为了在事件到达最终目标前拦截事件。

4.DOM事件流

DOM2 Events规范规定事件流分为3个阶段:事件捕获、到达目标和事件冒泡。

在这里插入图片描述
上图在DOM事件流中,实际的目标(<div> 元素)在捕获阶段不会接收到事件。这是因为捕获阶段从document 到<html> 再到<body> 就结束了。下一阶段,即会在<div> 元素上触发事件的“到达目标”阶段,通常在事件处理时被认为是冒泡阶段的一部分(稍后讨论)。然后,冒泡阶段开始,事件反向传播至文档。

5.事件处理程序

为响应事件而调用的函数被称为事件处理程序 (或事件监听器 )。

<input type="button" value="Click Me" onclick="console.log('Clicked')"/>
<script>
  function showMessage() {
    console.log("Hello world!");
  }
</script>
<input type="button" value="Click Me" onclick="showMessage()"/>
<!-- 输出"click" -->
<input type="button" value="Click Me" onclick="console.log(event.type)">

动态创建的包装函数还有一个特别有意思的地方,就是其作用域链被扩展了。在这个函数中,document 和元素自身的成员都可以被当成局部变量来访问。

这是通过使用with 实现的:

function() {
  with(document) {

    with(this) {
       // 属性值
    }
  }
}

这意味着事件处理程序可以更方便地访问自己的属性。下面的代码与前面的示例功能一样:

<!-- 输出"Click Me" -->
<input type="button" value="Click Me" onclick="console.log(value)">
<form method="post">
  <input type="text" name="username" value="">
  <input type="button" value="Echo Username"
         onclick="console.log(username.value)">
</form>
function() {
  with(document) {
    with(this.form) {
      with(this) {
         // 属性值
      }
    }
  }
}

6.DOM0事件处理程序

let btn = document.getElementById("myBtn");
btn.onclick = function() {
  console.log("Clicked");
};

所赋函数被视为元素的方法。因此,事件处理程序会在元素的作用域中运行,即this 等于元素。下面的例子演示了使用this 引用元素本身:

let btn = document.getElementById("myBtn");
btn.onclick = function() {
  console.log(this.id);  // "myBtn"
};

通过将事件处理程序属性的值设置为null ,可以移除通过DOM0方式添加的事件处理程序,如下面的例子所示:

btn.onclick = null;  // 移除事件处理程序

7.DOM2事件处理

addEventListener() 和removeEventListener()

它们接收3个参数:事件名、事件处理函数和一个布尔值,true 表示在捕获阶段调用事件处理程序,false (默认值)表示在冒泡阶段调用事件处理程序。

let btn = document.getElementById("myBtn");
btn.addEventListener("click", () => {
  console.log(this.id);
},

使用DOM2方式的主要优势是可以为同一个事件添加多个事件处理程序

let btn = document.getElementById("myBtn");
btn.addEventListener("click", () => {
  console.log(this.id);
}, false);
btn.addEventListener("click", () => {
  console.log("Hello world!");
}, false);

用removeEventListener() 并传入与添加时同样的参数来移除。这意味着使用addEventListener() 添加的匿名函数无法移除

let btn = document.getElementById("myBtn");
btn.addEventListener("click", () => {
  console.log(this.id);
 }, false);
// 其他代码
btn.removeEventListener("click", function() {    // 没有效果!
  console.log(this.id);

}, false);
let btn = document.getElementById("myBtn");
let handler = function() {
  console.log(this.id);
};
btn.addEventListener("click", handler, false);
// 其他代码
btn.removeEventListener("click", handler, false);  // 有效果!

传给remove的函数必须是和add是同一个函数。

8.attachEvent() 和detachEvent()

是IE实现了与DOM类似的方法

var btn = document.getElementById("myBtn");

btn.attachEvent("onclick", function() {
  console.log("Clicked");
});

attachEvent() 的第一个参数是"onclick" ,而不是DOM的addEventListener() 方法的"click" 。

使用DOM0方式时,事件处理程序中的this 值等于目标元素。而使用attachEvent() 时,事件处理程序是在全局作用域中运行的,因此this 等于window 。

var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function() {
  console.log(this === window);   // true
});
var btn = document.getElementById("myBtn");
var handler = function() {
  console.log("Clicked");
};
btn.attachEvent("onclick", handler);
// 其他代码
btn.detachEvent("onclick", handler);

9.跨浏览器事件处理程序

自定义addHandler() 方法

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

10.事件对象

在DOM中发生事件时,所有相关信息都会被收集并存储在一个名为event 的对象中。

DOM事件对象

let btn = document.getElementById("myBtn");
btn.onclick = function(event) {
  console.log(event.type);  // "click"
};
btn.addEventListener("click", (event) => {
  console.log(event.type);  // "click"
}, false);

不同的事件生成的事件对象也会包含不同的属性和方法。所有事件对象都会包含下表列出的这些公共属性和方法。

在这里插入图片描述

在这里插入图片描述
this 对象始终等于currentTarget 的值,而target 只包含事件的实际目标。

如果事件处理程序直接添加在了意
图的目标,则this 、currentTarget 和target 的值是一样的。

let btn = document.getElementById("myBtn");
btn.onclick = function(event) {
  console.log(event.currentTarget === this);  // true
  console.log(event.target === this);         // true
};

在document.body 上添加了单击处理程序:

document.body.onclick = function(event) {
  console.log(event.currentTarget === document.body);              // true
  console.log(this === document.body);                             // true
  console.log(event.target === document.getElementById("myBtn"));  // true
};

this 和currentTarget 都等于document.body
,这是因为它是注册事件处理程序的元素。而target 属性等于按钮本身,这是因为那才是click 事件真正的目标。

type 属性在一个处理程序处理多个事件时很有用。比如下面的处理程序中就使用了event.type :

let btn = document.getElementById("myBtn");
let handler = function(event) {
  switch(event.type) {
    case "click":
      console.log("Clicked");
      break;
    case "mouseover":
      event.target.style.backgroundColor = "red";
      break;
    case "mouseout":
      event.target.style.backgroundColor = "";
      break;
  }
};
btn.onclick = handler;
btn.onmouseover = handler;
btn.onmouseout = handler;

preventDefault() 方法用于阻止特定事件的默认动作

let link = document.getElementById("myLink");
link.onclick = function(event) {
  event.preventDefault();
};

任何可以通过preventDefault() 取消默认行为的事件,其事件对象的cancelable 属性都会设置为true 。

stopPropagation() 方法用于立即阻止事件流在DOM结构中传播,取消后续的事件捕获或冒泡

eventPhase 属性可用于确定事件流当前所处的阶段。

如果事件处理程序在捕获阶段被调用,则eventPhase 等于1;

如果事件处理程序在目标上被调用,则eventPhase 等于2;

如果事件处理程序在冒泡阶段被调用,则eventPhase 等于3。

IE事件对象

如果事件处理程序是使用DOM0方式指定的,则event 对象只是window 对象的一个属性,如下所示:

var btn = document.getElementById("myBtn");
btn.onclick = function() {
  let event = window.event;
  console.log(event.type);  // "click"
};

如果事件处理程序是使用attachEvent() 指定的,则event 对象会作为唯一的参数传给处理函数,如下所示:

var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function(event) {
  console.log(event.type);  // "click"
});

11.事件类型

DOM3 Events定义了如下事件类型。

用户界面事件 (UIEvent ):涉及与BOM交互的通用浏览器事
件。
焦点事件 (FocusEvent ):在元素获得和失去焦点时触发。
鼠标事件 (MouseEvent ):使用鼠标在页面上执行某些操作时触
发。
滚轮事件 (WheelEvent ):使用鼠标滚轮(或类似设备)时触
发。
输入事件 (InputEvent ):向文档中输入文本时触发。
键盘事件 (KeyboardEvent ):使用键盘在页面上执行某些操作
时触发。
合成事件 (CompositionEvent ):在使用某种IME(Input
Method Editor,输入法编辑器)输入字符时触发。

用户界面事件

DOMActivate :元素被用户通过鼠标或键盘操作激活时触发(比
click 或keydown 更通用)。这个事件在DOM3 Events中已经废
弃。因为浏览器实现之间存在差异,所以不要使用它。
load :在window 上当页面加载完成后触发,在窗套
(<frameset> )上当所有窗格(<frame> )都加载完成后触发,
在<img> 元素上当图片加载完成后触发,在<object> 元素上当相

应对象加载完成后触发。
unload :在window 上当页面完全卸载后触发,在窗套上当所有窗
格都卸载完成后触发,在<object> 元素上当相应对象卸载完成后
触发。
abort :在<object> 元素上当相应对象加载完成前被用户提前终
止下载时触发。
error :在window 上当JavaScript报错时触发,在<img> 元素上当
无法加载指定图片时触发,在<object> 元素上当无法加载相应对
象时触发,在窗套上当一个或多个窗格无法完成加载时触发。
select :在文本框(<input> 或textarea )上当用户选择了一
个或多个字符时触发。
resize :在window 或窗格上当窗口或窗格被缩放时触发。
scroll :当用户滚动包含滚动条的元素时在元素上触发。<body>
元素包含已加载页面的滚动条。

load 事件

在window 对象上,load 事件会在整个页面(包括所有外部资源如图片、JavaScript文件和CSS文件)加载完成后触发。
第一种

window.addEventListener("load", (event) => {
  console.log("Loaded!");
});

第二种

<!DOCTYPE html>
<html>
<head>
  <title>Load Event Example</title>
</head>
<body onload="console.log('Loaded!')">
</body>
</html>

为了向后兼容,所有浏览器都在window 上实现了load 事件

图片上也会触发load 事件,包括DOM中的图片和非DOM中的图片。可以在HTML中直接给 元素的onload 属性指定事件处
理程序:

<img src="smile.gif" onload="console.log('Image loaded.')">
let image = document.getElementById("myImage");
image.addEventListener("load", (event) => {
  console.log(event.target.src);
});

在通过JavaScript创建新<img> 元素时,也可以给这个元素指定一个在加载完成后执行的事件处理程序。在这里,关键是要在赋值src属性前指定事件处理程序,如下所示:

window.addEventListener("load", () => {
  let image = document.createElement("img");
  image.addEventListener("load", (event) => {
    console.log(event.target.src);
  });
  document.body.appendChild(image);
  image.src = "smile.gif";
});

下面的例子使用新Image 对象实现了图片预加载,下载图片并不一定要把 元素添加到文档,只要给它设置了src 属性就会立即开始下载。:

window.addEventListener("load", () => {
  let image = new Image();
  image.addEventListener("load", (event) => {
    console.log("Image loaded!");
  });
  image.src = "smile.gif";
});

unload 事件

unload 事件会在文档卸载完成后触发

window.addEventListener("unload", (event) => {
  console.log("Unloaded!");
});
<!DOCTYPE html>
<html>
<head>
  <title>Unload Event Example</title>
</head>
<body onunload="console.log('Unloaded!')">
</body>
</html>

无论使用何种方式,都要注意事件处理程序中的代码。因为unload 事件是在页面卸载完成后触发的,所以不能使用页面加载后才有的对象。此时要访问DOM或修改页面外观都会导致错误。

resize 事件

当浏览器窗口被缩放到新高度或宽度时,会触发resize 事件

scroll 事件
虽然scroll 事件发生在window 上,但实际上反映的是页面中相应元素的变化

window.addEventListener("scroll", (event) => {
  if (document.compatMode == "CSS1Compat") {
    console.log(document.documentElement.scrollTop);
  } else {
    console.log(document.body.scrollTop);
  }
});

焦点事件

blur :当元素失去焦点时触发。这个事件不冒泡,所有浏览器都
支持。
DOMFocusIn :当元素获得焦点时触发。这个事件是focus 的冒泡
版。Opera是唯一支持这个事件的主流浏览器。DOM3 Events废弃
了DOMFocusIn ,推荐focusin 。
DOMFocusOut :当元素失去焦点时触发。这个事件是blur 的通用
版。Opera是唯一支持这个事件的主流浏览器。DOM3 Events废弃
了DOMFocusOut ,推荐focusout 。
focus :当元素获得焦点时触发。这个事件不冒泡,所有浏览器都
支持。
focusin :当元素获得焦点时触发。这个事件是focus 的冒泡版。
focusout :当元素失去焦点时触发。这个事件是blur 的通用版。

当焦点从页面中的一个元素移到另一个元素上时,会依次发生如下事件。

(1) focuscout 在失去焦点的元素上触发。
(2) focusin 在获得焦点的元素上触发。
(3) blur 在失去焦点的元素上触发。
(4) DOMFocusOut 在失去焦点的元素上触发。
(5) focus 在获得焦点的元素上触发。
(6) DOMFocusIn 在获得焦点的元素上触发。

其中,blur 、DOMFocusOut 和focusout 的事件目标是失去焦点的元素,而focus 、DOMFocusIn 和focusin 的事件目标是获得焦点的元素。

鼠标和滚轮事件

DOM3 Events定义了9种鼠标事件

click :在用户单击鼠标主键(通常是左键)或按键盘回车键时触
发。这主要是基于无障碍的考虑,让键盘和鼠标都可以触发
onclick 事件处理程序。
dblclick :在用户双击鼠标主键(通常是左键)时触发。这个事
件不是在DOM2 Events中定义的,但得到了很好的支持,DOM3
Events将其进行了标准化。
mousedown :在用户按下任意鼠标键时触发。这个事件不能通过键
盘触发。
mouseenter :在用户把鼠标光标从元素外部移到元素内部时触
发。这个事件不冒泡,也不会在光标经过后代元素时触
发。mouseenter 事件不是在DOM2 Events中定义的,而是DOM3
Events中新增的事件。
mouseleave :在用户把鼠标光标从元素内部移到元素外部时触
发。这个事件不冒泡,也不会在光标经过后代元素时触
发。mouseleave 事件不是在DOM2 Events中定义的,而是DOM3
Events中新增的事件。
mousemove :在鼠标光标在元素上移动时反复触发。这个事件不能
通过键盘触发。
mouseout :在用户把鼠标光标从一个元素移到另一个元素上时触
发。移到的元素可以是原始元素的外部元素,也可以是原始元素的
子元素。这个事件不能通过键盘触发。
mouseover :在用户把鼠标光标从元素外部移到元素内部时触发。
这个事件不能通过键盘触发。
mouseup :在用户释放鼠标键时触发。这个事件不能通过键盘触
发。

除了mouseenter 和mouseleave,所有鼠标事件都会冒泡,都可以被取消,而这会影响浏览器的默认行为。

由于事件之间存在关系,因此取消鼠标事件的默认行为也会影响其他事件。

click 事件触发的前提是mousedown 事件触发后,紧接着又在同一个元素上触发了mouseup 事件。如果mousedown 和mouseup 中的任意一个事件被取消,那么click 事件就不会触发。类似地,两次连续的click 事件会导致dblclick 事件触发。只要有任何逻辑阻止了这两个click 事件发生(比如取消其中一个click 事件或者取消mousedown或mouseup 事件中的任一个),dblclick 事件就不会发生。

顺序:

(1) mousedown
(2) mouseup
(3) click
(4) mousedown
(5) mouseup
(6) click
(7) dblclick

客户端坐标
鼠标事件都是在浏览器视口中的某个位置上发生的。这些信息被保存在event 对象的clientX 和clientY 属性中。

let div = document.getElementById("myDiv");
div.addEventListener("click", (event) => {
  console.log(`Client coordinates: ${event.clientX}, ${event.clientY}`);
});

页面坐标
客户端坐标是事件发生时鼠标光标在客户端视口中的坐标,而页面坐标 是事件发生时鼠标光标在页面上的坐标,通过event 对象的pageX 和pageY 可以获取。

这两个属性表示鼠标光标在页面上的位置,因此反映的是光标到页面而非视口左边与上边的距离。

let div = document.getElementById("myDiv");
div.addEventListener("click", (event) => {
  console.log(`Page coordinates: ${event.pageX}, ${event.pageY}`);
});

屏幕坐标

鼠标事件不仅是在浏览器窗口中发生的,也是在整个屏幕上发生的。可以通过event 对象的screenX 和screenY 属性获取鼠标光标
在屏幕上的坐标。

可以像下面这样获取鼠标事件的屏幕坐标:

let div = document.getElementById("myDiv");
div.addEventListener("click", (event) => {
  console.log(`Screen coordinates: ${event.screenX}, ${event.screenY}`);
});

修饰键

虽然鼠标事件主要是通过鼠标触发的,但有时候要确定用户想实现的操作,还要考虑键盘按键的状态。键盘上的修饰键 Shift、Ctrl、Alt和Meta经常用于修改鼠标事件的行为。

DOM规定了4个属性来表示这几个修饰键的状态:shiftKey 、ctrlKey 、altKey 和metaKey 。这几属性会在各自对应的修饰键被按下时包含布尔值true ,没有被按下时包含false 。在鼠标事件发生的,可以通过这几个属性来检测修饰键是否被按下。

let div = document.getElementById("myDiv");
div.addEventListener("click", (event) => {
  let keys = new Array();
  if (event.shiftKey) {
    keys.push("shift");
  }
  if (event.ctrlKey) {
    keys.push("ctrl");
  }
  if (event.altKey) {
    keys.push("alt");
  }
  if (event.metaKey) {
    keys.push("meta");
  }
  console.log("Keys: " + keys.join(","));
});

鼠标按键

只有在元素上单击鼠标主键(或按下键盘上的回车键)时click 事件才会触发,因此按键信息并不是必需的。

对mousedown 和mouseup 事件来说,event 对象上会有一个button 属性,表示按
下或释放的是哪个按键。

DOM为这个button 属性定义了3个值:
0表示鼠标主键、
1表示鼠标中键(通常也是滚轮键)、
2表示鼠标副键。

按照惯例,鼠标主键通常是左边的按键,副键通常是右边的按键

mousewheel 事件

document.addEventListener("mousewheel", (event) => {
  console.log(event.wheelDelta);
});

wheelDelta
当鼠标滚轮向前滚动时,wheelDelta 每次都是+120;
当鼠标滚轮向后滚动时,wheelDelta 每次都是–120;

12.键盘与输入事件

键盘事件包含3个事件:
keydown ,用户按下键盘上某个键时触发,而且持续按住会重复触发。
keypress ,用户按下键盘上某个键并产生字符时触发,而且持续按住会重复触发。Esc键也会触发这个事件。DOM3 Events废弃了
keypress 事件,而推荐textInput 事件。
keyup ,用户释放键盘上某个键时触发。

每个键有键码,可以查。
keyCode 的值与小写字母和数字的ASCII编码一致

还有很多事件,不用全记,可以要用再查。

HTML5事件

contextmenu 事件

专门用于表示何时该显示上下文菜单,从而允许开发者取消默认的上下文菜单并提供自定义菜单。

contextmenu 事件冒泡,因此只要给document 指定一个事件处理程序就可以处理页面上的所有同类事件。

<!DOCTYPE html>
<html>
<head>
  <title>ContextMenu Event Example</title>
</head>
<body>
  <div id="myDiv">Right click or Ctrl+click me to get a custom context menu.
    Click anywhere else to get the default context menu.</div>
  <ul id="myMenu" style="position:absolute;visibility:hidden;background-color:
    silver">
    <li><a href="http://www.somewhere.com"> somewhere</a></li>
    <li><a href="http://www.wrox.com">Wrox site</a></li>
    <li><a href="http://www.somewhere-else.com">somewhere-else</a></li>
  </ul>
</body>
</html>
window.addEventListener("load", (event) => {
  let div = document.getElementById("myDiv");
  div.addEventListener("contextmenu", (event) => {
    event.preventDefault();
    let menu = document.getElementById("myMenu");
    menu.style.left = event.clientX + "px";
    menu.style.top = event.clientY + "px";
    menu.style.visibility = "visible";
  });
  document.addEventListener("click", (event) => {
    document.getElementById("myMenu").style.visibility = "hidden";
  });
});

beforeunload 事件

beforeunload 事件会在window 上触发,用意是给开发者提供阻止页面被卸载的机会。

window.addEventListener("beforeunload", (event) => {
  let message = "I'm really going to miss you if you go.";
  event.returnValue = message;
  return message;
});

DOMContentLoaded 事件

而DOMContentLoaded 事件会在DOM树构建完成后立即触发,而不用等待图片、JavaScript文件、CSS文件或其他资源加载完成。相对于load 事件,DOMContentLoaded 可以让开发者在外部资源下载的同时就能指定事件处理程序,从而让用户能够更快地与页面交互。

document.addEventListener("DOMContentLoaded", (event) => {
  console.log("Content loaded");
});

readystatechange 事件

支持readystatechange 事件的每个对象
都有一个readyState 属性,该属性具有一个以下列出的可能的字符串值。

uninitialized :对象存在并尚未初始化。
loading :对象正在加载数据。
loaded :对象已经加载完数据。
interactive :对象可以交互,但尚未加载完成。
complete :对象加载完成。

pageshow 与pagehide 事件

hashchange 事件

HTML5增加了hashchange 事件,用于在URL散列值(URL最后#后面的部分)发生变化时通知开发者。这是因为开发者经常在Ajax应用程序中使用URL散列值存储状态信息或路由导航信息。

onhashchange 事件处理程序必须添加给window ,每次URL散列值发生变化时会调用它。event 对象有两个新属性:oldURL 和newURL 。这两个属性分别保存变化前后的URL,而且是包含散列值的完整URL。下面的例子展示了如何获取变化前后的URL:

window.addEventListener("hashchange", (event) => {
  console.log(`Old URL: ${event.oldURL}, New URL: ${event.newURL}`);
});

如果想确定当前的散列值,最好使用location 对象:

window.addEventListener("hashchange", (event) => {
  console.log(`Current hash: ${location.hash}`);
});

设备事件
用的时候再查.

13.内存与性能

事件委托:
“过多事件处理程序”的解决方案是使用事件委托 。事件委托利用事件冒泡,可以只使用一个事件处理程序来管理一种类型的事件。

<ul id="myLinks">
  <li id="goSomewhere">Go somewhere</li>

  <li id="doSomething">Do something</li>
  <li id="sayHi">Say hi</li>
</ul>

这里的HTML包含3个列表项,在被点击时应该执行某个操作。对此,通常的做法是像这样指定3个事件处理程序:

let item1 = document.getElementById("goSomewhere");
let item2 = document.getElementById("doSomething");
let item3 = document.getElementById("sayHi");
item1.addEventListener("click", (event) => {
  location.href = "http:// www.wrox.com";
});
item2.addEventListener("click", (event) => {
  document.title = "I changed the document's title";
});
item3.addEventListener("click", (event) => {
  console.log("hi");
});

使用事件委托,只要给所有元素共同的祖先节点添加一个事件处理程序,就可以解决问题。比如:

let list = document.getElementById("myLinks");
list.addEventListener("click", (event) => {
  let target = event.target;
  switch(target.id) {
    case "doSomething":
      document.title = "I changed the document's title";
      break;
    case "goSomewhere":
      location.href = "http:// www.wrox.com";
      break;

    case "sayHi":
      console.log("hi");
      break;
  }
});

事件委托具有如下优点。

document 对象随时可用,任何时候都可以给它添加事件处理程序(不用等待DOMContentLoaded 或load 事件)。这意味着只要页面渲染出可点击的元素,就可以无延迟地起作用。

节省花在设置页面事件处理程序上的时间。只指定一个事件处理程序既可以节省DOM引用,也可以节省时间。

减少整个页面所需的内存,提升整体性能。

删除事件处理程序

删除带有事件处理程序的元素

<div id="myDiv">
  <input type="button" value="Click Me" id="myBtn">
</div>
<script type="text/javascript">
  let btn = document.getElementById("myBtn");
  btn.onclick = function() {
    // 执行操作
    document.getElementById("myDiv").innerHTML = "Processing...";
    // 不好!
  };
</script>
<div id="myDiv">
  <input type="button" value="Click Me" id="myBtn">
</div>
<script type="text/javascript">
  let btn = document.getElementById("myBtn");
  btn.onclick = function() {
    // 执行操作
    btn.onclick = null;   // 删除事件处理程序
    document.getElementById("myDiv").innerHTML = "Processing...";
  };

</script>

这样就可以确保内存被回收,按钮也可以安全地从DOM中删掉。

如果在页面卸载后事件处理程序没有被清理,则它们仍然会残留在内存中。

一般来说,最好在onunload 事件处理程序中趁页面尚未卸载先删除所有事件处理程序。这时候也能体现使用事件委托的优势,因为事件处理程序很少,所以很容易记住要删除哪些。关于卸载页面时的清理,可以记住一点:onload 事件处理程序中做了什么,最好在onunload 事件处理程序中恢复。

14.模拟事件

任何时候,都可以使用document.createEvent() 方法创建一个event对象。这个方法接收一个参数,此参数是一个表示要创建事件类型的字符串。

let btn = document.getElementById("myBtn");
// 创建event对象
let event = document.createEvent("MouseEvents");
// 初始化event对象
event.initMouseEvent("click", true, true, document.defaultView,
                     0, 0, 0, 0, 0, false, false, false, false, 0, null);

// 触发事件
btn.dispatchEvent(event);
let textbox = document.getElementById("myTextbox"),

    event;
// 按照DOM3的方式创建event对象
if (document.implementation.hasFeature("KeyboardEvents", "3.0")) {
   event = document.createEvent("KeyboardEvent");
   // 初始化event对象
   event.initKeyboardEvent("keydown", true, true, document.defaultView, "a",
                           0, "Shift", 0);
}
// 触发事件
textbox.dispatchEvent(event);

也就是可以模拟一些事件的发生.

自定义DOM事件

DOM3增加了自定义事件 的类型。自定义事件不会触发原生DOM事件,但可以让开发者定义自己的事件。要创建自定义事件,需要调用createEvent(“CustomEvent”) 。返回的对象包含initCustomEvent() 方法,该方法接收以下4个参数。

type (字符串):要触发的事件类型,如"myevent" 。bubbles (布尔值):表示事件是否冒泡。
cancelable (布尔值):表示事件是否可以取消。detail (对象):任意值。作为event 对象的detail 属性。

自定义事件可以像其他事件一样在DOM中派发,比如:

let div = document.getElementById("myDiv"),
    event;
div.addEventListener("myevent", (event) => {
  console.log("DIV: " + event.detail);
});
document.addEventListener("myevent", (event) => {
  console.log("DOCUMENT: " + event.detail);
});
if (document.implementation.hasFeature("CustomEvents", "3.0")) {
  event = document.createEvent("CustomEvent");
  event.initCustomEvent("myevent", true, false, "Hello world!");
  div.dispatchEvent(event);
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值