由event target引发的关于事件流的一连串思考(二)
阻止事件冒泡
W3C的方法是ev.stopPropagation(),IE則是使用ev.cancelBubble = true。
先不談IE的私有方法,首先討論一個問題:ev.stopPropagation()真的是阻止事件冒泡嗎?
實際上,這個問題需要分兩種情況來討論:
此時輸出結果如下:
可以看到阻止事件冒泡成功了,證明DOM0確實是阻止事件冒泡。此時點擊內層圓,輸出結果如下:
我們將 ul.addEventListener('click',function(ev){console.log("ul 冒泡"); }); 復制代碼改為
ul.addEventListener('click',function(ev){console.log("ul 冒泡");ev.stopPropagation(); }); 復制代碼此時點擊內層圓,輸出結果如下:
可以看到本來會冒泡到div上的點擊事件被阻止了,此時跟DOM0的阻止事件冒泡是一致的。 但是如果我們改為阻止在ul的捕獲事件上阻止事件冒泡的話,事件捕獲還會進行嗎?還是只會阻止冒泡?我們來測試一下,將 ul.addEventListener('click',function(ev){console.log("ul 捕獲"); },true); 復制代碼改為
ul.addEventListener('click',function(ev){console.log("ul 捕獲");ev.stopPropagation(); },true); 復制代碼此時的輸出結果如下:
可以看到,不但冒泡的整個階段被阻止了,而且li的事件捕獲也被阻止了。所以總結一下這兩點,ev.stopPropagation()不止可以阻止事件冒泡,如果在捕獲階段使用還可以阻止事件捕獲。
那么我們再考慮一種特殊情況:如果ev.stopPropagation()在target階段執行會是什么情況,代碼如下。 JavaScript:
div.addEventListener('click',function(){console.log("div 捕獲"); },true); ul.addEventListener('click',function(ev){console.log("ul 捕獲"); },true); li.addEventListener('click',function(ev){console.log("li 捕獲");ev.stopPropagation(); },true); div.addEventListener('click',function(ev){console.log("div 冒泡"); }); ul.addEventListener('click',function(ev){console.log("ul 冒泡"); }); li.addEventListener('click',function(ev){console.log("li 冒泡"); }); 復制代碼我們在target上阻止了事件監聽,這樣整個事件冒泡應該是被阻止的,我們看輸出結果:
target的冒泡仍然執行了,其實原因很簡單,我們在上一章已經提到了,就不多做贅述了。阻止事件冒泡的兼容寫法:
if(event.stopPropagation){event.stopPropagation(); }else{event.cancelBubble = true; } 復制代碼阻止默認事件
這個沒什么好講的,用于阻止瀏覽器默認的事件,比如提交按鈕的點擊默認提交,a標簽的點擊跳轉等。不過之前遇到過一個問題,在jsp里無法阻止提交按鈕的提交事件,最后還是換成了div然后使用form.submit()提交才通過。 兼容寫法如下:
if(event.preventDefault){// W3C的阻止默認事件event.preventDefault(); }else{// IE私有的阻止默認事件event.returnValue = false; } 復制代碼事件流的常見應用:事件委托
事件委托就是利用事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件。
阻止事件冒泡應用
有一個很應景的例子,頁面有一個彈出框,可拖拽,彈出框內有一個input框,這個框內輸入的文字要可以選中。 我們先來實現頁面結構和拖拽功能,代碼如下:
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Document</title><style>*{margin: 0;padding: 0;}div{position: absolute;width: 300px;height: 100px;background-color: #2578b5;box-sizing: border-box;padding: 30px;}input{width: 100%;line-height: 1.6em;font-size: 16px;}</style> </head> <body><div><input type="text" value="用于復制的文本"></div><script>var div = document.querySelector('div');var input = document.querySelector('input');div.onmousedown = function(ev){var mouseLeftDiv = ev.clientX - div.offsetLeft;var mouseTopDiv = ev.clientY - div.offsetTop;document.onmousemove = function(ev){var divLeftBody = ev.clientX - mouseLeftDiv;var divTopBody = ev.clientY - mouseTopDiv;var docWidth = document.documentElement.clientWidth;var docHeight = document.documentElement.clientHeight;if(divLeftBody <= 0){divLeftBody = 0;}else if(divLeftBody >= docWidth - div.offsetWidth){divLeftBody = docWidth - div.offsetWidth;};if(divTopBody <= 0){divTopBody = 0;}else if(divTopBody >= docHeight - div.offsetHeight){divTopBody = docHeight - div.offsetHeight;};div.style.left = divLeftBody + 'px';div.style.top = divTopBody + 'px';}document.onmouseup = function(){document.onmousemove = null;}}</script> </body> </html> 復制代碼此時頁面如下:
拖拽功能實現了,但是我們發現想要復制文本的時候,沒有復制到,反而也觸發了拖拽功能,這就很尷尬了。這時我們的阻止事件冒泡就起作用了,我們在input框上阻止mousedown事件冒泡到外層,代碼如下: JavaScript:
input.onmousedown = function(ev){ev.stopPropagation(); } 復制代碼大功告成,此時既可以復制文本,外層又可以拖拽。
參考資料: http://www.cnblogs.com/liugang-vip/p/5616484.html http://www.cnblogs.com/libin-1/p/6368323.html
總結
以上是生活随笔為你收集整理的由event target引发的关于事件流的一连串思考(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微软发布Azure SignalR Se
- 下一篇: OO9-11总结