DOM 事件机制

DOM 事件机制

  • 事件是元素天生具有的行为方式(和写不写 JS 代码不要紧),当咱们去操做元素的时候会触发元素的不少事件
  • 给当前元素的某一个事件绑定方法,目的是为了让当前元素某个事件被触发的时候,能够作一些事情

DOM0 事件

DOM0 事件绑定javascript

element.onclick=function(e){
  //=>this:element
   e=e||window.event;

element.onmouseenter=function(){}
  • 给当前元素对象的某一个私有属性(onxxx 这样的私有属性)赋值的过程(以前属性默认值是 null,若是咱们给赋值一个函数,至关于绑定了一个方法)
  • 当赋值成功(赋值一个函数),此时浏览器会把 DOM 元素和赋值的函数创建关联,以及创建 DOM 元素行为操做的监听,当某一个行为被用户触发,浏览器会把相关行为赋值的函数执行
  • 一、只有 DOM 元素天生拥有这个私有属性(onxxx 事件私有属性),咱们赋值的方法才叫作事件绑定,不然属于给当前元素设置一个自定义属性而已
  • 二、移除事件绑定的时候,咱们只须要赋值为 null 便可
  • 三、在 DOM0 事件绑定中,只能给当前元素的某一个事件行为(某一个事件私有属性)绑定一个方法,绑定多个方法,最后一次绑定的会把以前绑定的都替换掉
btn.onclick = function() {
  console.log("this is a click event");
};

click 事件并无像其余函数同样,必需要调用才能够执行,click 事件并不肯定何时发生,而当浏览器发现用户点击该按钮时,浏览器就检测 btn.onclick 是否有值,若是有,就会执行 btn.onclick.call(btn,event),此时函数执行,call() 方法接收两个参数,第一个指向调用当前方法的对象,也就是 thishtml

须要注意的是,指定的 this 值并不必定是该函数执行时真正的 this 值,若是这个函数处于非严格模式下,则指定为 nullundefinedthis 值会自动指向全局对象(浏览器中就是 window 对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。java

另外一个参数则是事件对象 event,该对象也能够经过 arguments[0] 来访问,它包含了事件相关的全部信息,如本例子中,则包含了点击事件的所有信息。能够经过给函数传参来获取事件信息。node

btn.onclick = function(e) {
  console.log("this is a click event");
  console.log(e); //  事件对象
};

在 DOM0 级中,若是想要实现一个对象绑定多个函数,能够这样实现。git

function fn1() {
  // do something
}
function fn2() {
  // do something
}
btn.onclick = function(e) {
  fn1.call(this, xxx);
  fn2.call(this, yyy);
};
https://github.com/HarleyWang...

DOM2 事件

当前这个实例 document.body 之因此能用 addEventListener 这个方法,说明这个方法确定在它的原型上出现。github

能够用 instanceof 检测浏览器

DOM2 级事件定义了两个方法,用于处理指定和删除事件处理程序的操做,addEventListener()removeEventListener(),全部的 DOM 节点中都包含这两个方法,它们都接收 3 个参数dom

  • 要处理的事件名
  • 做为事件处理程序的函数
  • 布尔值,true 表明在捕获阶段调用事件处理程序,false 表示在冒泡阶段调用事件处理程序,默认为 false
btn.addEventListener("click", function() {
  //  do something
});
btn.addEventListener("click", function() {
  //  do something else
});
element.addEventListener(
  "click",
  function(event) {
    // 只执行一次的代码
  },
  { once: true }
);
  • 一、 DOM2 事件绑定使用的 addEventListener/attachEvent 都是在 EventTarget 这个内置类的原型上定义的,调取使用的时候,首先经过原型链找到这个方法,而后执行完成事件绑定的效果
  • 浏览器首先会给当前元素的某一个事件行为开辟一个事件池(事件队列)[实际上是浏览器有一个统一的事件池,咱们每一个元素的某个行为绑定的方法都放在这个事件池中,只是经过相关的标识来区分的],当咱们经过 addEventListener 作事件监听的时候,会把绑定的方法存放在事件池中
  • 当元素的某一个行为触发,浏览器会到对应的事件池中,把当前存放在事件池中的全部方法,依次按照存放的前后顺序执行

DOM0 是私有属性赋值,DOM2 是事件池的事件机制编辑器

  • 一、全部 DOM0 支持的事件行为,DOM2 均可以使用,不只如此,DOM2 还支持一些 DOM0 没有的事件行为:DOMContentLoaded...
  • 二、DOM2 中能够给当前元素的某一个事件行为绑定‘多个不一样的方法’(不一样的方法=>不一样的空间地址,好比一个私有 fn 和全局的 fn 地址不同,因此不是同一个 fn 方法,)(由于绑定的全部方法都存放在事件池中了;而 DOM0 是经过给私有属性赋值来绑定方法的,一个私有属性只能附一个值)
  • 三、DOM2 事件绑定的移除比较麻烦一些,须要和绑定的时候:事件类型、绑定的方法、传播阶段,三个彻底一致才能够移除掉

DOM3 事件

DOM3 级事件在 DOM2 级事件的基础上添加了更多的事件类型,所有类型以下函数

事件类型 说明 举例
UI 事件 当用户与页面上的元素交互时触发 {load、scroll
焦点事件 当元素得到或失去焦点时触发 blur、focus
鼠标事件 当用户经过鼠标在页面执行操做时触发 dbclick、mouseup
滚轮事件 当使用鼠标滚轮或相似设备时触发 mousewheel
文本事件 当在文档中输入文本时触发 textInput
键盘事件 当用户经过键盘在页面上执行操做时触发 keydown、keypress
合成事件 当为 IME(输入法编辑器)输入字符时触发 compositionstart
变更事件 当底层 DOM 结构发生变化时触发 DOMsubtreeModified

同时 DOM3 级事件也容许开发人员自定义一些事件。

var event = new Event('build');

// Listen for the event.
elem.addEventListener('build', function (e) { ... }, false);

// Dispatch the event.
elem.dispatchEvent(event);

添加自定义数据 – CustomEvent()

var event = new CustomEvent("build", { detail: elem.dataset.time });

冒泡事件&捕获事件

img

事件委托

因为事件会在冒泡阶段向上传播到父节点,所以能够把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件。这种方法叫作事件的代理(delegation

那么利用事件冒泡或捕获的机制,能够对事件绑定作一些优化。 在 JS 中,若是咱们注册的事件愈来愈多,页面的性能就愈来愈差,由于:

  • 函数是对象,会占用内存,内存中的对象越多,浏览器性能越差
  • 注册的事件通常都会指定 DOM 元素,事件越多,致使 DOM 元素访问次数越多,会延迟页面交互就绪时间。
  • 删除子元素的时候不用考虑删除绑定事件
<ul id="list">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
</ul>

<script>
// 给父层元素绑定事件
document.getElementById('list').addEventListener('click', function (e) {
    // 兼容性处理
    var event = e || window.event;
    var target = event.target || event.srcElement;
    // 判断是否匹配目标元素
    if (target.nodeName.toLocaleLowerCase() === 'li') {
        console.log('the content is: ', target.innerHTML);
    }
});
</script>

EventTarget

DOM 的事件操做(监听和触发),都定义在 EventTarget 接口。全部节点对象都部署了这个接口,其余一些须要事件通讯的浏览器内置对象(好比,XMLHttpRequestAudioNodeAudioContext)也部署了这个接口

该接口主要提供三个实例方法。

  • addEventListener:绑定事件的监听函数;用于在当前节点或对象上,定义一个特定事件的监听函数。一旦这个事件发生,就会执行监听函数。该方法没有返回值。
  • removeEventListener:移除事件的监听函数;方法用来移除 addEventListener 方法添加的事件监听函数;removeEventListener 方法的参数,与 addEventListener 方法彻底一致
  • dispatchEvent:触发事件;当前节点上触发指定事件,从而触发监听函数的执行。该方法返回一个布尔值,只要有一个监听函数调用了 Event.preventDefault(),则返回值为 false,不然为 true;参数是 Event 实例

Event 对象常见的方法和属性

  • event. preventDefault();若是调用这个方法,默认事件行为将再也不触发。什么是默认事件呢?例如表单一点击提交按钮(submit)刷新页面、a 标签默认页面跳转或是锚点定位等
  • event.stopPropagation() & event.stopImmediatePropagation() event.stopPropagation() 方法阻止事件冒泡到父元素,阻止任何父事件处理程序被执行; stopImmediatePropagation 既能阻止事件向父元素冒泡,也能阻止元素同事件类型的其它监听器被触发。而 stopPropagation 只能实现前者的效果
https://juejin.im/post/5be643...

https://www.w3.org/TR/DOM-Lev...

https://javascript.ruanyifeng...

https://javascript.ruanyifeng...

相关文章
相关标签/搜索