[TOC]

一、事件
是某事发生的信号。所有的DOM节点都生成这样的信号(但事件不仅限于DOM)
二、DOM事件列表
见:https://www.yuque.com/tqpuuk/yrrefz/ixdth3

事件机制

一、事件机制有3个组成部分;

  1. 事件源:即事件的发送者
  2. 事件:事件源发出的一种信息或状态
  3. 事件侦听者:对事件作出反映的对象。

    事件处理程器

    一、处理程序(handler):一个在事件发生时运行的函数
    二、处理程序是在发生用户行为(action)时运行JavaScript代码的一种方式。

    分配处理程序的方法

    HTML特性

    一、处理程序可以设置在HTML中名为on的特性(attribute)中。
    【示例1】要为input分配一个click处理程序,可以使用onclick
    <input value="Click me" onclick="alert('Click!')" type="button">
    
    二、最好创建一个JavaScript函数,然后在HTML特性中调用这个函数 ```jsx

三、HTML特性名是大小写不敏感的,所以ONCLICK和onClick以及onCLICK都一样可以运行。但是特性通常是小写的:onclick
<a name="4owgP"></a>
### DOM属性(同HTML特性)
一、可以使用DOM属性(property)on<event>来分配处理程序。<br />【示例1】elem.onclick
```jsx
<input id="elem" type="button" value="Click me">
<script>
  elem.onclick = function() {
    alert('Thank you');
  };
</script>

二、如果一个处理程序是通过HTML特性(attribute)分配的,那么随后浏览器读取它,并从特性的内容创建一个新函数,并将这个函数写入DOM属性(property)。
三、下面两段代码工作相同
1、只有HTML
(1)button.onclick是通过HTML特性(attribute)初始化的

<input type="button" onclick="alert('Click!')" value="Button">

2、HTML + JS
(1)通过脚本初始化

<input type="button" id="button" value="Button">
<script>
  button.onclick = function() {
    alert('Click!');
  };
</script>

四、因为只有一个onclick属性,所以我们无法分配更多事件处理程序。
【示例1】使用JavaScript添加一个处理程序,覆盖现有的处理程序

<input type="button" id="elem" onclick="alert('Before')" value="Click me">
<script>
  elem.onclick = function() { // 覆盖了现有的处理程序
    alert('After'); // 只会显示此内容
  };
</script>

五、要移除一个处理程序,就赋值elem.onclick = null

访问元素:this

一、处理程序中的this的值是对应的元素。就是处理程序所在的那个元素。
【示例1】button使用this.innerHTML来显示它的内容

<button onclick="alert(this.innerHTML)">Click me</button>

可能出现的错误

一、可以将一个现存的函数用作处理程序。函数应该是以func的形式进行赋值,而不是func()

function sayThanks() {
  alert('Thanks!');
}

// 函数应该是以sayThanks的形式进行赋值,而不是sayThanks()
// 正确
button.onclick = sayThanks;

// 错误
button.onclick = sayThanks(); // 添加了括号,sayThanks就变成了一个函数调用。这行代码实际上获得的是函数执行的结果,即undefined(因为这个函数没有返回值)。此代码不会工作

二、在标记(markup)中,需要括号

<input type="button" id="button" onclick="sayThanks()">

1、当浏览器读取HTML特性(attribute)时,浏览器将会使用特性中的内容,创建一个处理程序。
2、标记(markup)会生成下面这个属性

button.onclick = function() {
    sayThanks(); // 特性(attribute)中的内容变到了这里
}

三、不要对处理程序使用setAttribute
1、这样调用会失效

// 点击<body>将产生error
// 因为特性总是字符串的,函数变成了一个字符串
document.body.setAttribute('onclick', function() {alert(1)});

四、DOM属性是大小写敏感的
1、将处理程序分配给elem.onclick,而不是elem.ONCLICK,因为DOM属性是大小写敏感的。

addEventListener

一、上述分配处理程序的方式的根本问题是:我们不能为一个事件分配多个处理程序。

| 【示例】在我们点击了一个按钮时,我们代码中的一部分想要高亮显示这个按钮,另一部分则想要显示一条消息。我们想为此事件分配两个处理程序。但是,新的DOM属性将覆盖现有的DOM属性。```jsx input.onclick = function() { alert(1); } input.onclick = function() { alert(2); } // 替换了前一个处理程序

 |
| --- |

二、可以使用特殊方法addEventListener和removeEventListener来管理处理程序的替代方法。它们没有这样的问题。
```jsx
// 添加处理程序的语法
element.addEventListener(event, handler[, {
    capture: false, // 默认为false
  passive: false, // 默认为false
  once: false, // 默认未false
}])

1、event
事件名,如”click”
2、handler
处理程序
3、options
(1)具有以下属性的附加可选对象
① once:如果为true,那么会在被触发后自动删除监听器。
② capture:事件处理的阶段。由于历史原因,options也可以是false / true,它与{ capture: false / true } 相同。
③ passive:如果为true,那么处理程序将不会调用preventDefault()。
三、要移除处理程序,可以使用removeEventListener

element.removeEventListener(event, handler[, options]);

四、移除需要相同的函数
1、要移除(removeEventListener)处理程序,我们需要传入与分配(addEventListener)的函数完全相同的函数

| 【示例】以下不起作用```jsx elem.addEventListener(‘click’, () => alert(‘Thanks!’));

// 运行以下代码,处理程序不会被移除,因为removeEventListener获取了另一个函数。虽然使用相同的代码,但这并不起作用,因为它是一个不同的函数对象 elem.removeEventListener(‘click’, () => alert(‘Thanks!’));

【示例】正确方法```jsx
function handler() {
  alert( 'Thanks!' );
}

input.addEventListener("click", handler);
// ....
input.removeEventListener("click", handler);

| | —- |

五、多次调用addEventListener,允许添加多个处理程序。

<input id="elem" type="button" value="Click me" />

<script>
  function handler1() {
    alert('Thanks!');
  };

  function handler2() {
    alert('Thanks again!');
  }

  elem.onclick = () => alert("Hello");
  elem.addEventListener("click", handler1); // Thanks!
  elem.addEventListener("click", handler2); // Thanks again!
</script>

1、我们可以同时使用DOM属性和addEventListener来设置处理程序。但通常我们只使用其中一种方式。
六、对于某些事件,只能通过addEventListener设置处理程序
1、有些事件无法通过DOM属性进行分配。只能使用addEventListener,所以addEventListener更通用。

| 【示例】DOMContentLoaded事件,该事件在文档加载完成并且DOM构建完成时触发。```jsx // 永远不会运行 document.onDOMContentLoaded = function() { alert(“DOM built”); };

// 这种方式可以运行 document.addEventListener(“DOMContentLoaded”, function() { alert(“DOM built”); });

 |
| --- |

七、addEventListener与onxxx(比如onclick)的区别

- 使用addEventListener监听事件不会被覆盖,而on会覆盖上一个事件
<a name="eooF2"></a>
# 事件对象
一、当事件发生时,浏览器会创建一个event对象,将详细信息放入其中,并将其作为参数传递给处理程序。

| 【示例】下面是一个从event对象获取鼠标指针的坐标的示例```jsx
<input type="button" value="Click me" id="elem">

<script>
  elem.onclick = function(event) {
    // 显示事件类型、元素和点击的坐标
    alert(event.type + " at " + event.currentTarget);
    alert("Coordinates: " + event.clientX + ":" + event.clientY);
  };
</script>

| | —- |

1、event对象的一些属性
(1)event.type
事件类型,这里是’click’
(2)event.currentTarget
处理事件的类型。这与this相同,除非处理程序是一个箭头函数,或者它的this被绑定到了其他东西上,之后我们就可以从event.currentTarget获取元素了。
(3)event.clientX / event.clientY
指针事件(pointer event)的指针的窗口相对坐标。
二、event对象在HTML处理程序中也可用
1、如果我们在HTML中分配了一个处理程序,那么我们也可以使用event对象,像这样

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

(1)当浏览器读取特性(attribute)时,它会创建像这样的处理程序:function(event) { alert(event.type) }。也就是说:它的第一个参数是“event”,而主体取自该特性(attribute)
三、事件对象有DOM类型和IE类型
1、DOM中的事件对象:(符合W3C标准)
preventDefault() 取消事件默认行为
stopImmediatePropagation() 取消事件冒泡同时阻止当前节点上的事件处理程序被调用。
stopPropagation() 取消事件冒泡对当前节点无影响。
2、IE中的事件对象:
e.cancelBubble = true 取消事件冒泡
returnValue() 取消事件默认行为

对象处理程序:handleEvent

一、我们不仅可以分配函数,还可以使用addEventListener将一个对象分配为事件处理程序。当事件发生时,我们就会调用该对象的handleEvent方法

| 【示例】使用对象```jsx

 |
| --- |

| 【示例】使用类```jsx
<button id="elem">Click me</button>

<script>
  class Menu {
    // 同一个对象处理两个事件
    handleEvent(event) {
      switch(event.type) {
        case 'mousedown':
          elem.innerHTML = "Mouse button pressed";
          break;
        case 'mouseup':
          elem.innerHTML += "...and released.";
          break;
      }
    }
  }

  // menu 对象只监听 mousedown 和 mouseup,而没有任何其他类型的事件
  let menu = new Menu();
  elem.addEventListener('mousedown', menu);
  elem.addEventListener('mouseup', menu);
</script>

| | —- |

二、handleEvent方法不必通过自身完成所有的工作。它可以调用其他特定于事件的方法

| 【示例】```jsx

``` | | —- |