JS 学习笔记 | 事件处理

1.事件概述

1.1 什么是事件

事件是可以被 JS 检测到的行为,实质上是一种交互操作。
例如:我们可以给某按钮添加一个 onclick (点击)事件,当用户点击时触发某个函数。

1.2 事件的作用

  • 各个元素之间可以借助事件来进行交互
  • 用户和页面之间也可以通过事件来交互
  • 后端和页面之间也可以通过事件来交互(减轻服务器压力)

注意:事件通常会与函数进行配合,当事件发生了函数才会执行,事件的本质就是一次交互操作。

1.3 事件传递

JS 中规定:
事件不仅能够和触发者交互,还会在特定情况下沿着 dom tree 逐级传递,和 dom tree 中的各个节点进行交互。而 JS 中的这种机制被称为事件传递机制。

事件交互的两种方式:

  • 事件冒泡:
    事件从最具体的元素开始,沿着 DOM 树逐级向上依次触发,直至最不具体的元素停止。
    <div>
        <button>点我</button>
    </div>
    
    var div = document.querySelector("div");
    var button = document.querySelector("button");
    button.onclick = function() {
        alert("按钮被点击了!");
    }
    div.onclick = function() {
        alert("div 被点击了!");
    }
    
    因为 div 包含了 button,所以 button 在 DOM 树中是 div 的子节点,所以点击按钮会向上冒泡,先是 button 触发了事件,紧接着是 div 触发了事件。
  • 事件捕获:
    事件从最不具体的元素开始,沿着 DOM 树逐级向下依次触发,直至最具体的元素停止。
    <div>
        <button>点我</button>
    </div>
    
    var div = document.querySelector("div");
    var button = document.querySelector("button");
    div.addEventListener("click", function() {
        alert("div 被点击了");
    }, true);
    button.addEventListener("click", function() {
        alert("button 被点击了");
    }, true);
    
    将第三个参数设置为 true,这样点击 button 时就会触发事件捕获,先是 div 触发事件,紧接着 button 触发事件。

在这里插入图片描述

由图可知捕获过程要先于冒泡过程
W3C 规定:事件冒泡 + 事件捕获 + 事件真正的触发者等各个分支构成了 JS 的事件机制。
注意:如果没有特殊情况,均采用事件冒泡

2.非 IE 浏览器中的 事件绑定

2.1 HTML 事件

绑定操作发生在 HTML 代码中的事件,称为 HTML 事件。
语法:

on + 事件 = 函数();函数();函数();...

例如:

<div class="d1" onclick="test1();test2()">
    <div class="d2" onclick="test2()"></div>
</div>

var div1 = document.querySelector(".div1");
var div2 = document.querySelector(".div2");

function test1() {
    console.log("这是第一个函数");
}

function test2() {
    console.log("这是第二个函数");
}

在上述 HTML 代码中,分别给 d1 和 d2 绑定了效果不同的 HTML 事件。
注意

  • HTML 事件采用冒泡机制来处理事件。即 点击 d2 时会先执行 d2 的绑定事件(test2()函数),然后采用事件冒泡将事件传递给上一级 DOM 节点(d1),然后 d1 执行自己的绑定事件。
  • 函数执行的顺序按照绑定事件时函数的顺序为准。

2.1.1 移除 HTML 事件的方式

语法:

元素.setAttribute("on+事件名", null);

例如:

button.setAttribute("onclick", null);

2.1.2 HTML 事件的缺陷

  • 耦合性太强,修改一处另一处也要修改。
  • 当函数没有加载成功时,用户去触发事件就会报错。

2.2 DOM 0级事件

在 JS 脚本中,直接通过 on+事件名 方式绑定的事件称为是 DOM0 级事件。
语法:

元素.on+事件名 = function() {需要执行的语句}

例如:

button.onclick = function() {
    console.log("按钮被点击了");
}

注意:以冒泡机制来处理事件,不存在兼容问题。

2.2.1 DOM0 级事件移除方式

语法:

元素.on+事件名 = null;

例如:

button.onclick = null;

2.2.2 DOM0 级事件的缺陷

一次只能绑定一个触发函数,如果同时绑定多个触发函数,则以最后一个为准。

2.3 DOM 2级事件

在 JS 脚本中,通过 addEventListener 函数绑定的事件被称为 DOM2级事件。
语法:

元素.addEventListener(type, listener, useCapture);
  • type:事件类型(没有 on
  • listener:监听函数,绑定的函数
  • useCapture:是否使用捕获机制。如果不写,默认值为 false
    注意:DOM2 级事件可以绑定多个函数,执行顺序按照函数熟悉的顺序。

例如:

var button = document.querySelector("button");
button.addEventListener("click", function() {
    console.log(11);
}, true);

button.addEventListener("click", function() {
    console.log(22);
}, true);

上述代码表示给按钮添加了两个 DOM2 级点击事件,事件传递采用事件捕获的方式。

2.3.1 DOM2 级事件移除方式

语法:

node.removeEventListener(type, 外部函数名, useCapture);

例如:

var button = document.querySelector("button");
button.addEventListener("click", clickEvent, false);

button.removeEventListener("click", clickEvent, false);

function clickEvent() {
    console.log(22);
}

注意:DOM2 级事件中如果绑定函数为匿名函数则无法解除。能够删除的只能是外部函数,并且移除时的参数要与添加时的参数完全一致。

3.IE 浏览器中的 事件绑定

HTML 事件处理程序 等同于非 IE
DOM0 级事件 等同于非 IE

  • DOM2 级事件
    在 JS 脚本中,通过 attachEvent 函数绑定事件
    语法:

    元素.attachEvent(type, listener);
    
    • type:事件类型(有 on
    • listener:监听函数,绑定的函数

    注意:如果绑定多个函数,按照函数书写的倒序执行。

    例如:

    var div1 = document.querySelector(".d1");
    var div2 = document.querySelector(".d2");
    
    div1.attachEvent("onclick", test1);
    div2.attachEvent("onclick", test1);
    

    不支持 IE11。

3.1 移除 DOM2 级事件

语法:

元素.detachEvent(type, listener);

例如

div1.detachEvent("onclick", test1);
div2.detachEvent("onclick", test1);

4.解决浏览器中事件绑定的兼容性问题

由于 IE 浏览器的事件绑定和 非 IE 浏览器的事件绑定方式方法都有所不同,所以单一的某种函数都不能完美解决不同浏览器下的方法绑定问题。
那么我们又应该如何面对在不同浏览器下 事件绑定 这个问题呢?

4.1 解决方案的思路

  • 绑定事件时:
    如果能使用 addEventListener 方法绑定的,就采用本方法,否则使用 attachEvent 方法绑定。
  • 解绑事件时:
    如果能采用 addEventListener 方法绑定的,就使用 removeEventListener 方法解绑,否则采用 detachEvent 方法解绑。
var div = document.querySelector("div");
var superEvent = {
    // 添加事件的兼容性函数
    add: function addEvent(ele, type, func) {
        if (ele.addEventListener) {  // 判断在哪个环境下
            ele.addEventListener(type, func);
        } else {
            ele.attachEvent("on" + type, func);
        }
    },
    // 移除事件的兼容性函数
    remove: function removeEvent(ele, type, func) {
        if (ele.addEventListener) {  // 判断在哪个环境下
            ele.removeEventListener(type, func);
        } else {
            ele.detachEvent("on" + type, func);
        }
    }
};

function func() {
    console.log(11);
}

superEvent.add(div, "click", func);
superEvent.remove(div, "click", func)

5.鼠标事件

语法:

元素.on+鼠标事件名 = 调用函数

例如:

diiv.ondbclick = function() {
    console.log("这是 div");
}

注意

  • DOM0 级事件可以给一个元素绑定多个不同类型的事件。
  • 事件之间互不影响。
  • 默认是冒泡事件

5.1 click 单击时触发

var div = document.querySelector("div");
// 单击事件
div.onclick = function() {
    console.log("div 被点击了");
}

5.2 dbclick 双击时触发

// 双击事件
div.ondblclick = function() {
    console.log("div 被双击了");
}

5.3 mousedown 按下时触发

// 鼠标按下事件
div.onmousedown = function() {
    console.log("鼠标按下了");
}`

5.4 mouseup 抬起时触发

// 鼠标抬起事件
div.onmouseup = function() {
    console.log("鼠标抬起了");
}

5.5 mousemove 移动时触发

// 鼠标在 div 中移动了
div.onmousemove = function() {
    console.log("鼠标在 div 中移动了");
}

5.6 mouseenter(不冒泡)移入时触发

div2.onmouseenter = function() {
    console.log("鼠标移入了div2 中")
}

5.7 mouseleave(不冒泡)移出时触发

div2.onmouseleave = function() {
    console.log("鼠标移出了 div2 ")
}

5.8 mouseover(冒泡)移入时触发

div1.onmouseover = function () {
    console.log("鼠标移入了 div1 中")
}

5.9 mouseout(冒泡)移出时触发

div1.onmouseout = function () {
    console.log("鼠标移出了 div1 ")
}

5.10 鼠标事件总结

  • 鼠标的基本事件默认采用冒泡传递
  • 可以给一个元素添加多个不同的鼠标事件,不同的鼠标事件之间互不影响。
  • mouseentermouseleave 这两个事件不冒泡。

6.文档事件

文档事件中主要是指添加给整个文档的事件。在这一类事件中,绝大部分不需要用户去主动进行调用。而是通过文档的不同状态来进行自动执行。

6.1 加载成功\失败事件

  • load:该事件是指节点加载成功时自动发生回调事件
  • error:该事件是指节点加载失败时自动发生的回调事件

语法:

node.onload = func(){};

例如:
加载页面中的图片,如果加载成功,会回调 onload 方法,如果加载失败会回调 onerror 方法。

<img src="images/11.jpg" alt="">
<script>
    document.querySelector("img").onload = function() {
        console.log("图片加载成功!");
    }

    document.querySelector("img").onerror = function() {
        console.log("图片加载失败");
    }
</script>

6.2 当 DOM 加载完成时触发事件

  • DOMContentLoaded:该事件和 load 事件触发的时机不一样,先触发 DOMContentLoaded 事件,后触发 load 事件。

    DOM 文档加载步骤:

    • 解析 HTML 结构
    • 加载外部脚本和样式表文件
    • 解析并执行脚本代码
    • DOM 树构建完成 // DOMContentLoaded 执行
    • 加载图片等外部文件
    • 页面加载完成 // load 执行

    从 DOM 文件的加载步骤可以看出,样式文件的加载会阻塞脚本的执行
    如果把内部的 <script> 标签放到 <link> 标签的后面,如果页面没有解析完成,那么脚本则不会触发,必须要等到样式文件加载完成之后,这种情况被称为文件阻塞

6.3 页面(文档)发生卸载时触发的事件

  • beforeunload:页面卸载时触发这个事件(页面刷新和页面关闭),通常情况下配合 event.returnValue 使用。
    一般情况下都是直接添加到 body 上面。而如果没有在 body 上添加本事件,则需要在 window 上添加。
    window.onbeforeunload = function() {
        event。returnValue = "";
        return "信息已修改,是否确认离开";
    }
    
    注意beforeunload 事件中弹出的对话框一般情况下是不允许用户做出修改的。只能采用默认的对话框。而且在 beforeunload 所关联的回调函数中也是不支持 alert 弹出框的。

6.4 文档加载状态判断事件

  • readystatechange:当文档的 readyState 改变时触发这个事件(仅第二阶段)。
    document 节点中拥有一个属性叫做 readyState,其拥有 3 个可能值:

    • loading:加载 DOM 中
    • interactive:加载外部资源
    • complete:加载完成

    readystatechange 事件正是在这个状态发生改变时调用的事件。
    调用的方式可以使用 DOM0 或者 DOM2 来绑定。

    例子:

    console.log(document.readyState);
    
    // 文档加载状态变化
    document.addEventListener("readystatechange", function() {
        console.log("文档加载状态变化" + document.readyState);
    })
    
    // 文档 DOM 树加载完成
    document.addEventListener("DOMContentLoaded", function() {
        console.log("文档 DOM 树加载完成");
        
    })
    
    // 页面彻底加载完成
    window.onload = function() {
        console.log("页面彻底加载完成");
    }
    
    document.querySelector("img").onload = function() {
        console.log("图片加载完成");
    }
    

    运行结果:


    在这里插入图片描述

6.5 文档大小发生改变时的回调事件

  • resize:该事件是在文档大小发生改变时回调,但是因为 JS 追求变化的敏感度,将 resize 事件设置成了 0,也就是说每次文档大小发生改变都会立即调用本事件。由此造成了 一次变化,多次 resize

    window.onresize = function() {
        console.log("clientX: " + document.documentElement.clientWidth);
        console.log("clientY: " + document.documentElement.clientHeight);
    }
    

    解决方式:采用延迟写法来实现。

    var flag = false;
    function frame() {
        if (flag) {
            console.log("clientWidth: " + document.documentElement.clientWidth);
            console.log("clientHeight: " + document.documentElement.clientHeight);
        }
        flag = false;
        setTimeout(function() {
            flag = true;
        }, 500);
    }
    
    window.onresize = function() {
        frame();
    }
    

7.焦点事件

焦点:当前正在和用户发生交互的节点被称作焦点。

7.1 失去焦点事件 blur

语法:获得焦点和失去焦点事件既可以使用 DOM0 绑定也可以使用 DOM2 绑定。

var input = document.querySelector("input");
// DOM0 方式绑定
input.addEventListener("blur", function() {
    console.log("输入框失去了焦点");
})
// DOM2 方式绑定
input.onblur = function() {
    console.log("输入框失去了焦点");
}

7.2 获取焦点事件 focus

语法:

var input = document.querySelector("input");
// DOM0 方式绑定
input.addEventListener("focus", function() {
    console.log("输入框获取了焦点");
})
// DOM2 方式绑定
input.onfocus = function() {
    console.log("输入框获取了焦点");
}

注意:这两个事件均 不支持 事件冒泡(只有当前节点发生调用)。如果需要连续多次的触发,则需要使用 DOM2 级绑定事件中的捕获事件来达到。

8.文档滚动事件

scroll 事件会在 文档 或 元素 发生滚动时触发

文档发生滚动时:
属性 scrollTop\scrollLeft 表示文档滚动的距离(没有单位)

  • IE:document.documentElement.scrollTop\Left
  • 非 IE:document.body.scrollTop\Left

可以使用 document.body.scrollTop || document.documentElement.scrollTop 来解决兼容性。

例如:

var button = document.querySelector("button");
button.onclick = function() {
    document.body.scrollTop = 1000;
    document.documentElement.scrollTop = 1000;
}
document.onscroll = function() {
    // 滚动事件调用一次就输出一次滚动距离
    console.log(document.body.scrollTop || document.documentElement.scrollTop);
}

9.元素滚动事件

元素发生滚动时并不存在兼容性的问题,但是需要有一个前提:必须存在滚动条(元素的滚动条属性可以通过 overflow: scroll / overflow-x: scroll / overflow-y: scroll 来实现)。

当元素发生滚动时,可以通过 元素.scrollTop / scrollLeft 获取到元素的位移距离。

例如:

<style>
    div {
        overflow: scroll;
        width: 100px;
        height: 100px;
        background-color: skyblue;
    }
</style>

<script>
    var div = document.querySelector("div");
    div.onscroll = function() {
        console.log("top " + div.scrollTop + " left" + div.scrollLeft);
    }
</script>

注意:內容要占满 div 的空间。

10.键盘事件

10.1 键盘事件种类

键盘事件是指当用户在操作键盘的时候会被自动触发的事件,通常有以下三种:

  • keydown:用户按下任意键都可以触发这个事件。如果按住不放,事件会被连续触发
  • keypress:用户按下任意键都可以触发这个事件(功能键除外)。如果按住不放,事件会被连续触发。
  • keyup:用户释放按键时触发。
// keydown 事件
var input = document.querySelector("input");
input.onkeydown = function() {
    console.log("键盘被按下了");
}

// keypress 事件
input.onkeypress = function() {
    console.log("键盘被按下了");
}

// keyup 事件
input.onkeyup = function() {
    console.log("按键被松开了");
}

注意:键盘事件一般绑定在需要用户输入的元素上(例如:input),但是由于键盘事件默认采用冒泡机制,因此将键盘事件直接绑定在 body 之上也是允许的。

10.2 键盘事件中提供的属性

在键盘事件中可以通过 event.keycode 来获取按下的按键的编码值。

例如:

// 该方式不区分大小写
input.onkeydown = function() {
    console.log("down " + event.keyCode);
}

// 该方式区分大小写
input.onkeypress = function() {
    console.log("down " + event.keyCode);
}

10.3 对比 keydown 和 keypress 事件

  • keypress 主要用来捕获 数字(包括 shift + 数字的符号)、字母(包括大小写)、先键盘等能够显示在屏幕中的字符。但是不能对系统功能键(例如:退格)进行正常的响应。
    keydownkeyup 通常可以捕获键盘除了 PrScrn 之外所有按键(这里不讨论特殊键盘的特殊键)。
  • 捕获字符长度有区别
    ·keypress 只能捕获单个字符。
    keydownkeyup可以捕获组合键。
  • 捕获字符大小写识别区别
    keypress 可以捕获单个字符的大小写。
    keydownkeyup 对于单个字符捕获的 keyCode 都是一个值,也就不能判断单个字符的大小写。
  • 捕获字符数字区别
    keypress 不区分小键盘和主键盘的数字字符。
    keydownkeyup 区分小键盘和主键盘的数字字符。
  • 特殊情况
    • PrScrn 按键的 keypresskeydownkeyup 都不能捕获。
    • 上下左右等功能键的 keydownkeyup 都能获取 keyCode,并且值相等。

常见的键盘按键编码:


在这里插入图片描述

11.触摸事件

11.1 手机触摸事件

  • touchstart:当手指触摸屏幕时触发,即使有一个手指放在屏幕上也会触发
  • touchmove:当手指在屏幕上滑动时连续触发。
  • touchend:当手指在屏幕上移开时触发。
  • touchcancel:当系统停止跟踪触摸时触发。(如电话接入或弹出信息,一般在这个操作中来做一些暂停游戏类的操作)。

例如:

var div = document.querySelector("div");
div.addEventListener("touchstart", function() {
    console.log("touch begin");
})

div.addEventListener("touchmove", function() {
    console.log("touch move");
})

div.addEventListener("touchend", function() {
    console.log("touch end");
})

div.addEventListener("touchcancel", function() {
    console.log("touch cancel");
})

注意

  • 除非特殊说明,否则事件均为冒泡事件。
  • 手机触摸事件必须使用 dom2 来进行绑定。
  • 可以给一个元素添加多个触摸事件。

11.2 事件对象的属性

事件对象:即 事件触发时 用来保存 事件相关的所有信息的对象
注意:事件对象基本都是系统为我们自动生成的,不必手动创建。

div.addEventListener("touchstart", function() {
    console.log(event);
})
  • touches:表示当前跟踪的触摸操作的 Touch 对象的数组(当前屏幕上所有的触摸点列表)。
    • 触摸对象,即 事件对象的 touches 属性 中的每一个元素。一次触摸会创建一个触摸对象
      触摸对象中提供了很多属性方便我们获取和使用:

      • clientX:触摸目标在视口中的 X 坐标。
      • clientY:触摸目标在视口中的 Y 坐标。
      • identifier:表示触摸的唯一 id。
      • pageX:触摸目标在页面中的 x 坐标。
      • pageY:触摸目标在页面中的 y 坐标。
      • screenX:触摸目标在屏幕中的 x 坐标。
      • screenY:触摸目标在屏幕中的 y 坐标。
      • target:触摸的 DOM 节点坐标。

      通常都会在触摸事件被触发的时候,通过这两个属性获取当前节点的位置。

  • targetTouches:特定于事件目标的 Touch 对象的数组(当前对象上所有的触摸点列表)。
  • changeTouches:表示自上次触摸以来发生了什么改变的 Touche 对象数组(涉及当前事件的触摸点列表)。

12.this 对象

this 代表 函数运行时 自动生成的 一个 用来指代函数调用者 的对象, this 只能在函数内部使用

例子:

var div = document.querySelector("div");
function test() {
    console.log(this);
}
test(); // 指向 window
document.addEventListener("click", test);   // 指向 document
div.addEventListener("click", test);    // 指向 div

根本原则:谁是调用者,this 就指向谁。

13.HTML event 事件应用

13.1 非 IE 下的 event 对象

13.1.1 event 对象及获取 event 对象的方法

当 DOM tree 中某个事件被触发的时候,会同时自动产生一个用来描述事件所有的相关信息(比如发出事件的元素、或者是事件的类型)的对象,这个对象就是 event (事件对象)。

获取方式:

  • 直接通过 event 获取
  • 通过函数传参数的形式来使用,一般而言我们使用 形参e 或者 eve 来代替。
    var div = document.querySelector(".d1");
    // div.onclick = function(e) {
    //     console.log(e);
    // };
    
    // div.onmouseenter = function(eve) {
    //     console.log(eve);
    // }
    
    div.onclick = function() {
        console.log(event);
    }
    

13.1.2 event 中常用的属性和方法

因为 event 对象是用来描述 发生的事件的信息 的,而 event 对象当中所提供的一系列属性和方法正是用来获取这些信息的途径。

  • type 属性
    type 属性用来获得 当前触发事件 的类型,此属性只读

    var div = document.querySelector(".d1");
    div.onclick = function(e) {
        console.log(e.type);    // 依赖于事件触发而存在,是只读属性
    };
    
  • bubbles 属性
    bubbles 属性用来获得 当前触发事件 的类型是否冒泡。如果冒泡则返回 true,否则返回 false

    div.onmouseenter = function(eve) {
        console.log(eve.bubbles);
    }
    
  • stopPropagation()
    该方法用于阻止事件从当前节点传播到下一个节点。
    语法:

    event.stopPropagation();
    

    例如:

    var div = document.querySelector(".d1");
    div.onclick = function(e) {
        // 阻止事件的传播
        e.stopPropagation();
    };
    
    document.body.onclick = function() {
        // 如果不添加 stopPropagation() 将会被打印
        console.log("body 受到监听");   
    }
    

    注意:该方法只是阻止了事件的传播,但是并不会影响同一节点上的其它句柄。

  • preventDefault()
    event 对象中提供了一个名为 preventDefault 的方法,用来取消当前节点的默认行为(例如超链接的点击跳转行为),该方法没有返回值。

    语法:

    <a href="http://www.baidu.com">百度</a>
    <script>
        var aLink = document.querySelector("a");
        aLink.onclick = function() {
            event.preventDefault(); // 添加后不会跳转
        }
    </script>
    
  • cancelable()
    event 对象中提供了一个名为 cancelable 的属性,用来判断当前节点能否使用 preventDefault() 来取消默认行为,如果可以则返回 true,否则会返回 false

    var aLink = document.querySelector("a");
    aLink.onclick = function() {
        console.log(event.cancelable);
    }
    

13.2 非 IE 下的 event 对象属性

13.2.1 eventPhase 属性

eventPhase:事件传导至 当前节点 时处于什么状态。

  • 1:事件处于捕获状态
  • 2:事件处于真正的触发者
  • 3:事件处于冒泡状态

注意:该返回值是 只读 状态。

事件捕获:

var div = document.querySelector("div");
var span = document.querySelector("span");

span.addEventListener("click", function() {
    console.log("span: " + event.eventPhase);
})

div.addEventListener("click", function() {
    console.log("div: " + event.eventPhase);
}, true);

document.body.addEventListener("click", function() {
    console.log("body: " + event.eventPhase);
}, true);

document.addEventListener("click", function() {
    console.log("document: " + event.eventPhase);
}, true);

事件冒泡:

var div = document.querySelector("div");

div.addEventListener("click", function() {
    console.log("div: " + event.eventPhase);
});

document.body.addEventListener("click", function() {
    console.log("body: " + event.eventPhase);
});

document.addEventListener("click", function() {
    console.log("document: " + event.eventPhase);
});

13.2.2 target 属性与 currentTarget 属性

  • target:返回事件真正的触发者,和 this 基本相同,只不过 this 返回的是调用者。
  • currentTarget:返回事件的监听者(触发的事件绑定到了哪个节点,就返回谁)。

例如:

<div class="d1">
    d1
    <div class="d2">d2</div>
</div>
<script>
    var d1 = document.querySelector(".d1");
    d1.onclick = function() {
        console.log(event.target);
        console.log(event.currentTarget);
    }
</script>

13.3 IE 中的 event 对象

13.3.1 IE 中的 event 对象与非 IE 下的区别

  • 非 IE 下 event 的值默认为 undefined,而 IE中 event 的值默认为 null
  • 非 IE 下可以随意通过 DOM0 或 DOM2 中的参数来使用 event,而 IE 中 DOM0 无法使用传参的方式来使用 event

注意:因为 event 本身是归属于 window 的一个属性,因此我们可以在函数中通过 var eve = e || window.event来解决获取 event 的兼容性问题。

13.3.2 IE 中的 event 对象的常用属性和方法

由于 IE 下存在某些属性的赋值方式和非 IE 中略有不同,因此在这里单独说明一下。

  • secElement
    srcElement 属性代表事件真正的触发者,等同于非 IE 下的 target 属性。
    因此,为了在不同的浏览器下解决获取 target 的兼容性问题,可以采取如下写法:
    var target = event.target || eve.srcElement;
    
  • cancelBubble
    cancelBubble 属性用来阻止事件在当前节点上的冒泡行为。
    作用类似于非 IE 下的 stopPropagation()
    语法:
    event.cancelBubble = true;// 可取消冒泡
    event.cancelBubble = false; // 默认值
    
    注意stopPropagation() 方法用于阻止事件传递,而 cancelBubble 属性则仅阻断事件冒泡。
  • returnValue
    returnValue 属性用来设置 书否取消当前节点的默认行为
    作用类似非 IE 下的 proventDefault()
    语法:
    e.returnValue = false;  // 取消默认行为
    e.returnValue = true;   // 默认值
    

14.事件委托

事件委托是给父元素绑定事件,用来监听子元素的冒泡事件,并能找到是哪个子元素的事件。

例子:

<ul>
    <li>li 1</li>
    <li>li 2</li>
    <li>li 3</li>
    <li>li 4</li>
</ul>

var ul = document.querySelector("ul");
ul.onclick = function() {   // 为父元素绑定事件,监听子元素的冒泡 
    console.log(event.target.innerHTML);
}

15.三级联动

  • select 元素的 option 创建方式 var option = new Option("显示的內容");
  • select 元素添加 option 元素,select.options.add(新建的 option);
  • select 元素清空 option 的方式:select.options.length = 0;
  • select 元素改变时触发的事件:select.onchange = function() {}
  • select 元素当前正选中的 option 序号 select.selectedIndex,序号从 0 开始。

例子(不完整):

<span>省:</span>
<select id="province">
    <option>-请选择-</option>
</select>
<span>市:</span>
<select id="city">
    <option>-请选择-</option>
</select>
<span>区:</span>
<select id="district">
    <option>-请选择-</option>
</select>
<script>
    var province = document.querySelector("#province");
    var city = document.querySelector("#city");
    var district = document.querySelector("#district");
    var provinceIndex = 0;
    // var option = new Option("山西省");
    // province.options.add(option);
    var provinceArr = ["山西省", "辽宁省", "福建省"];
    var cityArr = [
        ["太原市", "临汾市", "大同市", "运城市", "长治市"], 
        ["沈阳市", "大连市", "鞍山市", "阜新市"], 
        ["福州市", "厦门市", "三明市", "莆田市", "泉州市", "龙岩市"]
    ];
    var districtArr = [
        [["太原 1 区", "太原 2 区", "太原 3 区"], ["临汾 1 区", "临汾 2 区", "临汾 3 区"], ["大同 1 区", "大同 2 区"]],
        [["沈阳 1 区", "沈阳 2 区"], ["大连 1 区", "大连 2 区"]],
        [["福州 1 区", "福州 2 区",], ["厦门 1 区", "厦门 2 区"]]
    ];

    for (var i = 0; i < provinceArr.length; i++) {
        var provinceOpt = new Option(provinceArr[i]);
        province.options.add(provinceOpt);
    }
    
    province.onchange = function(eve) {
        provinceIndex = eve.target.selectedIndex - 1;
        if (provinceIndex == -1) {
            city.options.length = 0;
            district.options.length = 0;
        } else {
            city.options.length = 0;
            // 根据省的序号加载市的內容
            for (var i = 0; i < cityArr[provinceIndex].length; i++) {
                var cityOpt = new Option(cityArr[provinceIndex][i]);
                city.options.add(cityOpt);
            }
            // 加载所选省的市的第一个区(默认)
            district.options.length = 0;
            for (var i = 0; i < districtArr[provinceIndex][0].length; i++) {
                var districtOpt = new Option(districtArr[provinceIndex][0][i]);
                district.options.add(districtOpt);
            }
        }
    }

    city.onchange = function(eve) {
        var cityIndex = eve.target.selectedIndex;
        district.options.length = 0;
        for (var i = 0; i < cityArr[cityIndex].length; i++) {
            var districtOpt = new Option(districtArr[provinceIndex][cityIndex][i]);
            district.options.add(districtOpt);
        }
    }
</script>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343