JS学习笔记(十三)事件

JS学习笔记(十三)事件

文章目录


       JS和HTML的交互是通过事件实现的,可以使用仅在事件发生时执行的监听器(处理程序)订阅事件。在传统软件工程领域,这个模型叫”观察者模式“,其能够做到也页面行为与页面展示的分离。

事件三要素:

  • 事件源:事件被触发的对象
  • 事件类型:如何触发什么事件(如:鼠标经过触发还是键盘按下触发)
  • 事件处理程序:通过一个函数赋值的方法完成

 

一、事件流

事件流描述了页面接收事件的顺序

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Document</title>
    </head>
    <body>
        <div id="myDiv">Click Me</div>
    </body>
</html>

 

1.1 事件冒泡

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

点击上面的civ后,click事件发生的顺序:

       

1.2 事件捕获

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

       点击上面的civ后,click事件发生的顺序:

       

1.3 DOM 事件流

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

       

二、事件处理程序(事件监听器)

事件处理程序的名字以on开头
       

2.1 HTML 事件处理程序(不建议使用)

       特定元素支持的每个事件都可以使用事件处理程序得到名字以HTML属性的形式来指定。

       注意: 因为属性的值是JS代码,所以不能在未转义的情况下使用HTML语句,如符号和好(&)、双引号、大小于号。为避免使用HTML实体,可以使用单引号代替双引号

<script>
    function showMessage() {
        console.log("Hello World!");
    }
</script>
<input type="button" value="Click me" onclick="showMessage()">

       以调用函数指定的事件处理函数首先会创建一个函数来封装属性的值。该函数有个特殊的局部变量event,其中保存的是event对象。动态创建的包装函数其作用域链被扩展了。document和元素自身的成员都可以被当成局部变量来访问。通过with实现,意味着事件处理程序可以更方便的访问自己的属性

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

       

2.1.1 HTML 事件处理程序的问题

  1. 时机问题

    有可能HTML元素已经显示在页面上,用户已经与其交互,而事件处理程序得代码还无法执行

  2. 对事件处理程序作用域链的扩展在不同浏览器中可能导致不同的结果

  3. HTML 和 JS 强耦合

       

2.2 DOM0 事件处理程序

       JS中指定事件处理程序得传统方法是:把一个函数赋值给(DOM元素)一个事件处理程序属性。 因为该方法简单,现在所有浏览器仍然支持此方法。

       要使用JS指定事件处理程序,必须先获得操作对象得引用。然后将事件处理程序属性赋值为一个函数

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

       事件处理程序会在元素的作用域里运行,即this等于元素。在事件处理程序里通过this可以访问元素的任何属性和方法。以这种方法添加事件处理程序是注册在事件流的冒泡阶段

       通过将事件处理程序属性设置为null,可以移除通过DOM0方式添加的事件处理程序。

       

2.3 DOM2 事件处理程序

1. addEventListener()和 removeEventListener()

       DOM2 为事件处理程序的赋值和移除添加了两个方法:addEventListener()和 removeEventListener()。接收3个参数:事件名、事件处理函数和一个布尔值。true表示在捕获阶段调用事件处理程序。false表示在冒泡阶段调用事件处理程序。

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

也可以把方法抽象出去

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

注意:

  1. 里面的事件类型必须写成字符串类型,一定要加引号,且不带on
  2. 同一个元素,同一个事件可以添加多个监听器

 

2. attachEvent 注册事件

ie9 以前支持

注意:

  • 里面的事件类型要带on,如:onclick

 

3. 注册事件兼容性解决方案

function addEventListener(element,eventName,fn) {
  if(element.addEventListener) {
    element.addEventListener(eventName,fn); //第三个参数默认false
  } else if(element.attachEvent) {
    element.attachEvent('on'+eventName,fn);
  } else {
    //相当于element.onclick = fn;
    element['on'+ eventName] = fn;
  }
}

       

2.4 IE 事件处理程序

       IE 实现了和DOM类似的方法,即attachEvent() 和 detachEvent()。这两个方法接收两个同样的参数:事件处理程序的名字和事件处理函数,使用attachEvent()添加的事件会添加到冒泡阶段

let btn = document.getElementById("myBtn");
btn.attachEvent("onclick",() => {
  console.log("clicked"));
});

注意:

  • attachEvent()的第一个参数是以on开头的事件名
  • 在IE中使用attachEvent()与使用DOM0的主要区别是事件处理程序的作用域。使用DOM0时,事件处理程序中的this等于目标元素。使用attachEvent()时,事件处理程序是在全局作用域进行的,即this等于windows
  • attachEvent()也可以添加多个事件处理程序,但事件处理程序会以添加他们的顺序反向触发。

       

2.5 跨浏览器事件处理程序

       为确保事件处理程序具有最大的兼容性,需要让代码在冒泡阶段运行

       为实现跨浏览器事件处理程序,需要创建 addHandler()。该方法根据需要分别使用DOM0、DOM2或IE方法添加事件处理程序。该方法会在**EventUtil()**对象上添加一个方法,以实现跨浏览器事件处理。添加的addHandler()接收3个参数:目标元素、事件名和事件处理程序

let btn = document.getElementById("myBtn");
let handler = function() {
  console.log("clicked");
}
EventUtil.addHandler(btn,"click",handler);

       addHandler() 和 removeHandler() 并没有解决所有跨浏览器一致性问题,比如IE的作用域问题、多个事件处理程序执行顺序问题

       

三、事件对象

       在DOM中发生事件时,所有相关信息都会被收集并存储在一个名为event的对象中,这个对象包括一些基本信息:如导致时间的元素,发生的事件类型以及可能与特定事件相关的任何其他数据
       

3.1 DOM 事件对象

       在DOM合规的浏览器中,event对象是传给事件处理程序的唯一参数。不管以哪种方法(DOM0 和 DOM2)指定事件处理程序,都会传入这个event对象

       事件包含的公共属性和方法:

 

(1)target 和 currentTarget

       在事件处理程序内部,this 对象始终等于 currentTarget 的值,而target只包含事件的实际目标。如果事件处理程序直接添加在了意图的目标,则this、currentTarget 和 target的值是一样的。

       若事件处理程序是添加到按钮的父节点上,那他们的值就不一样

let btn = document.getElementById("myBtn");
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
}

 

e.target和this的区别

区别:

  • e.target :点击了哪个元素就返回哪个元素
  • this :哪个元素绑定了事件,就返回哪个元素

 

(2)type属性

应用场景:处理程序处理多个事件

(3)preventDefault()

用于阻止特定事件的默认动作。比如链接的默认行为

(4)stopPropagation()

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

(5)eventPhase属性

用于确认事件流当前所处的阶段。

       

3.2 IE事件对象

       与DOM 事件不同,IE事件可以基于事件处理程序被指定的方式以不同的方法来访问。如果事件处理程序是使用DOM0方式指定的,则event对象只是window对象的一个属性。若事件处理程序是使用attachEvent()指定的,则event对象会作为唯一的参数传给处理函数,event对象仍然是window对象的属性。

       IE事件对象包含的公共属性和方法:

 
       事件处理程序的作用域取决于指定它的方式,因此this值并不总等于事件目标。因此,更好的是用事件对象的srcElement属性代替this

(1)returnValue

       等价于DOM的preventDefault(),用于取消给定事件默认的行为。returnValue = false;即设置阻止默认动作

(2)cancelBubble

       与DOM的stopPropogation()一样,都可以阻止事件冒泡,stopPropagation()即可取消捕获也取消冒泡

       

四、事件类型

DOM3 Event定义如下事件类型:

  • 用户界面事件(UIEvent)
  • 焦点事件(FocusEvent)
  • 鼠标事件(MouseEvent)
  • 滚轮事件(WheelEvent):使用鼠标滚轮是触发
  • 输入事件(InputEvent)
  • 键盘事件(KeyBoardEvent)
  • 合成事件(CompositionEvent):使用某种IME(输入法编辑器)输入字符时触发

       

4.1 用户界面事件

事件有:

  • DOMActive:元素被激活时触发,DOM3中被废除
  • load:在window上当页面加载完成后触发,在窗套(<frameset>)上当所有窗格(<frame>)都加载完成后触发,在<img>元素上当图片加载完成后触发,在<object>元素上当相应对象加载完成后触发。
  • unload:在window上当页面完全卸载后触发,在窗套上当所有窗格都卸载完成后触发,在<object>元素上当相应对象无法加载时触发。
  • abort:在<object>元素上当相应对象加载完成前被用户提前终止下载时触发
  • error
  • select:在文本框(input或textarea)上当用户选择了一个或多个字符时触发
  • resize:在window或窗格上当窗口或窗格被缩放时触发
  • srcoll

(1)load

1. 指定load事件的方法

       最常用的事件。load事件会在整个页面(包括所有外部资源)加载完后触发。有两种方式指定load事件:

  • JS方式(推荐使用)
window.addEventListener("load",(event)=>{
	...
})
  • <body>元素添加onload属性
<!DOCTYPE html>
<html lang="en">
<head>
  <title>Document</title>
</head>
<body onload="console.log('hhh')">
</body>
</html>

       

2. 会触发load事件的情况
  • 图片也会触发load事件,包括DOM中的图片和非DOM中的图片

给元素指定一个在加载完成后执行的事件处理程序:

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

注意:下载图片并不一定要把<img>元素添加到文档,只要给他设置src属性就会立即开始下载

  • <script>元素在 JS 文件加载完成后触发load事件,从而动态检测。
window.addEventListener("load",() => {
  let image = document.createElement("script");
  image.addEventListener("load", (event) => {
    console.log("loaded!");
  });
  script.src = "example.js";
  document.body.appendChild(script);
})

注意:与图片不同,要下载JS文件必须同时指定src属性并把<script>元素添加到文档中

  • IE 和 Opera 支持 <link>触发load事件

       

(2)unload 事件

       unload 与 load 事件相对,unload事件会在文档写在完成后触发。unload事件一般从一个页面导航到另一个页面触发,最常用于清理引用,以免内存泄漏。

       

4.2 焦点事件

       在元素获得或失去焦点时触发。这些事件可以与document.hasFocus() 和 document.activeElement 一起为开发者提供用户在页面中导航的信息。 有6种事件:

  • focus:元素获得焦点时触发。不冒泡,所有浏览器支持

  • blur:元素失去焦点时触发。不冒泡,所有浏览器支持

  • DOMFocusIn:元素获得焦点时触发。冒泡。DOM3废弃

  • DOMFocusOut:元素失去焦点时触发。冒泡,DOM3废弃

  • focusin:元素获得焦点时触发。冒泡

  • focusout:元素失去焦点时触发。冒泡

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

  1. focusout
  2. focusin
  3. blur
  4. DOMFocusOut
  5. focus
  6. DOMFocusIn

       

4.3 鼠标和滚轮事件

9种鼠标事件:

  • click:单击鼠标主键(通常左键)时或按键盘回车键触发
  • dblclick:双击鼠标主键(通常左键)时触发
  • mousedown:按下任意鼠标键触发,不能通过键盘触发
  • mouseup:用户释放鼠标键时触发
  • mouseenter:用户把鼠标光标从元素外部移动到元素内部触发。不冒泡,也不会在经过后代元素时触发
  • mouseleave:用户把鼠标光标从元素内部移动到元素外部触发。不冒泡,也不会在经过后代元素时触发
  • mousemove:在鼠标光标在元素上移动时反复触发,不能通过键盘触发,
  • mouseout:用户把鼠标光标从一个元素移动到另一个元素上时触发,移到的元素可以是原始元素的外部元素,也可以是原始元素的内部元素。不能通过键盘触发
  • mouseover:用户把鼠标光标从元素外部移动到元素内部触发。不能通过键盘触发

 
mousedown,mouseup,click和dblclick的触发顺序:

  1. mousedown
  2. mouseup
  3. click
  4. mousedown
  5. mouseup
  6. click
  7. dblclick

滚轮事件:

       只有mousewheel,反映鼠标滚轮或带滚轮的类似设备上滚轮的交互

       

1. 客户端坐标

       鼠标事件都是在浏览器视口中的某个位置发生的,这些信息被保存在event对象的clientX和clientY属性,表示事件发生时鼠标光标在视口中的坐标

       

2. 页面坐标

       事件发生时鼠标光标在页面上的坐标,pageX,pageY,在页面没有滚动时,pageX,pageY 和 clientX、clientY相同

       

3. 屏幕坐标

screenX 和 screenY

       

4. 修饰键

       修饰键:Shift、Ctrl、Alt、Meta 也经常用于修改鼠标事件的行为。DOM中修饰键对应的状态为:shiftKey、ctrlKey、altKey、metaKey,修饰键在被按下时其对应的状态为true

       

5. 相关元素

       对 mouseout 和 mouseover 而言,还存在与事件相关的其他元素。对mouseover来说,其目标是获得管的光标的元素,相关元素是失去光标的元素。对于mouseout来说,主要目标是失去光标的元素,相关元素是获得光标的元素。

       

6. 鼠标按键

       对 mousedown 和 mouseup 事件,event 对象上会有一个button属性,表示按下或释放的是哪个按键。DOM 为button属性定义了3个值:0表示鼠标主键、1表示鼠标中键、2表示鼠标右键

       

7. 额外事件信息

       DOM2 在event 对象上提供了detail属性,detail包含一个数值,表示在给定位置上发生了多少次单击。从1开始,若鼠标在mouseout 和 mouseup之间移动了,detail被重置为0

       

8. 触摸屏设备

触摸屏设备开发时需要注意:

  • 不支持dblclick事件。双击浏览器会放大,无法覆盖此行为
  • 单指点触屏幕上的可点击元素会触发mousemove事件,若操作导致内容变化,则不会再触发其他事件。若屏幕上没有变化,则会相继触发mousedown、mouseup 和 click 事件,点击不可点击元素不会触发事件
  • mousever事件也会触发mouseover和mouseout事件
  • 双指点触屏幕并华东导致页面滚动时会触发mouse wheel和scroll事件

 

9. 禁止鼠标选中文字

document.addEventListener("selectstart", (e) => {
    e.preventDefault();
})

 

10. mouseenter 和 mouseover 的区别(经典面试题)

  • mouseover鼠标经过自身盒子时会触发,经过子盒子还会触发,mouseenter只会经过自身盒子触发
  • mouseenter不冒泡,mouseover冒泡
           

4.4 键盘与输入事件

键盘事件

  • keydown:用户按下键盘上某个键时触发,且持续按住会重复触发
  • keypress:按下键盘上某个按键并产生字符时触发,持续按住会重复触发。DOM3 废弃,推荐textInput。textInput用于再文本显示给用户之前更方便的截获文本输入,在文本插入到文本框之前触发
  • keyup:释放键盘某个键时触发

       

1. 键码

       对于keydown 和 keyup,event对象的keyCode属性会保存一个键码,对应键盘上待定的一个键。

       

2. 字符编码

​        keypress事件时才会被设置值,为按键字符对应的ASCII编码

       

3. DOM3 的变化

       DOM3 Events并未规定charCode属性,而是定义了key和char两个新属性。其中key属性用于代替keyCode。

       DOM3 Events也支持location属性,是一个数值,表示在哪儿按的键。

       key、char、keyidentifier和location都缺乏浏览器支持,不建议使用

       

4. textInput事件

       DOM3新增的,textInput在字符被输入到可编辑区域时触发。与keypress的区别:

  • keypress会在任何可以获得焦点的元素上触发,textInput只在可编辑区域触发
  • textInput只在有新字符插入时才会触发,而keypress对任何可能影响文本的键都会触发,包括退格键

       

event.data

       textInput关注字符,所以event对象上提供了data属性,包含要插入的字符

       

event.inputMethod

       event对象上名为inputMethod的属性,表示向控件输入文本的手段:

  • 0:表示浏览器不能确定是什么输入手段
  • 1:表示键盘
  • 2:表示粘贴
  • 3:表示拖放操作
  • 4:表示IME
  • 5:表示表单选项
  • 6:表示手写
  • 7:表示语音
  • 8:表示组合方式
  • 9:表示脚本

       

4.5 合成事件

       DOM3 新增,用于处理通常使用IME(输入法编辑器)输入时的复杂输入序列。IME可以让用户输入物理键盘上没有的字符。IME通常需要同时按下多个键才能输入一个字符。合成事件用于检测和控制这种输入,有属性data:

  • compositionstart:在IME的文本合成系统打开时触发,表示输入即将开始,包含正在编辑的文本
  • compositionupdate:在新字符插入输入字段时触发,包含要插入的新字符
  • compositionend:在IME的文本合成系统关闭时触发,表示恢复正常键盘输入,包含本次合成过程输入的全部内容

       

4.6 HTML5事件

1. contentmenu事件

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

       contentmenu 事件冒泡, 因此只要给document指定一个事件处理程序就可以处理页面上的所有同类事件。通常自定义的上下文菜单都是通过contentmenu事件处理程序触发显示,并通过onclick事件处理程序触发隐藏的。

实现上下文菜单的基础代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Document</title>
</head>
<body>
  <div id="myDiv">hhh</div>
  <ul id="myMenu" style="position: absolute;visibility:hidden;background-color:silver">
    <li><a href="#">1</a></li>
    <li><a href="#">2</a></li>
    <li><a href="#">3</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";
  })
})

       

2. beforeunload事件

       beforeunload事件会在window上触发,用于给开发者提供阻止页面被卸载的机会。该事件在页面即将从浏览器中卸载时触发。若页面要继续使用,则可以不被卸载。该事件回向用户提示一个确认框,其中的信息表明浏览器即将卸载页面,请用户确认是否希望关闭页面。

       为显示确认框,需要将event.returnValue设置为要在确认框中显示的字符串,并将其作为函数值返回

window.addEventListener("beforeunload",(event) => {
  let message = "hhhhhhhhhhh";
  event.returnValue = message;
  return message;
})

       

3.DOMContentLoaded事件

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

​        window 添加事件处理程序(实际的事件目标时document,但会冒泡到window)

       

4. readystatechange事件

       用于提供文档或元素加载状态的信息。支持readystatechange事件的每个对象都有一个readyState属性, 该属性具有一个可以列出的可能的字符串值:

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

       

5. pageshow 和 pagehide事件

       Firefox 和 Opera 开发了往返缓存,旨在使用浏览器的前进和后退按钮时加快页面之间的切换。这个缓存不仅存储页面,也存储DOM 和 JS状态,实际把整个页面都保存在内存中。若页面在缓存中,那导航到该页面时不会触发load事件,但提供了一些事件暴露往返缓存的行为。

(1)pageshow

       在页面显示时触发,不论是否来自往返缓存。在新加载的页面上,pageshow会在load事件之后触发;在来自往返缓存的页面上,pageshow会在页面状态完全恢复后触发。

注意:虽然该事件的目标树document,但事件处理程序必须添加到window上

       

(2)pagehide

       在页面从浏览器中卸载后,在unload事件之前触发,事件处理程序也必须添加到window上

       pageshow 和 pagehide 都有属性 persisted页面存储了往返缓存就是true,否则为false对pageshow 来说,persisted 为true 表示页面时长往返缓存中加载的;对pagehide 来说,persisted 为 true 表示页面在卸载之后会被保存到往返缓存中。因此,第一次触发 pageshow 时 persisted 始终为false,第一次触发 pagehide 时 persisted 始终为 true。

       

6. haschange事件

       用于在URL散列值(URL最后#后面的部分)发生变化时通知开发者。因为开发者经常在Ajax应用中使用URL散列值存储状态信息或路由导航信息

       haschange 事件处理程序必须添加给window,event对象有两个属性:oldURL 和 newURL。用于分别保存变化前后的URL,且包含散列值的完整URL。

       

4.7 设备事件

用于确认用户使用设备的方式

1. orientationchange 事件

       苹果公式在Safari浏览器上创造了orientationchange 事件,以便开发者判断用户的设备是处于垂直模式还是水平模式。在window上暴露window.orientation属性,有3种值:

  • 0:垂直模式
  • 90:左转水平模式(主屏幕键在左侧)
  • -90:右转水平模式(主屏幕键在右侧)

       

2. deviceorientation事件

       若可以获取设备的加速计信息,且数据发生了变化,这个事件就会在window上触发。注意:deviceorientation事件只反应设备在空间中的朝向,而不涉及移动相关的信息

       当deviceorientation触发时,event对象会包含各个轴相对于设备静置时坐标值的变化,主要是:

  • alpha:0~360范围内的浮点值,表示围绕z轴转时y轴的度数
  • beta:-180~180范围内的浮点值,表示围绕x轴转时z轴的度数
  • gamma:-90~90范围内的浮点值,表示围绕y轴转时z轴的度数
  • absolute:布尔,表示设备是否返回绝对值
  • compassCalibrated:布尔,表示设备的指南针是否校准正确

 

3. devicemotion 事件

       用于提示设备实际上在移动,而不仅仅是改变了朝向。

       当devicemotion 事件触发时,event对象中包含如下额外的属性:

  • acceleration:对象,包含x,y和z属性,反映不考虑重力情况下各维度的加速信息
  • accelerationIncludingGravity:对象,包含x,y和z属性,反映考虑重力情况下各维度的加速信息
  • interval:毫秒,距离下次触发devicemotion 事件的时间。
  • rotationRate:对象,包含alpha、beta和gamma属性,表示设备朝向

       若无法提供acceleration、accelerationIncludingGravity 和 rotationRate信息,则属性值为null。为此,在使用这些属性前必须先要检测他们的值是否为null

       

4.8 触摸及手势事件

1. 触摸事件

       当手指放到屏幕上、在屏幕上滑动或从屏幕上拿开时,触摸事件触发,有以下几种:

  • touchstart:手指放到屏幕上时触发(即使有手指放到屏幕上了)
  • touchmove:手指在屏幕上滑动时连续触发,可用preventDefault()阻止滚动
  • touchend:手指从屏幕上移开时触发
  • touchcancel:系统停止跟踪触摸时触发。

       这些事件都会冒泡,也都可以被取消。每个触摸事件的event对象都提供了鼠标事件的公共属,除此之外还有:

  • touches:Touch对象数组,表示当前屏幕上的每个触电
  • targetTouches:Touch对象数组,表示特定于事件目标的触点
  • changedTouches:Touch对象数组,表示自上次用户动作后变化的触点

每个Touch对象的属性:

  • clientX
  • clientY
  • identifier:触点ID
  • pageX
  • pageY
  • screenX
  • screenY
  • target

       当手指点触屏幕上的元素时,依次会发生如下事件(包括鼠标事件):

  1. touchstart
  2. mouseover
  3. mousemove(1次)
  4. mousedown
  5. mouseup
  6. click
  7. touchend

       

2. 手势事件

       当两个手指触碰屏幕且相对距离或旋转角度变化时触发,有3种:

  • gesturestart:一个手指已经放在屏幕上,再把另一个手指放到屏幕上时触发
  • gesturechange:任何一个手指在屏幕上的位置发生变化时触发
  • gestureend:其中一个手指离开屏幕时触发

       只有在两个手指同时接触事件接收者时,这些事件才会触发。因为这些事件会冒泡,所以也可以把事件处理程序放到文档级别,从而处理所有手势事件

       每个手势事件的event对象都包含所有的鼠标事件属性。新增的两个event对象属性是:rotation 和 scale。rotation属性表示手指变化旋转的度数,负值表示逆时针旋转,正值表示顺时针旋转(从0开始)。scale属性表示两指之间距离变化的程度。开始为1,岁距离增大或缩小相应的增大或缩小

       

五、内存与性能

5.1 事件委托(重点)

       “过多事件处理程序”的解决方案:事件委托。事件委托利用事件冒泡,可以只使用一个事件处理程序来管理一类的事件。 如:click事件冒泡到document。以为着可以为整个页面指定一个onclick事件处理程序,而不用为每个可点击元素分别指定事件处理程序。

  <ul id="myLinks">
    <li id="go"><a href="#">1</a></li>
    <li id="hi"><a href="#">2</a></li>
    <li id="some"><a href="#">3</a></li>
  </ul>
let list = document.getElementById("myLinks");
list.addEventListener("click", (event) => {
  let target = event.target;

  switch(target.id) {
    case "go":
      document.title = 'hhhhhhh';
      break;

    case "hi":
      document.title = 'xixixii';
      break;

    case "some":
      location.href = "http://www.baidu.com";
      break;
  }
})

事件委托的优点:

  • document对象随时可用,意味着任何时候都可以给其添加事件处理程序(不用等待DOMContentLoaded 或 load事件)。以为着只要页面渲染出可点击元素,就可以无延迟的起作用
  • 节省话再设置页面事件处理程序上的时间。既节约DOM引用,又节约时间
  • 减少整个页面所需的内存,提升整体性能

       

5.2 删除事件处理程序

       很多Web应用性能不佳都是由于无用的事件处理程序常驻内存导致的。导致该问题的原因有:

  1. 删除带有事件处理程序的元素。 如:通过真正的DOM方法 removeChild()或replaceChild()删除节点。最常见的是innerHTML整体替换页面的某一部分。这时候被innerHTML删除的元素上如果有事件处理程序,就不会被垃圾收集程序正常清理

    <div id="myDiv">
        <input type="button" value="click me" id="myBtn">
    </div>
    <script>
        let btn = document.getElementById("myBtn");
        btn.onclick = function() {
            // 操作
    
            btn.onclick = null; //删除事件处理程序,一定要添加
            document.getElementById("myBtn").innerHTML = "hhhhhh...";
        }
    </script>
    

    单击按钮,会将自己删除并替换为一条信息,以阻止双击发生

  2. 页面卸载, 最好在onunloaded事件处理程序种趁页面尚未卸载时先删除所有的事件处理程序。

六、模拟事件

可以通过JS在任何时候触发任意事件,在测试时特别有用

6.1 DOM 事件模拟

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

  • “UIEvents”(DOM3是"UIEvent"):通用用户界面事件
  • “MouseEvents”(DOM3是"MouseEvents"):通用鼠标事件
  • “HTMLEvents”(DOM3没有):通用HTML事件

       事件模拟的最后一步是触发事件,使用 dispatchEvent(),接收一个参数,即表示要触发事件的event对象。 调用dispatchEvent()之后,事件就“转正”了,接着便冒泡并触发事件处理程序执行

1. 模拟鼠标事件

       调用createEvent()并传入“MouseEvents” 参数,返回一个event对象,该对象有**initMouseEvent()**方法,用于为新对象指定鼠标的特定信息。initMouseEvent()有15个参数:

  • type(字符串):要触发的事件类型,如:click
  • bubbles(布尔):事件是否冒泡。为精准模拟鼠标事件,应设置为true
  • cancelable(布尔):事件是否可用取消。为精准模拟鼠标事件,应设置为true
  • view:与事件关联的视图。基本始终是document.defaultView
  • detail(整数):关于事件的额外信息。只被事件处理程序使用,通常为0
  • screenX(整数):事件相对于屏幕的x坐标
  • screenY(整数):事件相对于屏幕的y坐标
  • clientX(整数):事件相对于视口的x坐标
  • clientY(整数):事件相对于视口的y坐标
  • ctrlkey(布尔):是否按下Ctrl键,默认为false
  • altkey(布尔):是否按下Atl键,默认为false
  • shiftkey(布尔):是否按下Shift键,默认为false
  • metakey(布尔):是否按下Meta键,默认为false
  • button(整数):表示按下了哪个按钮。默认为0
  • relatedTarget(对象):与事件相关的对象。只在mouseover 和 mouseout时使用

使用默认值模拟单击事件的例子:

let btn = document.getElementById("myBtn");
let event = document.createEvent("MouseEvents");
//初始化
event.initMouseEvent("click",true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);
//触发事件
btn.dispatchEvent(event);

       

2. 模拟键盘事件

       调用createEvent()并传入“KeyboardEvents” 参数,返回一个event对象,该对象有**initKeyboardEvent()**方法。initKeyboardEvent()参数:

  • type(字符串):要触发的事件类型,如:click
  • bubbles(布尔):事件是否冒泡。为精准模拟鼠标事件,应设置为true
  • cancelable(布尔):事件是否可用取消。为精准模拟鼠标事件,应设置为true
  • view:与事件关联的视图。基本始终是document.defaultView
  • key(字符串):按下按键的字符串代码
  • location(整数):按下按钮的位置。0为默认键,1表示左边,2表示右边,3表示数字键盘,4表示移动设备(虚拟键盘),5表示游戏手柄
  • modifiers(字符串):空格分隔的修饰键列表,如:“shift”
  • repeat(整数):连续按了这个键多少次

注意:DOM3 废除了keypress事件,因此只能用上述方法模拟keydown和keyup事件

       Firefox 允许给createEvent()传入"KeyEvents"来创建,返回的对象包含initKeyEvent(),参数:

  • type(字符串):要触发的事件类型,如:click
  • bubbles(布尔):事件是否冒泡。为精准模拟鼠标事件,应设置为true
  • cancelable(布尔):事件是否可用取消。为精准模拟鼠标事件,应设置为true
  • view:与事件关联的视图。基本始终是document.defaultView
  • ctrlkey(布尔):是否按下Ctrl键,默认为false
  • altkey(布尔):是否按下Atl键,默认为false
  • shiftkey(布尔):是否按下Shift键,默认为false
  • metakey(布尔):是否按下Meta键,默认为false
  • keyCode(整数):表示按下或释放键的键码,keydown和keyup中使用。默认为0
  • charCode(整数):表示按下键对应字符的ASCII编码,在keypress中使用。默认为0

       

3. 模拟其他事件

       模拟HTML事件需要调用createEvent()并传入“HTMLEvents” 参数,返回一个event对象,该对象有initEvent() 方法

       

4. 自定义DOM事件

       自定义事件不会触发原生的DOM事件。创建自定义事件,需要调用 createEvent(“CustomEvent”)。返回对象包括initCustomEvent()方法,接收4个参数:

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

       

6.2 IE事件模拟

       使用 document 的 createEventObject()来创建对象,与DOM不同,该方法不接受参数,返回一个通用的 event 对象,然后,手工给返回的对象指定希望该对象具备的所有属性。(没有初始化方法)。 最后在事件目标上调用 fireEvent() 方法,该方法接收两个参数:事件处理程序的名字和event对象。调用fireEvent()时, srcElement 和type属性会自动指派到event对象(其他属性必须手工指定)

模拟click事件:

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

event.screenX =100;
event.screenY =0;
event.clientX =0;
event.clientY =0;
event.ctrlkey =false;
event.altkey =false;
event.shiftkey =false;
event.button =0;

btn.fireEvent("onclick",event);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值