第十七章:事件处理

事件处理概述

        客户端JavaScript程序(浏览器)采用了异步事件驱动编程模型(我的理解是交互驱动当文档、 浏览器、元素或与之相关的对象发生某些有趣的事情时,Web浏览器就会产生事件(event)。如果JavaScript应用程序关注特定类型的事件,那么它可以注册当这类事件发生时要调用的一个或多个函数。这种风格并非Web编程独有,所有使用图形用户界面的应用程序都采用了它。

        一些重要的定义:

        1⃣️ 事件类型(event type):是一个用来说明发生什么类型事件的字符串。例如,“mouse-move”表示用户移动鼠标,“keydown”表示键盘上某个键被按下。事件类型只是一个字符串,有时候又称之为事件名字(event name)

         2⃣️ 事件目标(event target) :是 发生事件或与之相关的对象 Window、 Document和Element对象是最常见的事件目标 。当然,AJAX中的XMLHttpRequest对象也是一个事件目标;
         3⃣️ 事件处理程序(event handler) :是 处理或响应事件的函数,它也叫 件监听程序(event listener) 。应用程序通过指明事件类型和事件目标,在Web浏览器中注册它们的事件处理函数。
         4⃣️ 事件对象(event object) :是 与特定事件相关且包含有关该事件详细信息的对象 。事件对象作为参数传递给事件处理函数(但是在IE8以及其之前版本中,全局变量event才是事件对象)。事件对象都有用来指定事件类型(event type)的type属性和指定事件目标(event target)的target属性 (但是在IE8以及其之前版本中,用的是srcElement而非target)。当然,不同类型的事件还会为其相关事件对象定义一些其他的独有属性。例如,鼠标事件的相关对象会包
含鼠标指针的坐标,而键盘事件的相关对象会包含按下的键和辅助键的详细信息。
         5⃣️ 事件传播(event propagation) :如果在一个web页面上用鼠标点击一个元素a的某一子元素b时,应该先执行子元素b注册的事件处理程序还是先执行元素a注册的事件处理程序呢(假设元素a和它的子元素b都有注册事件处理程序)?

        当一个事件发生时,它会先从浏览器顶级对象Window一路向下传递,一直传递到触发这个事件的那个元素,这也就是事件捕获(event capturing)。然而,一切并没有结束,事件又从这个元素一路向上传递到Window对象,这也就是事件冒泡(event bubble)过程(但是在IE8以及其之前版本中,事件模型并未定义捕获过程,只有冒泡过程)。

        关于上面的问题,还得看元素a注册的事件处理程序是在捕获过程还是在冒泡过程了。
 

事件的分类

         1⃣️ 依赖于设备的输入事件 :mousedown/mouseover/keydown等;
        2⃣️ 独立于设备的输入事件 :click(指激活了链接、按钮或其他文档元素,可用鼠标也可用键盘回车键等)
         3⃣️ 用户界面事件 :change/focuse/submit(用户点击表单中提交后触发);
         4⃣️ 状态变化事件 :load/readystatechange;
        5⃣️ 特定API事件 :HTML5中定义的包括dragstart/dragenter以及<video><audio>相关事件;
         6⃣️ 计算器和错误处理程序
 

传统事件类型

         1⃣️ 表单事件
         当提交和重置表单时,<form>元素会分别出发 submit reset 事件,当用户和类按钮表单元素交互时,它们会发生 click 事件,用户通过输入文字、选择选项或选择复选框来改变相应表单元素状态时,这些元素会发生 change 事件(对于文本域只有用户和表单完成交互并通过Tab键或单击方式移动焦点时才会触发),表单某元素得到或失去焦点时触发 focus blur 事件;
         2⃣️ Window事件
        Window事件指: 事件发生于浏览器窗口本身而非窗口中显示的任何特定文档相关内容。
        load事件 :当文档和其所有外部资源完全加载并显示给用户时就会触发它。
        unload事件 :当用户离开当前文档转向其他文档时会触发它。
        onerror事件 :当Javascript出错时会触发。
         resize scroll 事件 :用户调整浏览器窗口大小或滚动它时会触发。
        
        3⃣️ 鼠标事件
        鼠标事件在鼠标指针所对应的最深嵌套元素上触发,但它们会冒泡直到文档最顶层。 clientX clientY 属性指定了鼠标在窗口坐标中的位置。 button which 属性指定了按下的鼠标键是哪个。 当键盘辅助键按下时,对应的属性 altKey/ctrlKey/metaKey shifKey 会设置为true。对于click事件, detail 属性指定了其是单击、双击还是三击。
        其他鼠标事件的触发:
  • mousemove事件:用户每次移动或拖动鼠标时触发 (发生很频繁)。
        用户鼠标左键一次操作可能发生的事件执行的事件过程: mousedown -> mouseup -> click -> dbclick。
        右键鼠标会出发contextmenu事件(浏览器弹出菜单),可以取消该事件来组织默认的弹出菜单操作。
         4⃣️ 键盘事件
        包括keydown / keyup / keypress等,原理与鼠标事件类似。
 

JavaScript中常用的事件类型

        上面笔记中提到的传统事件类型都是web应用中最常用的,它们已经存在了很长时间并得到了广泛的支持。下面综合一下如今几种常用的事件类型:

        1⃣️ UI事件

        UI事件指的是那些  不一定与用户操作有关 的事件。DOM规范中向后兼容。
        UI事件包含:
  • load:当页面加载后在window上面触发,当所有框架加载完成后在框架上触发,当图像加载完成后在<img>元素上面触发。
  • unload:当页面卸载后在window上面触发。
  • abort:当用户停止下载过程时,如果嵌入的内容没有加载完,则在<object>元素上触发。
  • error:当发生JavaScript错误时在window上面触发。
  • select:当用户选择文本框(input或textarea)或一个字符串时触发。
  • resize:当窗口或框架大小变化时在window上面触发。
  • scroll:当用户滚动滚动条的元素中的内容时,在元素上触发。
        这些事件多数与window对象有关。
load事件
        JavaScript中最常用的就是load 。当页面加载完成时(图像加载完成、JavaScript外部资源加载完成、css外部资源加载完成)在window上面触发。定义load事件有两种方法:
        第一种就是用JavaScript定义:         
EventUtil.addHandler(window, "load", function (event) {
    alert("load");
}); //load事件
        第二种方法就是在HTML的<body>中定义:
<body load="alert('load');">
<!-- Html代码 -->
</body>

        建议尽可能使用JavaScript代码来定义load事件。

unload事件

        只要文档被卸载后就会触发,当用户从一个页面切换到另一个页面就会触发,一般用于清除引用,避免内存泄露使用。定义unload事件也有两种方式,与定义load事件一样。
resize事件
        resize事件是当窗口或框架的尺寸大小发生变化时触发,这个事件是在window上触发的。建议使用JavaScript定义onresize事件处理程序。也有两种定义方法。
EventUtil.addHandler(window, "resize", function (event) {
    alert("resize");
}); /resize事件
        该事件会在窗口大小不断变化时重复触发,因此建议代码简单点。
scroll事件
        定义方法与load、unload、resize一样,也是两种即: 在HTML中定义或用JavaScript定义 ,建议用JavaScript定义。scroll是在window对象上发生的,但它实际上是反应了相应元素的变化。这个事件会在文档被滚动期间重复被触发,所以应当尽量保持事件处理程序的代码简单。
 

        2⃣️ 焦点事件

        焦点会在页面得到焦点或失去焦点时触发
  • focus,在得到焦点的元素上触发,这个事件不会冒泡。
  • focusIn,在得到焦点的元素上触发 ,这个事件会冒泡。
  • DOMFocusIn,在得到焦点的元素上触发,这个事件会冒泡。
  • DOMFocusOut,在失去焦点的元素上触发。
  • blur,在失去焦点的元素上触发,这个事件不会冒泡。
  • focusout,在失去焦点的元素上触发,这个事件会冒泡。
        例如:当input元素获取焦点时,会触发focus事件。
let input1 = document.getElementById("input1");
input1.onfocus = function (event) {
    alert("hi"); //hi
};
        当input元素失去焦点时,会触发blur事件。
let input1 = document.getElementById("input1");
input1.onblur = function (event) {
    alert("失去焦点"); //失去焦点
};

        3⃣️ 鼠标与滚轮事件

        常见的鼠标事件:
  • click:鼠标单击事件,当单击鼠标(一般为左键)或按下回车键时,会触发事件。
  • dbclick:鼠标双击事件,当双击鼠标时,会触发事件。
  • mousedown:当任意按下鼠标键时,会触发事件。
  • mouseup:当释放鼠标铵键时,会触发事件。
  • mouseover:当鼠标移动进到当前元素的区域就会触发事件。
  • mouseout:当鼠标移出当前元素的区域就会触发事件。
  • mousemove:当鼠标在当前元素区域内不断移动时,会重复触发事件。
        当按下鼠标按键时:
let input1 = document.getElementById("input1");
input1.onmousedown = function (event) {
    alert("按下鼠标按键");
};

当释放鼠标按键时:

let input1 = document.getElementById("input1");
input1.onmouseup = function (event) {
    alert("释放鼠标按键");
};

当单击鼠标按键时:

let input1 = document.getElementById("input1");
input1.onclick = function (event) {
    alert("点击鼠标按键");
};

当双击鼠标按键时:

let input1 = document.getElementById("input1");
input1.ondbclick = function (event) {
    alert("双击鼠标按键");
};
客户区坐标位置
        鼠标事件都是在浏览器视口中特定位置发生的,这些位置信息保存在对象的 clientX和clientY属性中,这两个属性分别表示鼠标在视口中水平位置和垂直位置
        注:这两个值不包括页面滚动的距离,也就是说,这两个值不包括鼠标在页面中的位置,只是表示在视口中的某位置发生了事件。
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>JavaScript</title>
    </head>
    <body>
        <input id="input1" type="button" value="单击事件">
        <script>
            let input1 = document.getElementById("input1");
            //客户区坐标,不包括页面滚动的距离
            input1.onclick = function (event) {
            alert("clientX:" + event.clientX + " clientY:" + event.clientY);
            };
        </script>
    </body>
</html>
页面坐标位置
        客户区坐标位置只是表示鼠标在视口的某位置发生了事件,而想要表示鼠标在页面中的某个位置发生了事件,则用 pageX和pageY表示鼠标在页面中的水平位置和垂直位置
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>JavaScript</title>
    </head>
    <body>
        <input id="input1" type="button" value="单击事件">
        <script>
            let input1 = document.getElementById("input1");
            //页面坐标位置,包括了页面滚动的距离
            input1.onclick = function (event) {
            alert("pageX:" + event.pageX + " pageY:" + event.pageY);
            };
        </script>
    </body>
</html>
视口位置与页面位置的区别:
        视口位置不包括页面滚动的距离,也就是说当页面出现有滚动条时,即使在视口的同一位置点击相同的元素,视口位置与页面位置所返回的值是不同的。
        视口位置是从视口区的顶端即最后一工具栏下和浏览器左端开始计算的,即使水平方向和垂直方向上出现了滚动条,也是从视口的顶端和浏览器的左边作为起始坐标计算的。而页面位置则从页面的最顶端和页面的最左边开始计算的,即使有了滚动条也是。
屏幕坐标位置
        鼠标除了有相对于浏览器窗口的位置,还有相对于屏幕的位置,即 screenX与screenY
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>JavaScript</title>
    </head>
    <body>
        <input type="button"><br>
        <input type="button"><br>
        <input type="button"><br>
        <input type="button"><br>
        <input id="input1" type="button" value="单击事件">
        <script>
            let input1 = document.getElementById("input1");
            //屏幕坐标
            input1.onclick = function (event) {
            alert("screenX:" + event.screenX + " screenY:" + event.screenY);
            };
        </script>
    </body>
</html>

        即使鼠标在同一点击事件,clientY与screenY的值是不同的,screenY的值大一些,这是因为浏览器的菜单栏与工具栏要占一定的空间。

修改键
        鼠标事件主要是由鼠标触发的,但有时有些按键也会影响到鼠标事件的操作,这些键叫做 修改键 。修改键有: Shift、Ctrl、Alt和Meta (windows下是Windows键,苹果下是Cmd键),DOM为此定义了四个属性,表示这四个键的状态: shiftKey、CtrlKey、altKey和metaKey 。如果在鼠标触发事件的同时,也按下了这四个修改中的其中一个或多个,其状态属性返回true。
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>JavaScript</title>
    </head>
    <body>
        <input id="input1" type="button" value="单击事件">
        <script>
            let input1 = document.getElementById("input1");
            input1.onclick = function (event) {
            alert("修改键");
            //定义一个Array类,用于保存用户触发了的修改键。
            let keys = new Array();
            //判断在按下鼠标键的同时,是否也按下了其它的修改键,如果按下了,
            //将相应修改键的名称推入数组。
            if (event.shiftKey) {
                keys.push("shifKey");
                }
            if (event.ctrlKey) {
                keys.push("ctrl");
                }
            if (event.altKey) {
                keys.push("altKey");
                }
            //最后将数组中的值用join()方法以字符串的形式用逗号隔开。
            alert("keys:" + keys.join(","));
            };
        </script>
    </body>
</html>
鼠标的按钮
        在鼠标事件中,有 mousedown和mouseup 两个事件,分别表示鼠标键被按下和鼠标键被释放。这两个事件的event对象有一个叫 botton 的属性,该属性记录了触发mousedown和mouseup事件时,用户所按下的鼠标的按键状态。
        我们知道,鼠标主要有三个按键,分别是 主按键、中间按键、次按键 。botton属性所记录的就是这三个按键的状态。 在DOM的botton属性中,当botton返回0时,表示用户按下的是鼠标的主按键,返回1时,表示用户按下的是鼠标的中间按键(也就滑轮),返回2时,表示用户按下的是鼠标的次按键。

         注:鼠标默认的按键是最左边的为主按键,中间的滑轮为中间按键,最右边的为次按键,当然,用户可以自定义设置这三个按键。

<!doctype html>
<html lang="zh">
    <head>
        <meta charset="utf-8">
        <title>JavaScript</title>
    </head>
    <body>
        <input id="input1" type="button" value="单击事件">
        <script>
            let input1 = document.getElementById("input1");
            input1.onmousedown = function (event) {
            console.log("button属性");

            //定义一个Array类,用于保存用户触发了的修改键。
            let keys = new Array();
            //判断在按下鼠标键的同时,是否也按下了其它的修改键,
            //如果按下了,将相应修改键的名称推入数组。
            if (event.shiftKey) {
                keys.push("shif");
                }
            if (event.ctrlKey) {
                keys.push("ctrl");
                }
            if (event.altKey) {
                keys.push("alt");
                }

            //最后将数组中的值用join()方法以字符串的形式用逗号隔开。
            console.log("keys:" + keys.join(","));
            switch (event.button) {
                case 0:
                    alert("用户按下鼠标的主按键");
                    break;
                case 1:
                    alert("用户按下鼠标的中间按键");
                    break;
                case 2:
                    alert("用户按下鼠标的次按键");
                    break;
                }
            };
        </script>
    </body>
</html>
鼠标datail属性
        在"DOM2级事件"中Event对象还提供了一个叫 detail 的属性,该属性表示事件的更多信息。比如:鼠标事件中,该属性包含一个数值,表示发生了多少次单击,在同一个元素上, 连续发生一次mousedown和一次mouseup算作一次单击 ,detail的值是从1开始计数,每次单击发生后数值递增。如果鼠标在mousedown和mouseup之间移动了位置,则datail重置为0。
        注:如果是 连续地单击鼠标 ,detail值会递增并显示,表示此次单击了多 次,但如果是 间断地单击鼠标 ,则datail的值还是1,表示为此次只单击了一 次。
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>JavaScript</title>
    </head>
    <body>
        <input id="inpt1" type="button" value="单击事件">
        <script>
            let inpt1 = document.getElementById("inpt1");
            //鼠标单击事件,datail记录单击的次数。
            inpt1.onclick = function (e) {
                console.log(e.detail);
            };
        </script>
    </body>
</html>
鼠标滑动事件
        当用户通过鼠标滑轮(滚轮)与页面交互、上下滚动页面时,会触发一个叫 mousewheel 的事件即 鼠标滑动事件 。该事件的event对象不仅包含了鼠标事件的所有信息,还包含一个叫做 wheelDelta 属性,当鼠标滑轮滚动时,该属性返回120的倍数。当向前滑动时(即页面向下滑动),wheelDelta属性返回-120的倍数,当向后滑动时(即页面向上滑动),wheelDelta属性返回+120的倍数。

 

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>JavaScript</title>
    </head>
    <body>
        <input id="input1" type="button" value="单击事件">
        <script>
            let input1 = document.getElementById("input1");
            //当触发mousewheel事件时,wheelDelta属性记录了滑动数据
            document.onmousewheel = function (event) {
                if (event.wheelDelta > 0) {
                    console.log("鼠标向前滑动");
                } else if (event.wheelDelta < 0) {
                    console.log("鼠标身后滑动");
                } else {
                    console.log("未滑动");
                }
                console.log(event.wheelDelta);
            };
        </script>
    </body>
</html>

        4⃣️ 键盘与文本事件

        用户在使用键盘时会触发键盘事件。常用的键盘事件有3种:
  • keydown:按下键盘上的任意按键会触发事件,如果按住按键不放,则会重复触发事件。
  • keyup:当释放键盘按键时会触发事件。
  • keypress:当用户按住键盘上的字符键时会触发事件,如果按住不放,则会重复触发事件。
        :当用户按了一下字符键时,首先会触发keydown事件,接着会触发keypress事件,最后会触发keyup事件。
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>JavaScript</title>
    </head>
    <body>
        <input id="input1" type="button" value="单击事件">
        <script>
            let input1 = document.getElementById("input1");
            //当按下键盘按键时会触发。
            document.onkeydown = function (event) {
                console.log("您按下了按键");
            };
            //当按下的是字符键时会触发
            document.onkeypress = function (event) {
                console.log("您按下的是字符键");
            };
            //释放按键时会触发
            document.onkeyup = function (event) {
                console.log("您释放了按键");
            };
        </script>
    </body>
</html>

键码

        当触发keydown和keyup事件时,其event对象有个叫做 keyCode 的属性,其包含了用户所按下的按键的字符键码。例如:字符“q”对应的键码为81,字符"w"对应的键码是87。
         keyCode属性不会区分字符大小写状态的 ,例如:不管是大写A还是小写a均返回65。
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>JavaScript</title>
    </head>
    <body>
        <input id="input1" type="button" value="单击事件">
        <script>
            let input1 = document.getElementById("input1");
            document.onkeydown = function (event) {
                console.log(event.keyCode);
            };
            document.onkeyup = function (event) {
                console.log(event.keyCode);
            };
        </script>
    </body>
</html>

 

 

 

 

字符编码
        当触发keypress事件时,就意味着会影响屏幕中文本的显示(意味着会插入字符或者删除字符)。当触发keypress事件时,其event对象有个叫做 charCode 的属性,其属性包含的是用户所按按键的字符编码,与keydown和keyup的even对象的 keyCode 属性相似。例如:当用户按下"a"时,该属性返回97,当按下"A",该属性返回65。
        注:charCode与keyCode的区别在于: keyCode不会区分字符的大小写状态 也就是说不管用户所按下的是小写的“a”,还是大写的"A",keyCode都是返回的 65。 charCode会区分大小写
状态 ,小写“a”返回97,大写“A”返回65。
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>JavaScript</title>
    </head>
    <body>
        <input id="input1" type="button" value="单击事件">
        <script>
            let input1 = document.getElementById("input1");
            //keypress事件的event对象的charCode属性
            document.onkeypress = function (event) {
                console.log(event.charCode);
            };
        </script>
    </body>
</html>
DOM3级变化
        DOM3级中,新增了两个属性: key和char ,这两个属性取代了charCode属性。
        key属性返回的是一个字符串,即用当用户所按键是字符时,会返回相应的字符 ,如"k"、“w”等,而 当用户所按为非字符按键时,该属性会返回相应的键名 ,如“shift”, "ctrl"等。
        char属性 与key属性相似, 当用户按下字符按键时,会返回相应的字符 ,但 当用户按下的是非字符按键时,该属性会返回null
        由于存在跨浏览器问题,还是不建议使用char和key属性
        DOM3中的location属性,该属性返回一个数值,表示用户所按下的按键处于键盘的什么位置。返回0表示在默认键盘位置,返回1表示在左侧位置(即左侧的shift),返回2表示在右侧位置(即右侧的shift),返回3表示数字小键盘,返回4表示移动设备键盘,返回5表示手柄。火狐和谷歌支持的是keyLocaltion属性。
textInput事件
        当用户在可编辑区域输入字符时,会触发该事件。
        textInput事件与keypress事件的区别:
  • textInput事件只有在可输入区域才能触发,而keypress事件就是只要任何获取焦点的元素就会触发该事件
  • 只有输入实际的字符才能触发textInput事件,而keypress事件,只要按下是否能影响文本显示的按键时就能触发
         textInput事件考虑的是字符,因为该事件的Event对象只有一个data属性,该属性包含的值就是用户输入的字符,包括字符的大小写形式。
<body>
    <input id="text1" type="text" >
    <script>
        let text1 = document.querySelector("#text1");
        text1.ontextInput = function (e) {
            alert(e.date);
        };
    </script>
</body>

Version:0.9 StartHTML:0000000105 EndHTML:0000031901 StartFragment:0000000141 EndFragment:0000031861

        5⃣️ 复合事件

        复合事件是DOM3新增的一类事件,用于处理输入的IME的输入序列。
        复合事件可以让用户输入物理键盘上没有的字符。

        6⃣️ 变动事件

        变动事件:DOM中某一部分发生变化时就会触发 。如删除节点、插入节点等操作。DOM2级中的变动事件如下:
  • DOMSubtreeModified:在DOM结构中发生任何变化时触发。这个事件在其它事件触发后都会触发。
  • DOMNodeRemoved:在节点从其父节点中移出时触发。(删除节点时)
  • DOMNodeInserted:在一个节点作为另一个节点的子节点插入时触发。(插入节点)
  • DOMNodeInsertedIntoDocument:在一个节点直接被插入到文档中或通过DOM子树结构插入到文档中时触发。
  • DOMNodeRemovedFromDocument:在一个节点直接从文档中移出或通过DOM子树结构移出时触发。
删除节点
        可以使用 removeChild()或replaceChild() 方法来删除节点,在删除节点的过程中,会触发以下事件:
        首先会触发 DOMNodeRemoved (删除节点时会触发)事件,该事件的目标(event.target)是被删除的节点,而event.relatedNode属性包含着对目标节点的父节点的引用。在触发该事件之时,节点还未被删除,此时parentNode属性仍然是其父节点(与event.relateNode引用的一样,该节点还未被删除,肯定有其父节点)。这个事件会冒泡,因此可以在DOM结构的任何层次上处理
(也就是说,可以在DOM结构的任何层次上创建该事件的处理程序)。 如果被删除的节点包含子节点(被删除的节点有子节点),就会在其所有子节点上以及该节点上相继触发DOMNodeRemovedFromDocument事件 ,该事件不会冒泡,所以只能指定给其中一个子节点的事件处理程序才会触发(也就是说只能于被删除的节点以及子节点创建处理程序)。这个事件的目标
(event.target)是相应的子节点或被移出的这个节点。除此之外event对象不包含其它信息。 最后会触发DOMSubtreeModifined 事件,这个事件引用的是被删除节点的父节点。除此之外event对象不包含任何其它事件信息。经过以上步骤后,节点从文档中被删除 (ElementNode.parent.removeChild(ElementNode))。
 
<!doctype html>
<html lang="zh-en">
    <head>
        <meta charset="utf-8">
        <title>变动事件之删除节点操作</title>
        <style></style>
    </head>
    <body>
        <ul id="myList">
            <li>li 1</li>
            <li>li 2</li>
            <li>li 3</li>
            <li>li 4</li>
        </ul>
        <script>
            window.onload = function (e) {
            //通过ID获取ul元素的引用
                let list = document.querySelector("#myList");
            /*首先是触发DOMNodeRemoved事件,event.relateNode包含对其父
              节点的引用(即document.body),由document添加该事件处理程序也可以。*/
                list.addEventListener("DOMNodeRemoved", function (e) {
                    console.log(e.type); //DOMNodeRemoved
                    console.log(e.target); // <ul>...</ul>
                    console.log(e.relateNode); //undefined
                    console.log(list.parentNode); //<body>...</body>
                });
                //接着在被删除节点上触发DOMNodeRemovedFromDocument事件
                list.addEventListener("DOMNodeRemovedFromDocument", 
                    function(e) {
                        console.log(e.type); //DOMNodeRemovedFromDocument
                        console.log(e.target); //<ul>...</ul>
                });
                //再接着在被删除节点的子节点上触发
                DOMNodeRemovedFromDocument事件
                list.firstChild.addEventListener("DOMNodeRemovedFromDocument",
                    function (e){
                    console.log(e.type); //DOMNodeRemoveFromDocument
                    console.log(e.target); //#text 因为<li>包含的是文本内容
                });
                /*随之触发DOMSubtreeModifined事件,该事件的目标是被删除节点的
                  父节点(即document.body)此时Event对象不会包含任何有关事件的信息,
                  所以以下的内容不会返回。*/
                list.addEventListener("DOMSubtreeModified", function (e) {
                    console.log(e.type);
                    console.log(e.target);
                });
                //设置以上事件处理程序之后,该元素从其父节点中被删除。
                list.parentNode.removeChild(list);
                /*该方式也行,因为在这个例子中,<ul>元素的父节点就是<body>
                document.body.removeChild(list);*/
            }
        </script>
    </body>
</html>
        可以看出当要删除<ul>节点时会经过以下的操作步骤:
  • 首先在<ul>元素上触发DOMNodeRemoved事件,该事件的目标就是当前元素节点即<ul>,该事件的Event对象的relatedNode引用的是其父节点即document.body。
  • 接着,在<ul>元素上触发DOMNodeRemovedFromDocument事件,该事件的目标就是<ul>元素本身,并且Event对象不包含其它信息了。
  • 再接着,在<ul>元素的子节点(当然要看被删除节点是否有子节点,如果没有,该行当没说。)<li>元素上也触发DOMNodeRemovedFromDocument事件,这次该事件的目标就是"#text",因为<li>元素包含的是文本内容。
  • 随着在其父节点上(document.body)上触发DOMSubtreeModified事件,该事件的目标就是document.body。
  • 最后,经过以上事件处理程序的操作,将<ul>元素节点从其父元素中删除。
插入节点
        使用 appendChild()、insertBefore()、replaceChild() 方法来插入节点,在执行这些操作时,会触发以下事件:
  • 首先会触发DOMNodeInsered事件,该事件的目标是被插入的节点(event.target),而event.relatedNode包含一个父节点的引用。在这个事件触发时,该节点已经被插入到文档中了。这个事件有冒泡,所以可以在DOM的任何层次上处理(也就是说,可以在DOM结构的任何层次上创建该事件的处理程序)。
  • 接着会在新插入的节点上触发DOMNoeInseredIntoDocument事件。该事件不会冒泡,所有需在该节点被插入之前为它添加事件处理程序(也就是说只能新插入的节点上创建处理程序),该事件的目标就是这个新插入的节点,除此之外Event对象不包含其它事件信息。
  • 最后在新插入的节点的父节点上触发DOMSubtreeModefied事件,该事件不包含任何有关事件的信息。
        经过以上事件处理程序之后,在某个节点下插入新的节点操作。
        就以上面的例子为基础,为<ul>元素节点新插入一个子节点。注:该新节点需要新创建。
<!doctype html>
<html lang="zh-en">
    <head>
        <meta charset="utf-8">
        <title>变动事件之删除节点操作</title>
        <style></style>
    </head>
    <body>
        <ul id="myList">
            <li>li 1</li>
            <li>li 2</li>
            <li>li 3</li>
            <li>li 4</li>
        </ul>
        <script>
            window.onload = function (e) {
                //通过ID获取ul元素的引用
                let list = document.querySelector("#myList");
                //创建一个新子节点,并添加内容。
                let item = document.createElement("li");
                item.innerHTML = "li 5";
                /*首先是触发DOMNodeInserted事件,event.relateNode包含对一个父
                  节点的引用(即<ul>)*/
                item.addEventListener("DOMNodeInserted", function (e) {
                    console.log(e.type); //DOMNodeInserted
                    console.log(e.target); // <li>...</li>
                    console.log(e.relateNode); //undefined
                    console.log(list.parentNode); 
                    //<body>...</body> 在文档中创建的节点,开始时其父节点为<body>
                });
                //接着在新节点上触发DOMNodeInsertedIntoDocument事件
                item.addEventListener("DOMNodeInsertedIntoDocument", 
                    function(e) {
                        console.log(e.type); //DOMNodeInsertedIntoDocument
                        console.log(e.target); //<li>...</li>
                });
                /*随之触发DOMSubtreeModifined事件,该事件的目标是新插入节点的
                  父节点(即<ul>)此时Event对象不会包含任何有关事件的信息,所以
                  以下的内容不会返回。*/
                document.addEventListener("DOMSubtreeModified", function (e) {
                    console.log(e.type);
                    console.log(e.target);
                });
                //设置以上事件处理程序之后,将新节点插入到文档中(即父节点中)。
                list.appendChild(item);
                //新节点插入到某个节点中,其父节点为某个节点。
                console.log(item.parentNode); // <ul>...</ul>
            }
        </script>
    </body>
</html>

Version:0.9 StartHTML:0000000105 EndHTML:0000022881 StartFragment:0000000141 EndFragment:0000022841

        7⃣️ TML5事件

        DOM规范没有涵盖浏览器支持的所有事件,HTML5列出了浏览器的支持的所有事件,下面是得到浏览器完美支持的事件:
        contextmenu事件
        默认的上下文菜单栏:当点击鼠标右键时,会出现一个默认的菜单栏。为了实现自定义的上下文菜单,开发人员遇见的主要问题是:如何确定要显示的菜单,如何隐藏和操作菜单。于是contextmenu事件出现了。
        contextmenu事件属于鼠标事件,一般为鼠标右键事件,它是冒泡的 ,所以可以为document指定一个事件处理程序。该事件的目标是被用户操作的元素。为了实现自定义的上下文菜单,首先是阻止鼠标右键的默认行为(即点击鼠标右键弹出默认菜单栏)。contextmenu事件属于鼠标事件,那么就可以通过event对象得到鼠标的位置,恰好自定义菜单出现的位置也是鼠标单击的位置。通常使用contextmenu事件来显示自定义的菜单栏,而通过鼠标的click事件来隐藏该菜单栏。
        比如:通过按鼠标右键弹出自定义菜单栏来选择上下面、首页、尾页等操作。
<!doctype html>
<html lang="zh-en">
    <head>
        <meta charset="utf-8">
        <title>contextmenu事件</title>
        <style>
            #myDiv {
                width: 200px;
                height: 100px;
                border: 1px solid blue;
                }
            #myMenu {
                position: absolute;
                visibility: hidden;
                width: 185px;
                height: 25px;
                background-color: silver;
                }
            #myMenu li {
                float: left;
                list-style: none;
                }
        </style>
    </head>
    <body>
        <div id="myDiv">文章内容</div>
        <ul id="myMenu">
            <li>首页</li>
            <li>上一页</li>
            <li>下一页</li>
            <li>尾页</li>
        </ul>
        <script>
            window.onload = function (e) {
                let div = document.querySelector("#myDiv");
                let menu = document.querySelector("#myMenu");
                //添加contextmenu事件处理程序,自定义鼠标右键的上下文菜单
                div.addEventListener("contextmenu", function (e) {
                    //阻止鼠标右键的默认行为(按鼠标右键有默认的菜单栏)
                    e.preventDefault();
                    //上下文菜单栏会出现在鼠标点击的位置
                    menu.style.left = e.clientX + "px";
                    menu.style.top = e.clientY + "px";
                    //点击鼠标显示菜单栏
                    menu.style.visibility = "visible";
                });
                //单击鼠标左键,隐藏自定义菜单栏。
                document.addEventListener("click", function (e) {
                    menu.style.visibility = "hidden";
                });
            };
        </script>
    </body>
</html>
beforeunload事件
        当卸载页面、或者重新刷新页面时,可能我们没有保存数据,刷新之后,数据就会消失。如果给winsow添加一个叫 beforeunload() 的事件处理程序,那么当我们要重新刷新页面时,页面会弹出警告框,要我们确认是否要刷新这个页面,这是一个友好的提示:
window.onbeforeunload = function (e) {
    let message = "确定要离开页面吗";
    return message;
};
DOMContentLoaded事件
        window的load事件会在页面加载完成之后触发,但这个过程可能会因为要加载的资源大多而等的时间较长。 DOMContentLoaded事件在形成完整的DOM结构之后就会触发,而不必等到图像、JavaScript资源、CSS资源加载完毕之后才触发 。这样用户就可以早点与浏览器交互。可以为document或window添加处理程序,但目标还是document。
window.addEventListenter("DOMContentLoaded", function () {
    alert("用户早点与浏览器交互");
});
readystatechange事件
        该事件的目的是提供与文档或元素加载状态有关的信息 。readystatechange事件的Event对象有个readyState属性,保存着状态值。状态值有5个:
  • uninitialized(未初始化):对象存在但未初始化。
  • loading:对象正在加载数据。
  • loaded:对象已经加载完数据。
  • interactive:可以操作对象了,但未完全加载。
  • compelete:对象已经加载完毕。
pageshow事件和pagehide事件
        注: 这两个事件的目标是document,但必需添加到window对象上 浏览器有一个特性做"往返缓存", 往返缓存(bfcache)可以在用户使用浏览器的"后退"和"前进"按钮时加快页面的转换速度 。bfcache中不仅保存了页面的数据,还保存了DOM和JavaScript的状态。将整个页面保存在了内存中,如果页面是在bfcache中,那么打开这个页面时,不会触发load事件。
        pageshow事件会在页面显示时触发,无论该页面是在bfcahce中,还是触发了load事件。pageshow事件会在load事件触发之后触发。 pageshow事件的Event对象中有个叫 persisted的属性,该属性是一个布尔值,true表示页面被保存在bfcache中,如果返回false,则表示页面是重新加载的
        与pageshow事件相对的就是pagehide事件 ,该事件是在unload事件之后触发的,同样Event对象中有个persisted属性,用途有点不同。如果 返回true,表示页面卸载之后被保存在bfcache中
hashchange事件
        HTML5新增了一个hashchange事件,该事件反应了URL变化的信息和状态。Event对象中有两个属性: oldURL和newURL 。分别表示变化前的URL和变化后的URL。通常用于Ajax技术。

        8⃣️ 拖放事件

        在HTML5之前,如果要实现拖放效果,一般会使用 mousedown、mousemove和mouseup 三个事件进行组合来模拟出拖拽效果,比较麻烦。 HTML5为所有的HTML元素规定了一个 draggable 属性,表示元素是否允许拖动。要想让其他元素也能被拖动,可以设置这个属性为true。
 
创建一个可拖放对象
        如果想要拖动某个元素,需要设置元素的 draggable 属性为 true。
<img id="dragImg" draggable="true" />
        给 dragstart 设置一个事件监听器存储拖放数据和效果。
document.getElementById("dragImg").addEventListener("dragstart",
    function(event) {
        event.dataTransfer.setData("Text",ev.target.id);
}, false);
放置对象
        假设放置对象的DOM为:
<div id="dragTarget"></div>
        dragenter事件,用来确定放置目标是否接受放置。如果放置被接受,那么这个事件必须取消。
document.getElementById("dragTarget").addEventListener("dragenter",
    function(event) {
        // 阻止浏览器默认事件
        event.preventDefault();
}, false);
        dragover事件,用来确定给用户显示怎样的反馈信息。如果这个事件被取消,反馈信息(通常就是光标)就会基于 dropEffect 属性的值更新。
document.getElementById("dragTarget").addEventListener("dragover",
    function(event) {
        // 阻止浏览器默认事件
        event.preventDefault();
}, false);
        最后是drop事件 ,允许放置对象。
document.getElementById("dragTarget").addEventListener("drop",
    function(event) {
        event.preventDefault();
        let data=event.dataTransfer.getData("Text");
        event.target.appendChild(document.getElementById(data));
}, false);
例子:
<!DOCTYPE HTML>
<html>
    <head>
        <style type="text/css">
            #dragTarget {
                width:488px;
                height:70px;
                padding:10px;
                border:1px solid #aaaaaa;}
        </style>
        <script type="text/javascript">
            function allowDrop(ev){
                ev.preventDefault();
            }

            function drag(ev){
                ev.dataTransfer.setData("Text",ev.target.id);
            }

            function drop(ev){
                ev.preventDefault();
                let data=ev.dataTransfer.getData("Text");
                ev.target.appendChild(document.getElementById(data));
            }
        </script>
    </head>
    <body>
        <p>please drop the picture to the box!</p>
        <div id="dragTarget" ondrop="drop(event)"
            ondragover="allowDrop(event)"></div>
        <br />
        <img id="dragImg" 
             src="http://www.w3school.com.cn/i/w3school_banner.gif"
             draggable="true" ondragstart="drag(event)" />
    </body>
</html>

拖放的相关事件 

事件产生事件的元素描述
dragstart被拖放的元素开始拖放操作
drag被拖放的元素拖放过程中
dragenter拖放过程中鼠标经过的元素被拖放元素开始进入本元素范围内
dragover拖放过程中鼠标经过的元素被拖放元素正在本元素范围内移动
dragleave拖放过程中鼠标经过的元素被拖放元素离开本元素范围
drop拖放的目标元素有其他元素被拖放到本元素中
dragend拖放的目标元素拖放操作结束

 DataTransfer属性

属性描述
dropEffect表示拖放操作的视觉效果,允许对其进行值的设定。该效果必须 在用effectAllowed属性指定的允许的视觉效果范围内,允许指 定的值有:none、copy、link、move。
effectAllowed用来指定当元素被拖放时所允许的视觉效果。可以指定的值有: none、copy、copyLink、copyMove、link、linkMove、all、 uninitialize。
files返回表示被拖拽文件的 FileList。
types存入数据的MIME类型。如果任意文件被拖拽,那么其中一个类 型将会是字符串”Files”。

  DataTransfer方法

方法描述
void setData(DOMString format, DOMString data)向DataTransfer对象存入数据。
DOMString getData(DOMString data)读取DataTransfer对象中的数据。
void clearData(DOMString format)清除DataTransfer对象中的数据。如 果省略参数format,则清除全部数 据。
void setDragImage(Element image, long x, long y)用img元素来设置拖放图标。

注册事件处理程序

        1⃣️ 设置JavaScript对象属性为事件处理程序 可以通过设置某一事件目标的事件处理程序属性来为其注册相应的事件处理程序 。事件处理程序属性名字由 “on”后面跟着事件名组成 ,例如:onclick、onmouseover。
<!DOCTYPE HTML>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title>test</title>
        <style type="text/css">
            #div1{width: 300px; 
                  height: 300px;
                  background: red;
                  overflow:hidden;}
            #div2{margin:50px auto; 
                  width: 200px; 
                  height: 200px; 
                  background:green; 
                  overflow:hidden;}
            #div3{margin:50px auto; 
                  width: 100px; 
                  height: 100px; 
                  background:blue;}
        </style>
    </head>
    <body>
        <div id="div1">div1
            <div id="div2">div2
                <div id="div3">div3</div>
            </div>
        </div>
        <script type="text/javascript">
            let div1 = document.getElementById('div1');
            let div2 = document.getElementById('div2');
            let div3 = document.getElementById('div3');
            div1.onclick = function(){
                console.log('div1');};
                div2.onclick = function(){
                    console.log('div2');
                };
                div3.onclick = function(){
                console.log('div3');
            };
            div1.onclick = function(){ /*覆盖前面的*/
                console.log('div11111');
            };
            div1.onClick = function(){ /*大写不会识别出来*/
                console.log('DIV11111');
            };
        </script>
    </body>
</html>
  • 因为JavaScript是严格区分大小写的,所以,这种形式下属性名只能按规定小写;
  • 若给同一元素对象写多个onclick事件处理属性,后面写的会覆盖前面的(ps:这就是在修改一个对象属性的值,属性的值是唯一确定的);
  • 这种形式也是在事件冒泡过程中注册事件处理程序的。
        2⃣️ 设置HTML标签属性为事件处理程序
        文档元素的事件处理程序属性,其名字由“on”后面跟着事件名组成,例如:onclick、onmouseover。这种形式只能为DOM元素注册事件处理程序。
<!DOCTYPE HTML>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title>test</title>
        <style type="text/css">
            #div1{width: 300px; 
                  height: 300px; 
                  background: red;
                  overflow:hidden;}
            #div2{margin:50px auto; 
                  width: 200px; 
                  height: 200px; 
                  background:green; 
                  overflow:hidden;}
            #div3{margin:50px auto; 
                  width: 100px; 
                  height: 100px; 
                  background:blue;}
        </style>
    </head>
    <body>
        <!--HTML中不区分大小写-->
        <div id="div1" onClick="console.log('div1');">div1
            <div id="div2" oNClick="console.log('div2');">div2
                <!--元素的多个onclick事件处理属性只执行第一个-->
                <div id="div3" onclick="console.log('div3');"
                    onclick="console.log('div3333');">div3</div>
            </div>
        </div>
        <script type="text/javascript"></script>
    </body>
</html>
  • 因为HTML里面不区分大小写,所以这里事件处理程序属性名大写、小写、大小混写均可,属性值就是相应事件处理程序的JavaScript代码;
  • 若给同一元素写多个onclick事件处理属性,浏览器只执行第一个onclick里面的代码,后面的会被忽略;
  • 这种形式是在事件冒泡过程中注册事件处理程序的。
        3⃣️ addEventListener()前两种方式出现在Web初期,众多浏览器都有实现。而 addEventListener()方法是标准事件模型中定义的 任何能成为事件目标的对象 ——这些对象包括
Window对象、Document对象和所有文档元素等—— 都定义了一个名叫 addEventListener() 的方法 使用这个方法可以为事件目标注册事件处理程序
        addEventListener()接受三个参数:
        第一个参数是要注册处理程序的事件类型,其值是字符串,但并不包括前缀“on”
        第二个参数是指当指定类型的事件发生时应该调用的函数
        第三个参数是布尔值 ,其可以忽略(某些旧的浏览器上不能忽略这个参数),默认值为false。这种情况是在事件冒泡过程中注册事件处理程序。当其为true时,就是在事件捕获过程中注册事件处理程序。
<!DOCTYPE HTML>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title>test</title>
        <style type="text/css">
            #div1{width: 300px; 
                  height: 300px; 
                  background: red;
                  overflow:hidden;}
            #div2{margin:50px auto; 
                  width: 200px; 
                  height: 200px; 
                  background:green; 
                  overflow:hidden;}
            #div3{margin:50px auto; 
                  width: 100px; 
                  height: 100px; 
                  background:blue;}
        </style>
    </head>
    <body>
        <div id="div1" >div1
            <div id="div2" >div2
                <div id="div3" >div3</div>
            </div>
        </div>
        <script type="text/javascript">
            let div1 = document.getElementById('div1');
            let div2 = document.getElementById('div2');
            let div3 = document.getElementById('div3');
            div1.addEventListener('click', function(){ 
                console.log('div1-bubble'); },false);
            div2.addEventListener('click', function(){ 
                console.log('div2-bubble'); },false);
            div3.addEventListener('click', function(){ 
                console.log('div3-bubble'); },false);
            div3.addEventListener('click', function(){ 
                console.log('div3-bubble222'); }, false);
            div1.addEventListener('click', function(){ 
                console.log('div1-capturing');}, true);
            div2.addEventListener('click', function(){ 
                console.log('div2-capturing');}, true);
            div3.addEventListener('click', function(){ 
                console.log('div3-capturing');}, true);
        </script>
    </body>
</html>
  • addEventListener()第三个参数可以忽略;
  • 通过addEventListener()方法给同一对象注册多个同类型的事件,并不会发生忽略或覆盖,而是会按顺序依次执行;
        相对addEventListener()的是removeEventListener()方法 ,它同样有三个参数,前两个参数自然跟addEventListener()的意义一样,而第三个参数也只需跟相应的addEventListener()的第三个参数保持一致即可,同样可以省略,默认值为false。它 表示从对象中删除某个事件处理函数
div1.addEventListener('click', div1BubbleFun, false);
div1.removeEventListener('click', div1BubbleFun, false);
    function div1BubbleFun(){
        console.log('div1-bubble');
    };
        4⃣️ attachEvent()
        IE8以及其之前版本的浏览器并不支持addEventListener()和removeEventListener()。相应的,IE定义了类似的方法 attachEvent()和detachEvent() 。因为IE8以及其之前版本浏览器也不支持事件捕获,所以attachEvent()并不能注册捕获过程中的事件处理函数,因此 attachEvent()和
detachEvent()要求只有两个参数:事件类型和事件处理函数。而且,它们的第一个参数使用了带“on”前缀的事件处理程序属性名
let div1 = document.getElementById('div1');
div1.attachEvent('onclick', div1BubbleFun);
function div1BubbleFun(){
    console.log('div1-bubble');
}
        相应的,从对象上删除事件处理程序函数使用detachEvent()。
div1.detachEvent('onclick', div1BubbleFun);

事件处理程序的调用

        1⃣️ 事件处理程序的参数
        通常事件对象作为参数传递给事件处理函数,但IE8以及其之前版本的浏览器中全局变量event才是事件对象。所以,我们在写相关代码时应该 注意兼容性问题
        给页面上id为div1的元素添加点击事件,当点击该元素时在控制台输出事件类型和被点击元素本身:
<!DOCTYPE HTML>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title>test</title>
        <style type="text/css">
            #div1{width: 300px; 
                  height: 300px; 
                  background: red; 
                  overflow:hidden;}
        </style>
    </head>
    <body>
        <div id="div1">div1</div>
        <script type="text/javascript">
            let div1 = document.getElementById('div1');
            if(div1.addEventListener){
                div1.addEventListener('click', div1Fun, false);
            }else if(div1.attachEvent){
                div1.attachEvent('onclick', div1Fun);
            }
            function div1Fun(event){
                event = event || window.event;
                let target = event.target || event.srcElement;
                console.log(event.type);
                console.log(target);
            }
        </script>
    </body>
</html>
        2⃣️ 事件处理程序的运行环境
        关于事件处理程序的运行环境,要注意事件处理程序中 调用上下文(this值) 的指向问题。
  • 事件处理程序中this指向这个元素本身:
<!DOCTYPE HTML>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <title>test</title>
        <style type="text/css">
            #div1{width: 300px; 
                  height: 300px; 
                  background: red; 
                  overflow:hidden;}
        </style>
    </head>
    <body>
        <div id="div1" onclick="console.log('html:');
            console.log(this);">div1</div>
        <script type="text/javascript"></script>
    </body>
</html>
  • 在<body></body>中 添加如下script代码,代码中的this也指向元素本身,但是会覆盖前面注册的事件处理程序
<script type="text/javascript">
    let div1 = document.getElementById('div1');
    div1.onclick = function(){
        console.log('div1.onclick:');
        console.log(this);
    };
</script>
  • 在<script></script>标签中继续添加如下代码,代码中的this同样指向元素本身,并且不会覆盖前面注册的事件处理程序
div1.addEventListener('click', function(){
    console.log('div1.addEventListener:');
    console.log(this);
    }, false);
  • 在<script></script>标签中添加如下代码,代码中的this指向的则是全局对象window,并且该方法也不会覆盖前面注册的事件处理程序:
div1.attachEvent('onclick', function(){
    console.log('div1.attachEvent:');
    console.log(this === window);
});
        3⃣️ 事件处理程序的调用顺序
        多个事件处理程序调用规则如下:
  • 通过HTML属性注册的处理程序通过设置对象属性的处理程序一直优先调用
  • 使用addEventListener()注册的处理程序按照它们的注册顺序依次调用
  • 使用attachEvent()注册的处理程序可能按照任何顺序调用,所以代码不应该依赖于调用顺序;
        4⃣️ 事件取消
        取消事件的浏览器默认操作(比如点击超链接元素会自动发生页面跳转的默认操作):         如果使用前两种方法注册事件处理程序,可以在处理程序中添加返回值false来取消事件的浏览器默认操作。在支持addEventListener()的浏览器中,也可以通过调用事件对象的 preventDefault()方法取消事件的默认操作。至于IE8及其之前的浏览器可以通过设置事件对象的returnValue属性为false来取消事件的默认操作。
function cancelHandler(event){
    let event = event || window.event;
    if(event.preventDefault){
        event.preventDefault();
    }
    if(event.returnValue){
        event.returnValue = false;
    }
    return false;
}
        取消事件传播
        在支持addEventListener()的浏览器中,可以调用事件对象的一个 stopPropagation() 方法阻止事件的继续传播,它能工作在事件传播期间的任何阶段(捕获期阶段、事件目标本身、冒泡阶段)
但是在IE8以及其之前版本的浏览器中并不支持stopPropagation()方法,而且这些浏览器也不支持事件传播的捕获阶段,相应的,IE事件对象有一个 cancelBubble 属性,设置这个属性为true能阻止事件进一步传播(即阻止其冒泡)。
        阻止发生在div3区域的点击事件冒泡到div2和div1:
<!DOCTYPE HTML>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
        <title>test</title>
        <style type="text/css">
            #div1{width: 300px; 
                  height: 300px; 
                  background: red;
                  overflow:hidden;}
            #div2{margin:50px auto; 
                  width: 200px; 
                  height: 200px;
                  background: green; 
                  overflow:hidden;}
            #div3{margin:50px auto; 
                  width: 100px; 
                  height: 100px;
                  background: blue;}
        </style>
    </head>
    <body>
        <div id="div1">div1
            <div id="div2">div2
                <div id="div3">div3</div>
            </div>
        </div>
        <script type="text/javascript">
            let div1 = document.getElementById('div1');
            let div2 = document.getElementById('div2');
            let div3 = document.getElementById('div3');
            div1.onclick = function(){
                console.log('div1');
            };
            div2.onclick = function(){
                console.log('div2');
            };
            div3.onclick = function(event){
                stopEventPropagation(event);
                console.log('div3');
            };
            function stopEventPropagation(event){
                let event = event || window.event;
                if(event.stopPropagation){
                    event.stopPropagation();
                }else{
                    event.cancelBubble = true;
                }
            }
        </script>
    </body>
</html>

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值