- 浏览: 26470 次
- 性别:
- 来自: 成都
文章分类
最新评论
-
549265480:
http://www.cnblogs.com/yexiaoch ...
在Java中实现.net中DataTable功能以及操作双数据库的LIst连接问题解决方案探究
【初窥javascript奥秘之事件冒泡】那些年我们一起冒的泡
前言
若是我说会有此文又是因为一次面试的话,我自己都不知道该怎么形容我的心情了,好似我的所有动力皆来自于面试似的。
其实不是这样的,我原来一个项目经理对我说,隔一两个月出去面试下,一来你会知道自己的不足知道怎么提高,二来你就知道自己涨价没。
现在回想起来他说的是很对的,面对这次的团队解散,我反而不那么着急,因为我不太惧怕面试,走到哪里都能找到工作,当然这里没有鼓励大家出去面试的意思啦。
回到本文,当时面试官问了我一个问题,我当时就支支吾吾的答不上来,其实细细思考的话这道题还是有点意思的:
在一个div上画div(绝对定位),然后再在刚刚那个div里面(上面更合适)画一个div,现在去拖到div,你知道你拖动的是哪个div吗?
说这道题本身并不难绝对是骗人的(反正时至今日我都有点没底...),说他难,他又没有难到哪里去,每个人都知道是事件冒泡相关的东西。
还是那句话知道不等于了解,了解不等于深入,皮毛说不清楚事情,今天让我们带着问题一起学习吧!
由于本文是边学边写的,可能会有点乱,可能会有我的唧唧歪歪请各位大哥见谅。
基础知识
刀不磨不亮,我们先从基础来,这里就直接忽略IE的attachEvent了吧,我们说下标准的就是,请看以下代码(这里我确实没脸再用jquery了,原生吧):
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title></title> 5 </head> 6 <body> 7 <div id="div"> 8 <input id="input" value="点击我" type="button" /> 9 </div> 10 <script type="text/javascript"> 11 var bt = document.getElementById('input'); 12 bt.addEventListener('click', function (e) { 13 var scope = this; 14 var s = ''; 15 16 }, false); 17 18 </script> 19 </body> 20 </html>
我们看到点击按钮后,执行点击事件,其中this便是对应元素,e包含了许多有用信息比如:
阻止冒泡(e.stopPropagation();)、阻止浏览器默认事件(e.preventDefault();)、当前点击元素、鼠标位置......
好,我们在此基础上做一个扩展,我们多增加两个元素,然后给document绑定事件,最后看看我们点击的是哪个:
1 <body> 2 <div id="div"> 3 <input id="input" value="点击我" type="button" /> 4 <ul> 5 <li><a>湿湿的</a></li> 6 <li><a>湿湿的1</a></li> 7 <li><a>湿湿的2</a></li> 8 </ul> 9 <span>安能辨我<b>是</b>雄雌</span> 10 </div> 11 <script type="text/javascript"> 12 document.addEventListener('click', function (e) { 13 var scope = this; 14 var cur_el = e.target.tagName; 15 var s = ''; 16 }, false); 17 </script> 18 </body>
现在我不论点击哪个标签皆会将其标签名字打印出来,请在s=''处设置断点查看:
于是我突然感觉知道了什么,又不能确认,所以我们都不敲板,来捋一捋:
1 我们为根元素绑定点击事件
2 我们点击按钮后,按钮并没有事件处理,所以将事件向上传递,直到document
3 document是绑定了事件的,所以触发了事件,其中this指向document,但是e中的当前点击元素却是按钮
好,先将一切暂停,我们来做一个很土的选项卡:
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title></title> 5 <style type="text/css"> 6 body { font: 12px 'PTSansRegular',Arial,Helvetica,sans-serif; background: #D1D1D1; } 7 ul, li { margin: 0; padding: 0} 8 li { list-style: none; } 9 10 #tabs_container { width: 400px; height: 200px; background: white; } 11 #tabs { border-bottom: 1px solid #1C87D5; padding: 5px 5px 0; } 12 #tabs li { padding: 5px 10px; cursor: pointer; display: inline-block; background: #1C87D5; color: White; } 13 14 #content { padding: 5px;} 15 </style> 16 </head> 17 <body id='body'> 18 <div id="tabs_container"> 19 <ul id="tabs"> 20 <li tab="1">选项卡1</li> 21 <li tab="2">选项卡2</li> 22 <li tab="3">选项卡3</li> 23 </ul> 24 <div id="content"> 25 内容区域 26 </div> 27 </div> 28 <script type="text/javascript"> 29 30 31 </script> 32 </body> 33 </html>
若是现在需要完成一个简单功能,点击每个选项卡,内容区域文字便会变成选项卡的标签文字你会怎么做呢?
很多年以前,我会使用jquery的标签选择器为每个li添加事件,我确信我会这样做,这样做有几个问题:
1 事件绑定过多
2 动态添加li标签的话,是不具备事件的
于是这里我们就可以用到前面的事件冒泡机制啦:
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title></title> 5 <style type="text/css"> 6 body { font: 12px 'PTSansRegular',Arial,Helvetica,sans-serif; background: #D1D1D1; } 7 ul, li { margin: 0; padding: 0} 8 li { list-style: none; } 9 10 #tabs_container { width: 400px; height: 200px; background: white; } 11 #tabs { border-bottom: 1px solid #1C87D5; padding: 5px 5px 0; } 12 #tabs li { padding: 5px 10px; cursor: pointer; display: inline-block; background: #1C87D5; color: White; } 13 14 #content { padding: 5px;} 15 </style> 16 </head> 17 <body id='body'> 18 <div id="tabs_container"> 19 <ul id="tabs"> 20 <li tab="1">选项卡1</li> 21 <li tab="2">选项卡2</li> 22 <li tab="3">选项卡3</li> 23 </ul> 24 <div id="content"> 25 内容区域 26 </div> 27 </div> 28 <script type="text/javascript"> 29 var tabs = document.getElementById('tabs'); 30 var con = document.getElementById('content'); 31 tabs.addEventListener('click', function (e) { 32 var cur_el = e.target; 33 con.innerHTML = cur_el.innerHTML; 34 }, false); 35 </script> 36 </body> 37 </html>
根据这个例子,我相信,各位都对事件冒泡有一个认识了,我们继续。
绝对定位·乱了的一切
这里会说到绝对定位,只是因为他比较特殊,其实漂浮、元素之间重叠都有可能让我们的冒泡变得复杂,先上代码:
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title></title> 5 <style type="text/css"> 6 div { padding: 10px; margin: 10px; filter:alpha(opacity=50); -moz-opacity:0.5; opacity:0.5; font-weight:bold; } 7 #d1 { width: 700px; height: 400px; background: #D1D1D1;} 8 #d1_1 { width: 200px; height: 200px; background: gray;} 9 #d2 { width: 200px; height: 200px; background: #1C87D5; position: absolute; top: 10px; left: 150px;} 10 #d3 { width: 200px; height: 200px; color:White; background: black; position: absolute; top: 150px; left: 150px;} 11 </style> 12 </head> 13 <body> 14 <div id="d1"> 15 d1 16 <div id="d1_1"> 17 d1_1 18 </div> 19 </div> 20 <div id="d2"> 21 d2 22 </div> 23 <div id="d3"> 24 d3 25 </div> 26 <script type="text/javascript"> 27 document.addEventListener('click', function (e) { 28 var scope = this; 29 var cur_el = e.target; 30 var id = cur_el.id; 31 var s = ''; 32 }, false); 33 </script> 34 </body> 35 </html>
现在各位还知道自己在干什么吗???这个将情况变的复杂,因为我们必须清晰的知道谁离我最近。
解决问题
到了解决问题的时候了,要不我们将最开始出现那道题做了吧?我们先规定一下做法,只能这样做哟:
1 给一个按钮给用户让用户选择现在是画矩形或者拖动矩形
2 在给定的一个div(相对定位)中画div,画的div(绝对定位)将append到父div里面
3 选择拖动div,便可在父层div中进行拖动了
4 不能为除父div以为的div添加事件!
5 可以使用jquery,可以暂时不考虑滚动条
怎么样简单吧,让我们动手吧:
为了方便各位拖到,我先上个图,然后再来一段丑陋的代码:
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title></title> 5 <style type="text/css"> 6 body { font: 12px 'PTSansRegular',Arial,Helvetica,sans-serif; background: #D1D1D1; } 7 ul, li { margin: 0; padding: 0} 8 li { list-style: none; } 9 10 #tabs_container { width: 400px; height: 200px; background: white;} 11 #tabs { border-bottom: 1px solid #1C87D5; padding: 5px 5px 0; width: 690px; margin: 0 auto; } 12 #tabs li { padding: 5px 10px; cursor: pointer; display: inline-block; background: #1C87D5; color: White; } 13 #tabs li.sec { color: black;} 14 15 #parent { width: 700px; height: 400px; background: white; margin: 0 auto; position: relative; } 16 #parent div { filter:alpha(opacity=50); -moz-opacity:0.5; opacity:0.5; font-weight:bold; background: red; position: absolute; } 17 </style> 18 </head> 19 <body> 20 <ul id="tabs" > 21 <li type="draw" class="sec">画矩形框</li> 22 <li type="drag">拖到矩形框</li> 23 </ul> 24 <div id="parent"> 25 </div> 26 <div id="state"></div> 27 <script type="text/javascript"> 28 var parent = document.getElementById('parent'), 29 tabs = document.getElementById('tabs'), 30 state = document.getElementById('state'), 31 con = document.getElementById('content'), 32 li = tabs.getElementsByTagName('li'), 33 type = 'draw'; //drag 34 35 tabs.addEventListener('click', function (e) { 36 for (var i = 0; i < li.length; i++) { 37 var el = li[i]; 38 el.className = ''; 39 var s = ''; 40 } 41 var cur_el = e.target; 42 cur_el.className = 'sec'; 43 type = cur_el.type; 44 45 var s = ''; 46 }, false); 47 48 parent.addEventListener('mousedown', function (e) { 49 var scope = this; 50 if (type == 'draw') { 51 (function () { 52 var el = e.target, //当前点击元素,父div或者拖到div 53 x = e.clientX, 54 y = e.clientY, 55 offsetTop = scope.offsetTop, 56 offsetLeft = scope.offsetLeft; 57 var div_x = x - offsetLeft, 58 div_y = y - offsetTop; 59 var div = document.createElement('div'); 60 var style = 'left: ' + div_x + 'px; top: ' + div_y + 'px;'; 61 div.setAttribute('style', style); 62 div.innerHTML = scope.getElementsByTagName('div').length; 63 scope.appendChild(div); 64 var func_move = function (ee) { 65 var x1 = ee.clientX, 66 y1 = ee.clientY; 67 var w = x1 - x; 68 var h = y1 - y; 69 if (w > 5 || h > 5) { 70 div.setAttribute('style', style + 'width: ' + w + 'px; height: ' + h + 'px;'); 71 } 72 }; 73 var func_up = function (ee) { 74 document.removeEventListener('mousemove', func_move, false); 75 document.removeEventListener('mouseup', func_up, false); 76 }; 77 document.addEventListener('mousemove', func_move, false); 78 document.addEventListener('mouseup', func_up, false); 79 })(); 80 81 } else { 82 (function () { 83 var el = e.target; //当前点击元素,父div或者拖到div 84 var x1 = e.clientX - el.offsetLeft; 85 var y1 = e.clientY - el.offsetTop; 86 87 var func_move = function (ee) { 88 var cur_el = ee.target; 89 if (cur_el.id && cur_el.id == 'parent') return false; 90 var x2 = 0; 91 var y2 = 0; 92 93 x2 = ee.clientX - x1 ; 94 y2 = ee.clientY - y1 ; 95 x2 = x2 > 0 ? x2 : 0; 96 y2 = y2 > 0 ? y2 : 0; 97 98 if (Math.abs(x2) > 5 || Math.abs(y2) > 5) { 99 cur_el.style.top = (y2) + 'px'; 100 cur_el.style.left = (x2) + 'px'; 101 } 102 }; 103 104 var func_up = function (ee) { 105 document.removeEventListener('mousemove', func_move, false); 106 document.removeEventListener('mouseup', func_up, false); 107 }; 108 document.addEventListener('mousemove', func_move, false); 109 document.addEventListener('mouseup', func_up, false); 110 })(); 111 } 112 113 }, false); 114 </script> 115 </body> 116 </html>
大家去运行看看,就会发现问题了:
我们拖动1时,没有问题,但是当我们拖到0时,一旦碰到1就会出状况!!!
这是因为我们mousedown事件是绑定到了父div上,当我们鼠标点下时,便给个元素绑定了滑动事件,但是在1
上时,因为他离我们近,所以我们不会滑动到0上,。。。。滑动0时碰到1,鼠标自然就在1
上滑动了,所以拖动的就是1。。。。
我不知道各位晕不晕,我可能有点晕,今天暂时如此了。。。。
师兄讨论的结果
刚刚和师兄就这个问题做了一个讨论,他的意见还是很中肯的:
我们mousedown的时候便获取该元素,然后直接给该子元素绑定各种事件,mouseup后便把事件取消,便不会有以上问题了,
另外可能起z-index还需要进行设置,我这里就不管了:
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title></title> 5 <style type="text/css"> 6 body { font: 12px 'PTSansRegular',Arial,Helvetica,sans-serif; background: #D1D1D1; } 7 ul, li { margin: 0; padding: 0} 8 li { list-style: none; } 9 10 #tabs_container { width: 400px; height: 200px; background: white;} 11 #tabs { border-bottom: 1px solid #1C87D5; padding: 5px 5px 0; width: 690px; margin: 0 auto; } 12 #tabs li { padding: 5px 10px; cursor: pointer; display: inline-block; background: #1C87D5; color: White; } 13 #tabs li.sec { color: black;} 14 15 #parent { width: 700px; height: 400px; background: white; margin: 0 auto; position: relative; } 16 #parent div { filter:alpha(opacity=50); -moz-opacity:0.5; opacity:0.5; font-weight:bold; background: red; position: absolute; } 17 </style> 18 </head> 19 <body> 20 <ul id="tabs" > 21 <li type="draw" class="sec">画矩形框</li> 22 <li type="drag">拖到矩形框</li> 23 </ul> 24 <div id="parent"> 25 </div> 26 <div id="state"></div> 27 <script type="text/javascript"> 28 var parent = document.getElementById('parent'), 29 tabs = document.getElementById('tabs'), 30 state = document.getElementById('state'), 31 con = document.getElementById('content'), 32 li = tabs.getElementsByTagName('li'), 33 type = 'draw'; //drag 34 35 tabs.addEventListener('click', function (e) { 36 for (var i = 0; i < li.length; i++) { 37 var el = li[i]; 38 el.className = ''; 39 var s = ''; 40 } 41 var cur_el = e.target; 42 cur_el.className = 'sec'; 43 type = cur_el.type; 44 45 var s = ''; 46 }, false); 47 48 parent.addEventListener('mousedown', function (e) { 49 var scope = this; 50 if (type == 'draw') { 51 (function () { 52 var el = e.target, //当前点击元素,父div或者拖到div 53 x = e.clientX, 54 y = e.clientY, 55 offsetTop = scope.offsetTop, 56 offsetLeft = scope.offsetLeft; 57 var div_x = x - offsetLeft, 58 div_y = y - offsetTop; 59 var div = document.createElement('div'); 60 var style = 'left: ' + div_x + 'px; top: ' + div_y + 'px;'; 61 div.setAttribute('style', style); 62 div.innerHTML = scope.getElementsByTagName('div').length; 63 scope.appendChild(div); 64 var func_move = function (ee) { 65 var x1 = ee.clientX, 66 y1 = ee.clientY; 67 var w = x1 - x; 68 var h = y1 - y; 69 if (w > 5 || h > 5) { 70 div.setAttribute('style', style + 'width: ' + w + 'px; height: ' + h + 'px;'); 71 } 72 }; 73 var func_up = function (ee) { 74 document.removeEventListener('mousemove', func_move, false); 75 document.removeEventListener('mouseup', func_up, false); 76 }; 77 document.addEventListener('mousemove', func_move, false); 78 document.addEventListener('mouseup', func_up, false); 79 })(); 80 81 } else { 82 (function () { 83 var el = e.target; //当前点击元素,父div或者拖到div 84 var x1 = e.clientX - el.offsetLeft; 85 var y1 = e.clientY - el.offsetTop; 86 87 var func_move = function (ee) { 88 var cur_el = ee.target; 89 if (cur_el.id && cur_el.id == 'parent') return false; 90 var x2 = 0; 91 var y2 = 0; 92 93 x2 = ee.clientX - x1 ; 94 y2 = ee.clientY - y1 ; 95 x2 = x2 > 0 ? x2 : 0; 96 y2 = y2 > 0 ? y2 : 0; 97 98 if (Math.abs(x2) > 5 || Math.abs(y2) > 5) { 99 cur_el.style.top = (y2) + 'px'; 100 cur_el.style.left = (x2) + 'px'; 101 } 102 }; 103 104 var func_up = function (ee) { 105 el.removeEventListener('mousemove', func_move, false); 106 el.removeEventListener('mouseup', func_up, false); 107 }; 108 el.addEventListener('mousemove', func_move, false); 109 el.addEventListener('mouseup', func_up, false); 110 })(); 111 } 112 113 }, false); 114 </script> 115 </body> 116 </html>
结语
小弟对冒泡机制理解还是很浅的,若是各位大哥看到此文觉得有什么不足,或者有什么问题,请一定指出来哦。
另外那道题建议各位做下,我那个代码写得有点水,期待高质量的代码。。。。
如果你觉得这篇文章还不错,请帮忙点击一下推荐,谢谢!
相关推荐
本段代码演示了如何使用JavaScript取消HTML事件的冒泡,即当后代元素的事件被触发时,祖先元素的相同事件也会被触发。代码中,页面包含一个div元素和一个嵌套在其中的span元素,分别设置了单击响应函数。当单击span...
一种解决事件冒泡的方法,有较好的浏览器兼容性,具体思路参见文档: http://blog.csdn.net/ivyandrich/article/details/22041933
javascript事件冒泡,事件捕获和事件委托详解 1、事件冒泡:在javascript事件传播过程中,当事件在一个元素上出发之后,事件会逐级传播给先辈元素,直到document为止,有的浏览器可能到window为止。并不是所有的...
JavaScript中事件冒泡机制示例详析 DOM事件流(event flow )存在三个阶段:事件捕获阶段、 处于目标阶段、 事件冒泡阶段。 事件捕获(event capturing):通俗的理解就是,当鼠标点击或者触发dom事件时,...
javascript 中事件冒泡和事件捕获机制的详解 二者作用:描述事件触发时序问题 事件捕获:从document到触发事件的那个节点,即自上而下的去触发事件—由外到内 事件冒泡:自下而上的去触发事件—由内到外 绑定事件...
事件冒泡、事件捕获和事件委托 在javascript里,事件委托是很重要的一个东西,事件委托依靠的就是事件冒泡和捕获的机制,我先来解释一下事件冒泡和事件捕获: 事件冒泡会从当前触发的事件目标一级一级往上传递,...
JavaScript事件冒泡示例,简单,明了,实用。
之所以会有此篇文章当然还要从最近的一次面试说起,很抱歉居然又扯到面试上去看,其实不要说,平时不注意的东西,往往在面试时便会立马给你揪出来哪里有问题。比如我当时就小小的栽了个跟头,栽跟头不要紧,要紧的是...
事件是javascript中的核心内容之一,在对事件的应用中不可避免的要涉及到一个重要的概念,那就是事件冒泡,在介绍事件冒泡之前,先介绍一下另一个重要的概念事件流: 一.什么是事件流: 文档对象模型(DOM)是一个树...
JavaScript+jQuery 网页特效设计;鼠标事件;1、鼠标事件;1、鼠标事件(案例);2、键盘事件;2、键盘事件(案例);3、事件的冒泡与阻止;3、事件的冒泡与阻止;3、事件的冒泡与阻止;3、事件的冒泡与阻止;3、事件的冒泡与...
JavaScript之DOM事件(源代码)JavaScript之DOM事件(源代码)JavaScript之DOM事件(源代码)JavaScript之DOM事件(源代码)JavaScript之DOM事件(源代码)JavaScript之DOM事件(源代码)JavaScript之DOM事件(源...
然而,在今天一些大型的WEB交互项目中,比如大型的WebGame项目,JavaScript事件冒泡影响是值得重视的。本文通过一个简单的例子来讲解JavaScript事件冒泡及使用注意事项。 如果你对JavaScript事件冒泡还没有什么印象...
一、什么是事件冒泡 在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回true,那么这个事件会向这个...
JavaScript 事件机制详细研究 JavaScript 事件机制是指浏览器中发生的各种事件,例如点击、鼠标悬停、键盘输入等,JavaScript 通过捕捉这些事件来执行相应的操作。本文将详细介绍 JavaScript 事件机制的实现方式和...
Javascript学习日记-阻止javascript事件冒泡,获取控件ID值
1.实现JavaScript事件注册;...2.实现JavaScript事件处理函数; 3.实现JavaScript鼠标和键盘事件; 4.实现JavaScript表单相关事件; 5.实现JavaScript字幕滚动事件; 6.实现JavaScript编辑事件;
主要介绍了javaScript 事件绑定、事件冒泡、事件捕获和事件执行顺序整理总结的相关资料,需要的朋友可以参考下
直接运行html 文件即可,第一个文本框为要排序的数字,第二位为排序后的现实的地方