JavaScript用户事件

526 阅读6分钟

发展

事件监听 定义了部分JavaScript与网页元素的关系,但是元素被加载和卸载并不会自动添加和回收监听器,所以JavaScript程序员需要

  1. 注册事件
  2. 在视图卸载之前移出监听,防止残留内存

JavaScript与HTML的交互是通过事件实现的,事件代表文档DOM或浏览器窗口BOM中某个有意义的动作。抽象来看,这运用了软件工程的一种设计模型-观察者模型

  • 事件最早在IE3和Netscape Navigator 2出现,当时的目标是把某些表单处理工作从服务器转移到浏览器上。
  • 点击button,也意味着点击button的容器、整个页面...,事件流描述了页面接受事件的顺序
  • IE8是最后一个使用专有事件系统的主流浏览器
  • DOM2开始标准化DOM事件API——DOM2 Event,目前所有浏览器基本都实现了DOM2的核心内容
  • BOM和DOM都有事件,HTML5致力于明确BOM与DOM的关系
  • DOM3又新增了一系列事件

DOM2 Event规定事件流分为3个阶段,event.eventPhase数字标记:事件捕获1、到达目标2、事件冒泡3

创建事件处理程序(监听器)

  1. 特定元素支持的事件,可以用HTML属性的形式指定处理程序,例如button的onclick。处理程序中可以通过this访问元素【不推荐:JavaScript与HTML强耦合】
<button onclick="console.log(&quto;转义双引号&quto;)"/>
  1. DOM0:使用JavaScript获得元素,然后赋值来注册监听。btn.onclick=null移出监听
  2. DOM2:addEventListener(事件名,处理程序,是否在捕获阶段调用)、removeEventListener传入与前者相同的参数即可移除监听【匿名函数作为事件处理程序时候,无法移除监听】【拦截事件:将处理程序注册到捕获阶段】
  3. IE:【只支持冒泡阶段】attachEvent(事件名,处理程序)、detachEvent
  4. addEventListener函数的第三个参数可以是布尔值,也可以是对象-拥有下列属性:
  • capture:  Boolean 表示 listener 会在该类型的事件捕获阶段传播到该 EventTarget 时触发。
  • once: Boolean 表示 listener 在添加之后最多只调用一次。如果是 true, listener 会在其被调用之后自动移除。
  • passive: Boolean 设置为true时,表示 listener 永远不会调用 preventDefault()。如果 listener 仍然调用了这个函数,客户端将会忽略它并抛出一个控制台警告。

使用元素属性赋值注册监听的方式btn.onclick,有缺点即事件目标对每种事件只有一种处理程序。然而使用addEventListener,不会重写之前的注册程序,同时存在,按注册顺序调用

事件对象

  • Firefox/Google:在DOM中发生事件,生成一个event对象
  • Opera/IE:event是全局变量,window.event 注意:IE中事件发生的对象是window.event.srcElement
    对象包含了一些基本信息:导致事件的元素,事件的类型、以及相关数据(鼠标点击位置、按键...)

所有事件对象都包括以下公共属性(只读)和方法(只读):

  • currentTarget 处理程序所在元素 处理程序内部,this的值
  • target事件目标(绑定事件那个dom)
  • bubbles 是否冒泡
  • cancelable 是否可以取消默认行为
  • defaultPrevented 是否已经调用了preventDefault(DOM3新增)
  • eventPhase 调用事件处理程序的阶段:1 捕获;2 处于阶段;3 冒泡阶段
  • detail 整数类型 事件相关的其他信息
  • view 与事件关联的抽象视图,==发生事件的window对象,类型是AbstractView
  • trusted true表明是系统的即浏览器生成的,false为开发人员JavaScript自定义的(DOM3新增)
  • type 事件类型,例如click、mouseover等一个处理程序处理多种事件,case语句分情况
  • preventDefault() 取消事件默认行为,cancelable是true时可以使用【特定事件的默认行为,e.g:链接被单击时候导航到href指定的URL】
  • stopPropagation() 取消事件流的后续捕获/冒泡,bubbles为true才能使用
  • stopImmediatePropagation() 阻止该事件目标执行别的注册事件(DOM3新增)

区别target与currentTarget:

<body  onclick="处理事件“>
    <button>
    </button>
</body>

处理程序中:
this== currentTarget即处理程序所属的元素
target==button

事件

DOM3事件

DOM3定义了如下事件:

  1. 用户界面事件UIEvent:与BOM交互的通用浏览器事件

  2. 焦点事件FocusEvent:获取或失去焦点

  3. 鼠标事件MouseEvent:使用鼠标在页面上执行某些操作

  4. 滚轮事件WheelEvent:使用鼠标滚轮或类似设备

  5. 输入事件InputEvent:

  6. 键盘事件KeyboardEvent

  7. 合成事件CompositionEvent:使用某种IME(输入法编辑器)输入字符时触发

  8. 用户界面HTMLEvents一般dom事件

  9. 变化事件 ~~MutationEvents,一般化dom变动 ~~Deprecated

用户界面事件HTMLEvent

DOMActivate

  • load:window【页面的外部资源加载完成、对应body元素】、frameset、img元素上存在,元素加载完成后触发\
  • unload:同load,卸载触发,一般用于清理内存
  • abort:加载完成前被用户提前终止下载时触发
  • resize窗口或者窗格被缩放时触发
  • scroll用户滚动包含滚动条的元素时

img即使不添加到DOM,只要给它设置了src属性就会立即开始下载

状态变化事件

  • DOM树构建完成后立即触发DOMContentLoaded事件,不用等图片、
  • JavaScript文件、CSS文件或其他资源文件。
  • 不支持DOMContentLoaded事件的,用超时为0的setTimeout()函数来设置处理程序。
  • 其他外部资源加载成功之后,触发window的load事件。
  • 支持readystatechange事件的每个对象都有一个readyState属性,属性值可能是uninitialized、loading、loaded、interactive、complete.

焦点事件

blur:失去焦点触发,不冒泡 focus focusin:冒泡般

鼠标和滚轮

  • mousewheel:用户使用滚轮会在任何元素上触发wheelDelta+-120
  • click:单击鼠标主键或是键盘回车
  • dbclick:双击
  • mousedown:任意鼠标键
  • mouseup:释放鼠标键触发
  • mouseover:从元素外部到元素内部
  • mouseenter:鼠标光标从元素外移到内
  • mouseleave:
  • mousemove:元素上移动时反复触发
  • mouseout:从一个元素A到另一个B,在A触发,B是相关元素relatedTarget

事件之间存在包含关系,所以规定双击的触发顺序是

  1. mousedown
  2. mouseup
  3. click//触发依赖前两,如果前两个事件被取消就不触发
  4. mousedown
  5. mouseup
  6. click
  7. dbclick

修饰键 shift、ctrl、alt、meta,DOM规定了四个属性,用布尔值来标记修饰键状态,

if(event.shiftKey){
	keys.push("shift");
}

键盘与输入

  • keydown:长按重复触发
  • keypress:产生字符后,长按重复触发
  • keyup
  • event.keyCode=键码

合成事件

处理IME输入时的复杂输入序列,IME可以让用户输入物理键盘上没有的字符
compositionstart、compositionupdate 、compositionend

除了浏览器定义的常见用户事件,也支持程序员自定义合成事件

let stEvent = new Event('start');
const onStart = function(event){
// 自定义
}
// 注册监听
document.addEventListener('start', onStart);
// 触发
document.dispatchEvent(stEvent);

// 事件监听会占用内存
document.removeEventListener('start', onStart);

HTML5事件

  • contextmenu
  • beforeunload
  • DOMContentLoaded
  • windows是右击鼠标,mac单击+ctrl
<!DOCTYPE html>
<html>
    <head>
        <title>ContextMenu Event</title>
        <script>
            window.addEventListener("load",(event)=> {//页面加载之后注册监听
                let div=document.getElementById("my");
                div.addEventListener("contextmenu",(event)=>{//展示菜单
                    event.preventDefault();
                    let menu=document.getElementById("menu");
                    menu.style.left=event.clientX+"px";
                    menu.style.top=event.clientY+"px";
                    menu.style.visibility="visible";
                });
                document.addEventListener("click",(event)=>{//随便点击页面的部分
                    document.getElementById("menu").style.visibility="hidden";
                });
            });
        </script>
    </head>
    <body>
        <div id="my">任何位置,右击鼠标或ctrl+单击显示菜单栏</div>
        <ul id="menu" style="position:absolute;visibility:hidden;">
            <li>1</li>
            <li>1</li>
            <li>1</li>
        </ul>
    </body>
</html>

模拟事件

事件除了用户交互或浏览器功能触发,通过JavaScript也可以模拟事件发生

// 创建
let myEvent = document.createEvent('MouseEvents');
// 初始化 事件对象
myEvent.initMouseEvent('click',true,true,document.defaultView,0,0...);
// 触发事件
btn.dispatchEvent(myEvent);