最全的DOM事件笔记

摘要:
1.DOM事件模型是微软和Netscape之间“浏览器战争”的产物。后来,它被“W3C”标准化。标准化不断升级和完善。目前,它已经升级到第四代,即level1(DOM 1)、level2(DOM 2)、level3(DOM 3)和level4(DOM 4)。事件模型是DOM的一部分,在不同的开发阶段有不同的定义。1.1 DOM 0/DOM 1时期的事件模型。DOM 0指的是尚未被“W3C”标准化的DOM

1. DOM事件模型

DOM是微软和网景发生“浏览器大战”时期留下的产物,后来被“W3C”进行标准化,标准化一代代升级与改进,目前已经推行至第四代,即 level1(DOM1)、level2(DOM2)、level3(DOM3)、level4(DOM4)。事件模型是DOM的一部分,在不同的发展时期有不同的定义。

1.1 DOM0 / DOM1时期的事件模型

DOM0指的是未被“W3C”标准化前的DOM,DOM被“W3C”正式标准化后才开始的DOM1,因此DOM1是DOM0的整理和归纳,也就是说DOM事件模型最开始的定义是在DOM0 / DOM1 时期,这时的DOM事件模型如下:

① HTML中的onevent事件属性

//在元素上使用 HTML  attribute on{eventtype}

<div onclick="alert('old')">点击div</div>

//赋值为事件处理函数
<div onclick="fn()"></div> //必须是加括号的调用形式
<div onclick="fn.call()"></div> //相当于fn()
<script>
  function fn(){
    console.log('ok');
  }
</script>

//此种方式的事件信息怎么传递
<div onclick="pe(event)">点击</div> //这里必须传递 event 关键字对象

<script>
  function pe(e){
    console.log(e); //事件信息
  }
</script>

② js 操作DOM节点的事件属性

//通过 JavaScript 设置页面元素相应的事件属性

let div = document.getElementById("a");
div.onclick = function() { alert('new') };

//当函数单独定义时
function fn(){
   alert("new");
}
div.onclick = fn;  //必须是不加括号,传递地址的形式

1.2 DOM2时期的事件模型

DOM2中的事件模型已经非常完善了,在DOM3中并未对事件模型进行修改,因此至今的事件模型是以DOM2事件标准为基准的。DOM2标准事件模型采用了事件监听队列,如下:

//addEventListener是添加事件监听,removeEventListener是移除事件监听

let div = document.getElementById("a");
div.addEventListener('click', function(e){
  console.log('点击div')
})

//基本语法
target.addEventListener(type, listener, useCapture);
target.addEventListener(type, listener, options);

type:表示监听事件类型的字符串

listener:事件处理函数,形参为事件信息

useCapture:Boolean类型的值,表示是否在捕获阶段触发事件,默认为false,默认在冒泡阶段处理事件,若设置为true,则会在捕获阶段处理事件。

options:一个指定有关  listener  属性的可选参数对象,相比于useCapture,可以有更多的设置,options对象的属性值都是Boolean值,默认全部为false,
{capture: 是否捕获阶段监听, once: 是否只监听一次, passive: 是否忽略preventDefault }

2. DOM事件机制(事件流)

DOM事件流的出现是在DOM节点中事件发生时常见的一种现象中产生的,如下问题:

<div   onclick="console.log('我是爷爷')">
      <div   onclick="console.log('我是爸爸')">
            <div   onclick="console.log('我是儿子')">
                  文字
            </div>
      </div>
</div>

//1. 点击了“文字”后,算不算点击了儿子?算不算点击了“爸爸”,算不算点击了“爷爷”?
//   答案是都算,点击元素内部的任一元素节点,都算点击了该元素。这就涉及到一个事件流的问题

由上述可知,事件是会传递的,但是事件会以怎样的顺序进行传递执行?

在上述的例子中,我们第一眼就想到的就是,点击了“文字”,会依次向上传递,先执行离“文字”最近的儿子的click事件处理程序,再执行父亲的,最后执行爷爷的。没错,在“浏览器大战”时微软的IE浏览器就是按照由内向外的事件流顺序定义DOM事件流的。但是和其对立的网景公司却是反着定义的,网景公司的DOM事件流传递顺序是由外层向内层执行,先执行爷爷的,再执行爸爸的,最后执行儿子的。

在W3C规定的DOM2中统一了DOM事件机制的标准,即规定事件的传递顺序是先从外层向内层依次传递,称之为“捕获阶段”,再从内层向外层依次传递,称之为“冒泡阶段”。但并不意味着一个事件处理程序要在“捕获”和“冒泡”同时执行两次,而是用户选择其事件处理程序的执行时期是在“捕获阶段”还是“冒泡阶段”。在DOM2的 addEventListener函数的第三个参数(useCapture)就是让用户选择该处理程序是放在“捕获阶段”执行还是“冒泡阶段”执行。默认是 false,即事件监听机制默认是在“冒泡阶段”,也就是用 addEventListener 定义的事件处理程序是默认在冒泡阶段执行。

但是无论事件在哪个阶段执行,一个完整的事件流都是先“捕获阶段”,再“冒泡阶段”,捕获和冒泡都检查一遍。除此之外,还添加了一个“目标阶段”,就是用户真正点击的元素的事件处理阶段。

捕获阶段 ====> 目标阶段 ====> 冒泡阶段

捕获不可以取消,冒泡可以取消。取消冒泡:e.stopPropagation()

最全的DOM事件笔记第1张

补充: 一般情况下,如果在捕获阶段和冒泡阶段都有对应的事件处理函数,一般是先执行捕获,再执行冒泡。但是如果只有一个div被监听时,对其来说,捕获和冒泡是同级的,因此会按照其代码顺序,谁先注册先执行。

3. DOM事件委托(代理)

事件委托是指本该自己监听的事件交给父元素或祖先元素监听,然后在祖先元素的监听函数中判断是否是触发的当前元素的事件,并进行相应的处理操作。时间委托就是由祖先元素监听事件,并根据事件来源统一处理。

有时候,页面元素是动态生成的,提前写好的事件绑定可能在元素还未出现时就已经执行,则事件处理则无法执行,除非在生成时再次绑定。这样比较麻烦,因此可以用事件代理,由祖先元素监听事件后进行相应的处理。被委托的祖先元素一般是页面中不变的一直存在的元素。那么被委托的祖先元素如何分发事件呢?

3.1 通过 e.target 分发事件

target 和 currentTarget 是DOM事件对象e上的属性,这两个属性是在事件委托中才各有各的作用,在不是事件委托的自己负责事件监听的DOM事件对象中,二者是相同的,都是元素本身。

二者的区别在于: e.target 是用户操作的实际对象,而 e.currentTarget 是程序员监听的对象。非箭头事件处理函数中的 this 是 e.currentTarget。

因此可以通过 e.target 来判断当前操作的元素,从而进行事件分发。

<div class="grandpa">
      <div class="father">
            <div class="child">
              <span class="text">文字</span>
            </div>
      </div>
</div>
let grandpa = document.querySelector(".grandpa");
grandpa.addEventListener('click',(e)=>{
  const t = e.target;
  if(t.className === "text"){
    console.log("span元素被点击了");
  }
  console.log(e.target);    // 是用户实际点击的元素
  console.log(e.currentTarget);   //一直是 div.grandpa 元素
})

3.2 通过 path 分发事件

在上述的 e.target 分发事件存在不准确的问题,比如div.parent元素进行事件监听时,想监听的是div.child元素,但是点击child内部的"span"元素时也算点击了child元素,应该触发child的点击事件,但是这里单单凭借e.target获得到的是"span"元素,无法用于判断到点击了child元素。这里可以使用DOM事件对象的"path"属性。

这是点击 span 时的 “path” 属性

最全的DOM事件笔记第2张

这是点击 child 时的 “path” 属性

最全的DOM事件笔记第3张

因此 "path" 属性是一个存储了"捕获和冒泡"的所有事件传递的路径元素信息,从 e.target 被操作的元素本身到其祖宗元素。可以通过该"path"属性进行精确的判断,上述例子修改如下:

let grandpa = document.querySelector(".grandpa");
grandpa.addEventListener('click',(e)=>{
  let child = e.path.find(el=>el.className === 'child');
  if(child){
    console.log("child 被点击了");  //点击 span 元素时也会输出"child被点击了"
  }
})

3.3 事件委托优点

① 省监听数,省内存

② 可以监听动态元素

4. DOM事件对象

4.1 e.target VS e.currentTarget

e.target 是操作对象本身,e.currentTarget是程序员监听的对象

4.2 e.path

e.path是存放了从 e.target 元素到最顶端祖先元素的事件传递路径信息的数组。

4.3 e.type

e.type是事件类型,如'click'事件。

4.4 e.bubbles VS e.cancelable

e.bubbles 和 e.cancelable 都是布尔值,e.bubbles 表示该事件是否支持冒泡,e.cancelable 表示该事件是否可以取消冒泡,如scroll不支持取消冒泡。

5. 自定义事件

浏览器提供了100多种事件,详细可见 DOM事件。但是浏览器也允许用户自定义事件,自定义事件需要考虑三个问题:

①自定义事件的事件定义

通过 "CustomEvent" 构造函数构造出一个自定义事件对象,第一个参数是自定义事件名,第二个参数是一个对象,是事件对象的定义。默认的 bubbles 等都是false。

②自定义事件的触发

通过dispatchEvent(event)函数触发自定义事件。

③自定义事件的监听

和普通事件一样的监听方法。

let grandpa = document.querySelector(".grandpa");
grandpa.addEventListener('click',(e)=>{
  const event = new CustomEvent('sayHi',{
    detail: {name: 'myEvent', content: 'hello'},
    bubbles: true,
    cancelable: true
  });  //① 自定义事件本身
  grandpa.dispatchEvent(event); //② 触发自定义事件
})
grandpa.addEventListener('sayHi',(e)=>{
  console.log(e); 
  console.log(e.detail.content);  //输出 hello
})  //③ 监听自定义事件,和监听普通事件一样。

免责声明:文章转载自《最全的DOM事件笔记》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇六.ansible批量管理服务Java基础知识强化之IO流笔记34:OutputStreamWriter(Writer字符流的子类)5种write数据方式下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

SVG DOM常用属性和方法介绍

将以Adobe SVG Viewer提供的属性和方法为准,因为不同解析器对JavaScript以及相关的属性和方法支持的程度不同,有些方法和属性是某个解析器所特有的。SVG支持DOM2标准。 12.2.1 文档初始化相关evt属性evt表示事件本身,可以通过evt获取与当前事件相关的信息,用户可以在script中定义响应函数,进行相应的处理。它与普通Jav...

获取get值&amp;amp;DOM例题

获取get值:    <body>        <form action="9.26获取get值.html" method="get">            <input type="text" name="t1" />            <input type="text" name="t2" />...

原生JS获取HTML DOM元素的方法----------c

jQuery 事件方法https://www.cnblogs.com/yuanjili666/p/12425257.html JS获取DOM元素的方法(8种) 通过ID获取(getElementById) 通过name属性(getElementsByName) 通过标签名(getElementsByTagName) 通过类名(getElementsByC...

开发富文本编辑器的一些经验教训

此文已由作者刘诗川授权网易云社区发布。 欢迎访问网易云社区,了解更多网易技术产品运营经验。 最近我们的产品有一个需求是要在PC端做一个面向用户的书评编辑器,让用户和编辑在蜗牛读书上能方便快捷的编辑和产出一些优质的文章,它的主要难点就是富文本编辑器部分。 这虽然是个业务需求,但是做业务的同时也要兼顾技术,所以在跟需求商量好不支持IE8之后,决定采用Vue来作...

【使用 DOM】使用事件

1. 使用简单事件处理器 可以用几种不同的方式处理事件。最直接的方式是用事件属性创建一个简单事件处理器(simple event handler)。元素为它们支持的每一种事件都定义了一个事件属性。举个例子,onmouseover事件属性对应全局事件mouseover,后者会在用户把光标移动到元素占据的浏览器屏幕的上方时触发。(这是一种通用的模式:大多数事件...

client高性能组件化框架React简单介绍、特点、环境搭建及经常使用语法

【本文源址:http://blog.csdn.net/q1056843325/article/details/54729657 转载请加入该地址】 明天就是除夕了 预祝大家新春快乐 [ ]~( ̄▽ ̄)~* 天天饭局搞得我是身心疲惫= = 所以更新比較慢 今天想跟大家分享的就是这个大名鼎鼎的React框架 简单介绍 React是近两年非常流行的框架...