最近写的文章感觉内容不像之前那么充实,内容可能也有点杂。对于DOM,和BOM来说,要理解是不难的,难的是做的时候。要自己想的到,而且,对于目前阶段来说,BOM还存在着很大的兼容性问题,最主要就是要兼容ie8。不过说实在的,用不了多久,ie8也差不多被淘汰了,新版本的ie浏览器对标准属性兼容性还是很好的。不过接下来要说的主题还是BOM中的一些内容。前一篇文章中主要讲了两种注册事件的方式和事件参数。本文主要讲如何移除事件,事件的冒泡。

  首先讲讲移除事件,移除事件用的是removeEventListener();移除事件一般都会配合addEventListener()一起使用,比如下述例子:

  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title></title>
  6. </head>
  7. <body>
  8. <input type="button" value="click" id="btn"/>
  9. <script>
  10. var btn = document.getElementById("btn");
  11. btn.addEventListener("click", play, false);
  12. function play() {
  13. alert("lalala");
  14. btn.removeEventListener("click", play, false);
  15. }
  16. </script>
  17. </body>
  18. </html>

  我们给btn这个按钮添加了鼠标单击事件,当我们单击这个按钮时,执行play这个函数。在play函数中,我们先输出了一句话,之后,我们再给鼠标移除了执行函数为play的鼠标单击事件。这样,我们这段代码就实现了鼠标单击一次按钮之后会跳出一句话,但之后鼠标再次点击的时候就不会有这样的效果了。不过,这段代码还有兼容性的问题,就是在ie8及以下版本的浏览器中,是没有这个方法的,在ie8中,我们注册事件用的是attachEvent(),他有两个参数,前一个参数是事件的名称,第二个参数则是事件处理函数。不过于addEventListener不同的是,它的事件名称是带on的,也就是说,我们要用这种方式给元素添加一个鼠标单击事件的时候,参数名称要写成onclick,具体如下:

  1. btn.attachEvent("onclick", play);
  2. function play() {
  3. alert("lalala");
  4. btn.detachEvent("onclick", play);
  5. }

  同样的,我们给btn这个按钮添加了一个鼠标单击事件,当我们单击这个按钮时,会输出一句话,之后移除btn的执行函数为play的鼠标单击事件。这样,我们在ie8中测试,也会发现在单击鼠标的时候,会显示一句话,但之后再点击鼠标则没有效果了。这样我们就实现了在ie8中事件的添加和移除。不过,在实际的使用中,我们可能在代码中把这两段代码都添加进去,因为这两种方法可以说是互不兼容的,google中并不支持attachEvent()这种方法。而ie8及以下版本的浏览器则不支持addEventListener这种方法。所以,这时候我们就只能封装兼容性代码了。

  1. function addEvent(element, type, listener) {
  2. if (element.addEventListener) {
  3. element.addEventListener(type, listener, false);
  4. } else if (element.attachEvent) {
  5. element("on" + type, listener);
  6. listener.call(element);
  7. } else {
  8. element["on" + type];
  9. }
  10. }
  11. function removeEvent(element, type, listener) {
  12. if (element.removeEventListener) {
  13. element.removeEventListener(type, listener, false);
  14. } else if (element.detachEvent) {
  15. element.detachEvent(type, listener);
  16. } else {
  17. element["on" + type] = null;
  18. }
  19. }

  以上两个函数分别封装了添加事件和移除事件的兼容性代码,在使用的过程中,只要调用这两个函数就可以了。比如下述代码

  1. addEvent(btn, "click", play);
  2. function play() {
  3. alert("lalala");
  4. removeEvent(btn, "click", play);
  5. }

  这段代码跟最前面两段代码执行的结果是一样的,而且他们在google和ie8中都能很好的兼容。这样,我们就封装了添加和移除事件的兼容性代码。

  说完了添加和移除事件,就来说说事件冒泡了。事件冒泡可能比较难理解,先看代码了解一下什么是事件冒泡。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <style>
  7. #box1 {
  8. width: 300px;
  9. height: 300px;
  10.  
  11. }
  12. #box2 {
  13. width: 200px;
  14. height: 200px;
  15. background-color: #00ff00;
  16. }
  17. #box3 {
  18. width: 100px;
  19. height: 100px;
  20. background-color: #0000ff;
  21. }
  22. </style>
  23. </head>
  24. <body>
  25. <div id="box1">
  26. <div id="box2">
  27. <div id="box3">
  28. </div>
  29. </div>
  30. </div>
  31. <script>
  32. var box1 = document.getElementById("box1");
  33. var box2 = document.getElementById("box2");
  34. var box3 = document.getElementById("box3");
  35. var elements = [box1, box2, box3, document.body, document];
  36. for(var i = 0, length = elements.length; i < length; i++) {
  37. var element = elements[i];
  38. element.addEventListener("click",test , false);
  39. function test() {
  40. console.log(this);
  41. }
  42. </script>
  43. </body>
  44. </html>

  上述代码中,我们定义了三个盒子,并且给box1,box2,box3,body,document都注册了鼠标单击事件。当我们单击box3的时候,控制台中输出的结果是

  

  我们发现,我们在点击box3的时候,不但输出了box3,还输出了box2,box1,body跟document。这是为什么呢?这时候,就涉及了事件冒泡。在说这个之前,我们先讲一讲事件执行的阶段:

  如上图,事件在被触发的时候分三个阶段,首先是事件捕获,就是从document起一层层遍历下来找到事件触发的元素,然后目标阶段,也就是正在执行的当前对象的事件处理程序。当执行玩之后,就会发生事件冒泡。拿上述代码来说,我们点击了box3,在经过了事件捕获阶段之后,就开始执行box3中的执行函数,只时候,就输出了box3。然后,事件进入到冒泡阶段,发现box2也有鼠标单击事件,这时候,执行box2中的执行函数,所以执行了一次box2中的执行函数,之后事件再冒泡到box1,发现他也有单击事件,这时候,执行box1中的执行函数,就这样一级级往上知道document为止。所以一共输出了5个内容。这就是事件冒泡。事件冒泡有他的好处,也有他的坏处,先来说说它的好处。既然事件会冒泡,那么我们就可以利用事件冒泡来做一些事情,比如事件委托。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. <ul id="names">
  9. <li id="ll">11111</li>
  10. <li id="lw">22222</li>
  11. <li id="lt">33333</li>
  12. <li id="xc">44444</li>
  13. </ul>
  14. <input type="button" value="插入" id="btn">
  15. <script>
  16. var ul = document.getElementById("names");
  17. ul.addEventListener("click", function (e) {
  18. alert(e.target.innerText);
  19. }, false);
  20. var btn = document.getElementById("btn");
  21. btn.onclick = function () {
  22. var li = document.createElement("li");
  23. li.innerText = "55555";
  24. ul.appendChild(li);
  25. }
  26. </script>
  27. </body>
  28. </html>

  在上述代码中,我们希望给每个li注册一个鼠标点击事件。按照正常的思路,我们就会遍历每个li,然后给每个li注册一个鼠标单击事件。这样的方法有很多坏处,首先,如果li很多的话,我们就要注册很多个事件,如果我们使用匿名函数注册的话,每多一个li就要多一个匿名函数,虽然 我们可以在外面先定义一个函数,然后在赋给鼠标单击事件。这样可以增加他的效率。不过,我们还会遇到另一个问题,就是我们如果想动态的创建一个函数的时候,我们要重新给他们添加事件,这样会很麻烦。这个时候,如果我们把这个鼠标单击事件委托给他们的父元素ul,在点击ul时,获取点击的那个li,这样,我们就只要给一个ul注册事件就好了,不用循环给每个li来添加事件。这里用到了一个知识点就是e.target,他获取的始终是当前触发事件的元素。这样,我们就实现了事件的委托。不过这个方法也是有兼容性问题。在ie8中,我们只能使用srcElement  ==  target这样的方式来获取当前事件触发的元素。所以,我们又要封装兼容性代码了,不过这个还是比较简单的。注意,这边我就不重复事件参数e的兼容性代码,这个在我BOM基础(三)的文章中提到过。

  1. getTarget: function (e) {
  2. return e.target ? event.target : e.srcElement;
  3. },

  既然说了事件冒泡的好处,就该来说说事件冒泡的坏处了。

  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <title></title>
  6. <style>
  7. #box1 {
  8. width: 200px;
  9. height: 200px;
  10.  
  11. }
  12.  
  13. #box2 {
  14. width: 200px;
  15. height: 200px;
  16. background-color: red;
  17. display: none;
  18. }
  19. </style>
  20. </head>
  21. <body>
  22. <div id="box1"></div>
  23. <div id="box2"></div>
  24. <script>
  25. var box1 = document.getElementById("box1");
  26. var box2 = document.getElementById("box2");
  27. box1.onclick = function () {
  28. box2.style.display = "block";
  29. }
  30. document.onclick = function () {
  31. box2.style.display = "none";
  32. }
  33. </script>
  34. </body>
  35. </html>

  在上述代码中,我们希望点击box1让box2显示,点击文档让box2隐藏。按正常的思路来说,我们会想到上述代码,不过,在尝试中我们发现,不管我们怎么点box1,box2都不会显示,这就是因为时间冒泡了,在我们点击box1的时候,执行了它的函数,然box2显示,当他完成了之后,事件开始冒泡,发现document也有一个鼠标单击事件,这时候,又执行他里面的代码,让box2隐藏。这个过程非常快,所以我们根本看不出来box2显示过。不过这不是我们想要的效果,所以,我们就要对其中的过程进行改进,就是在单击box1的时候,不让他冒泡。这时候,我们就又要用到事件参数的一个方法了就是e.stopPropagation();

  1. box1.onclick = function (e) {
  2. box2.style.display = "block";
  3. e.stopPropagation();
  4. }

  这样,我们就阻止了事件冒泡和捕获,实现了我们想要的效果,不过,这个方法在ie8中还是有兼容性问题,他用的是event.cancelBubble=true来阻止事件的冒泡,在ie8中,没有事件的捕获这个过程。这时候,我们又要封装兼容性代码了。

  1. function stopPropagation(event) {
  2. if (event.stopPropagation) {
  3. event.stopPropagation();
  4. } else {
  5. event.cancelBubble = true;
  6. }
  7. }

  到这里,这件冒泡就完成了。

BOM基础(四)的更多相关文章

  1. Python全栈开发【基础四】

    Python全栈开发[基础四] 本节内容: 匿名函数(lambda) 函数式编程(map,filter,reduce) 文件处理 迭代器 三元表达式 列表解析与生成器表达式 生成器 匿名函数 lamb ...

  2. Bootstrap<基础四> 代码

    Bootstrap 允许您以两种方式显示代码: 第一种是 <code> 标签.如果您想要内联显示代码,那么您应该使用 <code> 标签. 第二种是 <pre> 标 ...

  3. Python 基础 四 面向对象杂谈

    Python 基础  四  面向对象杂谈 一.isinstance(obj,cls) 与issubcalss(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls ...

  4. BOM基础 计时器 定时器 DOM 基础

    -------------------------------------------滴水穿石,我心永恒. day48 CSSJS 1 ECMA script 2 BOM browser object ...

  5. C#_02.13_基础四_.NET方法

    C#_02.13_基础四_.NET方法 一.方法概述: 方法是一块具有名称的代码.可以通过方法进行调用而在别的地方执行,也可以把数据传入方法并接受数据输出. 二.方法的结构: 方法头  AND  方法 ...

  6. BOM基础笔记

    BOM基础 BOM对浏览器的一些操作 1.打开.关闭窗口 •open –蓝色理想运行代码功能 window.open('http://www.baidu.com/', '_self'); <!d ...

  7. day 68 Django基础四之模板系统

      Django基础四之模板系统   本节目录 一 语法 二 变量 三 过滤器 四 标签Tags 五 模板继承 六 组件 七 自定义标签和过滤器 八 静态文件相关 一 语法   模板渲染的官方文档 关 ...

  8. day 54 Django基础四之模板系统

    Django基础四之模板系统   本节目录 一 语法 二 变量 三 过滤器 四 标签Tags 五 模板继承 六 组件 七 自定义标签和过滤器 八 静态文件相关 一 语法   模板渲染的官方文档 关于模 ...

  9. BOM基础

    BOM基础 打开窗口 window.open('about:blank','_blank') 第一个参数是打开哪一个口,第二个参数是在哪里打开窗口. 关闭窗口 window.close() windo ...

随机推荐

  1. rsync 实验

    参考1:http://www.jb51.net/LINUXjishu/142722.html 参考2:http://sookk8.blog.51cto.com/455855/328076 主服务器IP ...

  2. 聚类系数(clustering coefficient)计算

    转自http://blog.csdn.net/pennyliang/article/details/6838956 Clustering coefficient的定义有两种:全局的和局部的. 全局的算 ...

  3. Spring xml中进行autowired的方式

    可以在xml文件中进行autowired: xml: <?xml version="1.0" encoding="UTF-8"?> <bean ...

  4. 《深度探索C++对象模型》笔记——Function语意学

    member的各种调用方式 C++支持三种类型的member functions:static.nonstatic和virtual. nonstatic member functions会被编译器转换 ...

  5. Recurrent Neural Network系列2--利用Python,Theano实现RNN

    作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 本文翻译自 RECURRENT NEURAL NETWORKS T ...

  6. HDU2063(二分图最大匹配)

    过山车 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  7. 用虚拟 router 连通 subnet - 每天5分钟玩转 OpenStack(141)

    Neutron Routing 服务提供跨 subnet 互联互通的能力.例如前面我们搭建了实验环境: cirros-vm1      172.16.100.3        vlan100 cirr ...

  8. POI-处理大Excel文件(xls)

    最近需要处理一个比较大的excel文件,但是poi在处理文件时会抛出OOM导致程序崩溃,查看官方文档看到可以以流式的方式读取excel避免读取大文件时的OOM.本文主要记述xls的处理. 环境模拟 先 ...

  9. CSS实现的几款不错的菜单栏

    前言 自从做了智慧城市这个项目之后,我一个做后端的开发者,瞬间转为前端开发,不过我还是很喜欢前端的.前端那些事,其实蛮有意思的,HTML实现的是静态的,使用ajax之后就可以和数据库交互了,加上js和 ...

  10. 快速实现python c扩展模块

    1  python扩展模块的组成 在python中,对于一些和系统相关的模块或者对性能要求很高的模块,通常会把这个模块C化.扩展模块中主要包含下面几个部分: init函数,函数名为:init+模块名, ...