JavaScript学习笔记(十五) 事件模型

0、DOM 标准

在开始学习 JavaScript 事件模型前,我们首先来了解一下什么是 DOM(Document Object Model)

简单来说,DOM 是 W3C 定义的访问 HTML 和 XML 文档的标准

按照不同的发展阶段,分为不同的级别,分别是 DOM0、DOM1、DOM2、DOM3

DOM0、DOM2、DOM3 都有定义与事件相关的内容,但是 DOM1 没有定义与事件相关的内容

1、事件模型

(1)事件捕获

事件从文档对象上开始,然后往下传递,直到目标对象(从父到子),低版本浏览器不支持事件捕获

<!DOCTYPE html>
<html>
<head>
    <title>事件捕获</title>
</head>
<body>
    <ul>
        <li>Apple</li>
        <li>Banana</li>
        <li>Cherry</li>
    </ul>
</body>
<script>
    let html = document.documentElement
    html.addEventListener('click', () => { console.log('html') }, true)
    let body = document.body
    body.addEventListener('click', () => { console.log('body') }, true)
    let uls = document.getElementsByTagName('ul')
    for (let ul of uls) { ul.addEventListener('click', () => { console.log('ul') }, true) }
    let lis = document.getElementsByTagName('li')
    for (let li of lis) { li.addEventListener('click', () => { console.log('li') }, true) }
    // 点击列表项,打印结果为:html body ul li
</script>
</html>

(2)事件冒泡

事件从目标对象上开始,然后往上传递,直到文档对象(从子到父),所有的浏览器都支持事件冒泡

<!DOCTYPE html>
<html>
<head>
    <title>事件冒泡</title>
</head>
<body>
    <ul>
        <li>Apple</li>
        <li>Banana</li>
        <li>Cherry</li>
    </ul>
</body>
<script>
    let html = document.documentElement
    html.addEventListener('click', () => { console.log('html') }, false)
    let body = document.body
    body.addEventListener('click', () => { console.log('body') }, false)
    let uls = document.getElementsByTagName('ul')
    for (let ul of uls) { ul.addEventListener('click', () => { console.log('ul') }, false) }
    let lis = document.getElementsByTagName('li')
    for (let li of lis) { li.addEventListener('click', () => { console.log('li') }, false) }
    // 点击列表项,打印结果为:li ul body html
</script>
</html>

(3)事件流模型

DOM2 定义了事件流模型,这是目前广泛使用的 JavaScript 事件模型,规定事件传递先捕获后冒泡

<!DOCTYPE html>
<html>
<head>
    <title>事件流模型</title>
</head>
<body>
    <ul>
        <li>Apple</li>
        <li>Banana</li>
        <li>Cherry</li>
    </ul>
</body>
<script>
    let html = document.documentElement
    html.addEventListener('click', () => { console.log('Chtml') }, true)
    html.addEventListener('click', () => { console.log('Bhtml') }, false)
    let body = document.body
    body.addEventListener('click', () => { console.log('Cbody') }, true)
    body.addEventListener('click', () => { console.log('Bbody') }, false)
    let uls = document.getElementsByTagName('ul')
    for (let ul of uls) { ul.addEventListener('click', () => { console.log('Cul') }, true) }
    for (let ul of uls) { ul.addEventListener('click', () => { console.log('Bul') }, false) }
    let lis = document.getElementsByTagName('li')
    for (let li of lis) { li.addEventListener('click', () => { console.log('Cli') }, true) }
    for (let li of lis) { li.addEventListener('click', () => { console.log('Bli') }, false) }
    // 点击列表项,打印结果为:Chtml Cbody Cul Cli Bli Bul Bbody Bhtml
</script>
</html>

2、事件处理程序

(1)DOM0 事件处理程序

通过事件监听函数指定事件处理程序,事件处理程序在冒泡阶段执行

<button id="submit">提交</button>
<script>
    var button = document.getElementById('submit')
    // 对于 DOM0 事件处理函数,this 指向目标对象,这里 this 指向 button
    var handleEvent = function(e) { console.log(this) }
    // 添加事件处理函数 button.onclick = handleEvent
    // 删除事件处理函数 button.onclick = null
    button.onclick = handleEvent
</script>

DOM0 事件处理程序,同一个事件只能绑定一个事件处理函数,后面绑定的处理函数会覆盖前面绑定的处理函数

<button id="submit">提交</button>
<script>
    var button = document.getElementById('submit')
    var sayHello = function(e) { console.log('Hello') }
    var sayGoodbye = function(e) { console.log('Goodbye') }
    button.onclick = sayHello
    button.onclick = sayGoodbye
    // 只会打印 Goodbye
</script>

(2)DOM2 事件处理程序

通过 addEventListener() 添加事件处理程序,通过 removeEventListener() 删除事件处理程序

它们都接收三个参数,分别是事件名称、事件处理函数以及一个布尔类型的值,这个布尔值默认为 false

如果布尔值为 false,则在冒泡阶段执行处理函数,如果布尔值为 true,则在捕获阶段执行处理函数

<button id="submit">提交</button>
<script>
    var button = document.getElementById('submit')
    // 对于 DOM2 事件处理函数,this 指向目标对象,这里 this 指向 button
    var handleEvent = function(e) { console.log(this) }
    // 添加事件处理函数 button.addEventListener('click', handleEvent)
    // 删除事件处理函数 button.removeEventListener('click', handleEvent)
    button.addEventListener('click', handleEvent)
</script>

DOM2 事件处理程序,同一个事件可以绑定多个事件处理函数,先绑定先执行

<button id="submit">提交</button>
<script>
    var button = document.getElementById('submit')
    var sayHello = function(e) { console.log('Hello') }
    var sayGoodbye = function(e) { console.log('Goodbye') }
    button.addEventListener('click', sayHello)
    button.addEventListener('click', sayGoodbye)
    // 先打印 Hello,再打印 Goodbye
</script>

(3)低版本 IE 事件处理程序(IE9 之前)

通过 attachEvent() 添加事件处理程序,通过 detachEvent() 删除事件处理程序

它们都接收两个参数,分别是事件监听函数名称以及事件处理函数,将在冒泡阶段执行处理函数

<button id="submit">提交</button>
<script>
    var button = document.getElementById('submit')
    // 对于低版本 IE 事件处理函数,this 指向全局对象,这里 this 指向 window
    var handleEvent = function() { console.log(this) }
    // 添加事件处理函数 button.attachEvent('onclick', handleEvent)
    // 删除事件处理函数 button.detachEvent('onclick', handleEvent)
    button.attachEvent('onclick', handleEvent)
</script>

低版本 IE 事件处理程序,同一个事件可以绑定多个事件处理函数,先绑定后执行

<button id="submit">提交</button>
<script>
    var button = document.getElementById('submit')
    var sayHello = function() { console.log('Hello') }
    var sayGoodbye = function() { console.log('Goodbye') }
    button.attachEvent('onclick', sayHello)
    button.attachEvent('onclick', sayGoodbye)
    // 先打印 Goodbye,再打印 Hello
</script>

3、事件类型

HTML 与 JavaScript 通过事件进行交互,常见的事件如下:

(1)鼠标事件

  • mousedown:在按下鼠标按键时触发
  • mouseup:在松开鼠标按键时触发
  • click:在点击鼠标时触发
  • dblclick:在双击鼠标时触发
  • mouseenter:在鼠标移入特定范围时触发
  • mouseleave:在鼠标移出特定范围时触发
  • mousemove:鼠标在特定范围内移动时触发
  • mouseover:鼠标移到某元素上触发
  • mouseout:鼠标从某元素移开触发

(2)键盘事件

  • keydown:在按下键盘按键时触发
  • keyup:在松开键盘按键时触发
  • keypress:在按住键盘按键时触发

(3)UI 事件

  • load:在文档或图像加载完成后触发
  • unload:在文档或图像销毁完成后触发
  • error:加载文档或图像时发生错误
  • abort:加载文档或图像时出现中断
  • scroll:在滚动滚动条时触发
  • resize:调整窗口大小时触发

(4)焦点事件

  • focus:在元素获得焦点时触发,事件不冒泡
  • blur:在元素失去焦点时触发,事件不冒泡

(5)表单事件

  • select:在被选定时触发
  • change:在被修改时触发
  • submit:在被提交时触发

4、事件对象

当一个事件被触发时,会产生一个事件对象,这个事件对象会隐式传入事件处理函数

因此,我们可以在事件处理函数中通过事件对象的属性和方法获取事件的相关信息

(1)事件对象的常用属性

  • type:事件名称
  • target:触发事件的目标元素
  • currentTarget:触发事件的当前元素
  • bubbles:事件是否为冒泡类型
  • cancelBubble:是否取消冒泡行为
  • cancelable:是否能调用 preventDefault() 方法取消默认行为
  • defaultPrevented:是否有调用 preventDefault() 方法
  • eventPhase:事件传播的阶段
  • timeStamp:触发事件的时间
  • clientX:鼠标指针相对于浏览器页面的水平坐标
  • clientY:鼠标指针相对于浏览器页面的垂直坐标
  • screenX:鼠标指针相对于屏幕的水平坐标
  • screenY:鼠标指针相对于屏幕的垂直坐标
  • shiftKey:“SHIFT” 键是否被按下
  • ctrlKey:“CTRL” 键是否被按下
  • altKey:“ALT” 键是否被按下
  • metaKey:“meta” 键是否被按下

(2)事件对象的常用方法

  • preventDefault:阻止默认行为
  • stopPropagation:阻止事件传播

【 阅读更多 JavaScript 系列文章,请看 JavaScript学习笔记

posted @ 2020-04-03 16:24  半虹  阅读(232)  评论(0编辑  收藏  举报