日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

JavaScript:事件对象Event和冒泡

發布時間:2024/4/14 javascript 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JavaScript:事件对象Event和冒泡 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文最初發表于博客園,并在GitHub上持續更新前端的系列文章。歡迎在GitHub上關注我,一起入門和進階前端。

以下是正文。

綁定事件的兩種方式

我們在上一篇文章 DOM操作詳解 中已經講過事件的概念。這里講一下注冊事件的兩種方式,我們以onclick事件為例。

方式一:onclick

舉例:

<body> <button>點我</button> <script>var btn = document.getElementsByTagName("button")[0];//這種事件綁定的方法容易被層疊。btn.onclick = function () {console.log("事件1");}btn.onclick = function () {console.log("事件2");}</script> </body>

點擊按鈕后,上方代碼的打印結果:

事件2

我們可以看到,這種綁定事件的方式,會層疊掉之前的事件。

方式二:addEventListener

addEventListener()里的參數:

  • 參數1:事件名(注意,沒有on)

  • 參數2:事件名(執行函數)

  • 參數3:事件名(捕獲或者冒泡)

舉例:

<body> <button>按鈕</button> <script>var btn = document.getElementsByTagName("button")[0];//addEventListener: 事件監聽器。 原事件被執行的時候,后面綁定的事件照樣被執行//第二種事件綁定的方法不會出現層疊。(更適合團隊開發)btn.addEventListener("click", fn1);btn.addEventListener("click", fn2);function fn1() {console.log("事件1");}function fn2() {console.log("事件2");}</script> </body>

點擊按鈕后,上方代碼的打印結果:

事件1事件2

我們可以看到,這種綁定事件的方式,不會層疊掉之前的事件。

事件對象

在觸發DOM上的某個事件時,會產生一個事件對象event,這個對象中包含著所有與事件有關的信息。比如鼠標操作時候,會添加鼠標位置的相關信息到事件對象中。

所有瀏覽器都支持event對象,但支持的方式不同。如下。

(1)普通瀏覽器支持 event。比如:

(2)ie 678 支持 window.event。

于是,我們可以采取一種兼容性的寫法。如下:

event = event || window.event; 兼容性寫法

代碼舉例:

<!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title> </head> <body> <script>//點擊頁面的任何部分document.onclick = function (event) {event = event || window.event; 兼容性寫法console.log(event);console.log(event.timeStamp);console.log(event.bubbles);console.log(event.button);console.log(event.pageX);console.log(event.pageY);console.log(event.screenX);console.log(event.screenY);console.log(event.target);console.log(event.type);console.log(event.clientX);console.log(event.clientY);} </script> </body> </html>

event 屬性

event 有很多屬性,比如:

由于pageX 和 pageY的兼容性不好,我們可以這樣做:

  • 鼠標在頁面的位置 = 被卷去的部分+可視區域部分。

Event舉例

舉例1:鼠標跟隨

代碼實現:

<!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title><style>body {height: 5000px;}img {position: absolute;padding: 10px 0;border: 1px solid #ccc;cursor: pointer;background-color: yellowgreen;}</style> </head> <body> <img src="" width="100" height="100"/><script>//需求:點擊頁面的任何地方,圖片跟隨鼠標移動到點擊位置。//思路:獲取鼠標在頁面中的位置,然圖片緩慢運動到鼠標點擊的位置。// 兼容ie67做pageY和pageX;// 原理: 鼠標在頁面的位置 = 被卷去的部分+可視區域部分。//步驟://1.老三步。//2.獲取鼠標在頁面中的位置。//3.利用緩動原理,慢慢的運動到指定位置。(包括左右和上下)//1.老三步。var img = document.getElementsByTagName("img")[0];var timer = null;var targetx = 0;var targety = 0;var leaderx = 0;var leadery = 0;//給整個文檔綁定點擊事件獲取鼠標的位置。document.onclick = function (event) {//新五步//兼容獲取事件對象event = event || window.event;//鼠標在頁面的位置 = 被卷去的部分+可視區域部分。var pagey = event.pageY || scroll().top + event.clientY;var pagex = event.pageX || scroll().left + event.clientX;targety = pagey - 30;targetx = pagex - 50;//要用定時器,先清定時器clearInterval(timer);timer = setInterval(function () {//為盒子的位置獲取值leaderx = img.offsetLeft;//獲取步長var stepx = (targetx - leaderx) / 10;//二次處理步長stepx = stepx > 0 ? Math.ceil(stepx) : Math.floor(stepx);leaderx = leaderx + stepx;//賦值img.style.left = leaderx + "px";//為盒子的位置獲取值leadery = img.offsetTop;//獲取步長var stepy = (targety - leadery) / 10;//二次處理步長stepy = stepy > 0 ? Math.ceil(stepy) : Math.floor(stepy);leadery = leadery + stepy;//賦值img.style.top = leadery + "px";//清定時器if (Math.abs(targety - img.offsetTop) <= Math.abs(stepy) && Math.abs(targetx - img.offsetLeft) <= Math.abs(stepx)) {img.style.top = targety + "px";img.style.left = targetx + "px";clearInterval(timer);}}, 30);}</script></body> </html>

實現效果:

event應用舉例:獲取鼠標距離所在盒子的距離

關鍵點:

鼠標距離所在盒子的距離 = 鼠標在整個頁面的位置 - 所在盒子在整個頁面的位置

代碼演示:

<!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title><style>.box {width: 300px;height: 200px;padding-top: 100px;background-color: pink;margin: 100px;text-align: center;font: 18px/30px "simsun";cursor: pointer;}</style> </head> <body> <div class="box"></div><script src="animate.js"></script> <script>//需求:鼠標進入盒子之后只要移動,哪怕1像素,隨時顯示鼠標在盒子中的坐標。//技術點:新事件,onmousemove:在事件源上,哪怕鼠標移動1像素也會觸動這個事件。//一定程度上,模擬了定時器//步驟://1.老三步和新五步//2.獲取鼠標在整個頁面的位置//3.獲取盒子在整個頁面的位置//4.用鼠標的位置減去盒子的位置賦值給盒子的內容。//1.老三步和新五步var div = document.getElementsByTagName("div")[0];div.onmousemove = function (event) {event = event || window.event;//2.獲取鼠標在整個頁面的位置var pagex = event.pageX || scroll().left + event.clientX;var pagey = event.pageY || scroll().top + event.clientY;//3.獲取盒子在整個頁面的位置// var xx =// var yy =//4.用鼠標的位置減去盒子的位置賦值給盒子的內容。var targetx = pagex - div.offsetLeft;var targety = pagey - div.offsetTop;this.innerHTML = "鼠標在盒子中的X坐標為:" + targetx + "px;<br>鼠標在盒子中的Y坐標為:" + targety + "px;"}</script> </body> </html>

實現效果:

舉例:商品放大鏡

代碼實現:

(1)index.html:

<!DOCTYPE html> <html> <head lang="en"><meta charset="UTF-8"><title></title><style>* {margin: 0;padding: 0;}.box {width: 350px;height: 350px;margin: 100px;border: 1px solid #ccc;position: relative;}.big {width: 400px;height: 400px;position: absolute;top: 0;left: 360px;border: 1px solid #ccc;overflow: hidden;display: none;}/*mask的中文是:遮罩*/.mask {width: 175px;height: 175px;background: rgba(255, 255, 0, 0.4);position: absolute;top: 0;left: 0;cursor: move;display: none;}.small {position: relative;}img {vertical-align: top;}</style><script src="tools.js"></script><script>window.onload = function () {//需求:鼠標放到小盒子上,讓大盒子里面的圖片和我們同步等比例移動。//技術點:onmouseenter==onmouseover 第一個不冒泡//技術點:onmouseleave==onmouseout 第一個不冒泡//步驟://1.鼠標放上去顯示盒子,移開隱藏盒子。//2.老三步和新五步(黃盒子跟隨移動)//3.右側的大圖片,等比例移動。//0.獲取相關元素var box = document.getElementsByClassName("box")[0];var small = box.firstElementChild || box.firstChild;var big = box.children[1];var mask = small.children[1];var bigImg = big.children[0];//1.鼠標放上去顯示盒子,移開隱藏盒子。(為小盒子綁定事件)small.onmouseenter = function () {//封裝好方法調用:顯示元素show(mask);show(big);}small.onmouseleave = function () {//封裝好方法調用:隱藏元素hide(mask);hide(big);}//2.老三步和新五步(黃盒子跟隨移動)//綁定的事件是onmousemove,而事件源是small(只要在小盒子上移動1像素,黃盒子也要跟隨)small.onmousemove = function (event) {//新五步event = event || window.event;//想要移動黃盒子,必須要知道鼠標在small小圖中的位置。var pagex = event.pageX || scroll().left + event.clientX;var pagey = event.pageY || scroll().top + event.clientY;//x:mask的left值,y:mask的top值。var x = pagex - box.offsetLeft - mask.offsetWidth / 2; //除以2,可以保證鼠標mask的中間var y = pagey - box.offsetTop - mask.offsetHeight / 2;//限制換盒子的范圍//left取值為大于0,小盒子的寬-mask的寬。if (x < 0) {x = 0;}if (x > small.offsetWidth - mask.offsetWidth) {x = small.offsetWidth - mask.offsetWidth;}//top同理。if (y < 0) {y = 0;}if (y > small.offsetHeight - mask.offsetHeight) {y = small.offsetHeight - mask.offsetHeight;}//移動黃盒子console.log(small.offsetHeight);mask.style.left = x + "px";mask.style.top = y + "px";//3.右側的大圖片,等比例移動。//如何移動大圖片?等比例移動。// 大圖片/大盒子 = 小圖片/mask盒子// 大圖片走的距離/mask走的距離 = (大圖片-大盒子)/(小圖片-黃盒子) // var bili = (bigImg.offsetWidth-big.offsetWidth)/(small.offsetWidth-mask.offsetWidth);//大圖片走的距離/mask盒子都的距離 = 大圖片/小圖片var bili = bigImg.offsetWidth / small.offsetWidth;var xx = bili * x; //知道比例,就可以移動大圖片了var yy = bili * y;bigImg.style.marginTop = -yy + "px";bigImg.style.marginLeft = -xx + "px";}}</script> </head> <body> <div class="box"><div class="small"><img src="images/001.jpg" alt=""/><div class="mask"></div></div><div class="big"><img src="images/0001.jpg" alt=""/></div> </div> </body> </html>

(2)tools.js:

/*** Created by smyhvae on 2018/02/03.*///顯示和隱藏 function show(ele) {ele.style.display = "block"; }function hide(ele) {ele.style.display = "none"; }function scroll() { // 開始封裝自己的scrollTopif (window.pageYOffset != null) { // ie9+ 高版本瀏覽器// 因為 window.pageYOffset 默認的是 0 所以這里需要判斷return {left: window.pageXOffset,top: window.pageYOffset}}else if (document.compatMode === "CSS1Compat") { // 標準瀏覽器 來判斷有沒有聲明DTDreturn {left: document.documentElement.scrollLeft,top: document.documentElement.scrollTop}}return { // 未聲明 DTDleft: document.body.scrollLeft,top: document.body.scrollTop} }

效果演示:

事件冒泡

事件傳播的三個階段是:事件捕獲、事件冒泡和目標。

  • 事件捕獲階段:事件從最上一級標簽開始往下查找,直到捕獲到事件目標 target。(從祖先元素往子元素查找,DOM樹結構)。在這個過程中,事件相應的監聽函數是不會被觸發的。

  • 事件目標:當到達目標元素之后,執行目標元素該事件相應的處理函數。如果沒有綁定監聽函數,那就不執行。

  • 事件冒泡階段:事件從事件目標 target 開始,往上冒泡直到頁面的最上一級標簽。(從子元素到祖先元素冒泡)

如下圖所示:

PS:這個概念類似于 Android 里的 touch 事件傳遞

事件冒泡的概念

事件冒泡: 當一個元素上的事件被觸發的時候(比如說鼠標點擊了一個按鈕),同樣的事件將會在那個元素的所有祖先元素中被觸發。這一過程被稱為事件冒泡;這個事件從原始元素開始一直冒泡到DOM樹的最上層。

通俗來講,冒泡指的是:子元素的事件被觸發時,父盒子的同樣的事件也會被觸發。取消冒泡就是取消這種機制。

代碼演示:

//事件冒泡box3.onclick = function () {alert("child");}box2.onclick = function () {alert("father");}box1.onclick = function () {alert("grandfather");}document.onclick = function () {alert("body");}

上圖顯示,當我點擊兒子 box3的時候,它的父親box2、box1、body都依次被觸發了。即使我改變代碼的順序,也不會影響效果的順序。

冒泡順序

一般的瀏覽器: (除IE6.0之外的瀏覽器)

  • div -> body -> html -> document -> window

IE6.0:

  • div -> body -> html -> document

事件捕獲

addEventListener可以捕獲事件:

box1.addEventListener("click", function () {alert("捕獲 box3");}, true);

上面的方法中,參數為true,代表捕獲;參數為false或者不寫參數,代表冒泡。

代碼演示:

//參數為true,代表捕獲;參數為false或者不寫參數,代表冒泡box3.addEventListener("click", function () {alert("捕獲 child");}, true);box2.addEventListener("click", function () {alert("捕獲 father");}, true);box1.addEventListener("click", function () {alert("捕獲 grandfather");}, true);document.addEventListener("click", function () {alert("捕獲 body");}, true);

效果演示:

不是所有的事件都能冒泡

以下事件不冒泡:blur、focus、load、unload、onmouseenter、onmouseleave。意思是,事件不會往父元素那里傳遞。

我們檢查一個元素是否會冒泡,可以通過事件的以下參數:

event.bubbles

如果返回值為true,說明該事件會冒泡;反之則相反。

舉例:

box1.onclick = function (event) {alert("冒泡 child");event = event || window.event;console.log(event.bubbles); //打印結果:true}

阻止冒泡的方法

w3c的方法:(火狐、谷歌、IE11)

event.stopPropagation();

IE10以下則是:

event.cancelBubble = true

兼容代碼如下:

box3.onclick = function (event) {alert("child");//阻止冒泡event = event || window.event;if (event && event.stopPropagation) {event.stopPropagation();} else {event.cancelBubble = true;}}

上方代碼中,我們對box3進行了阻止冒泡,產生的效果是:事件不會繼續傳遞到 father、grandfather、body了。

事件委托

事件委托,通俗地來講,就是把一個元素響應事件(click、keydown......)的函數委托到另一個元素。

比如說有一個列表 ul,列表之中有大量的列表項 li,我們需要在點擊列表項li的時候響應一個事件。如果給每個列表項一一都綁定一個函數,那對于內存消耗是非常大的,效率上需要消耗很多性能。

因此,比較好的方法就是把這個點擊事件綁定到他的父層,也就是 ul 上,然后在執行事件的時候再去匹配判斷目標元素。

所以事件委托可以減少大量的內存消耗,節約效率。

事件委托的參考鏈接:JavaScript 事件委托詳解

我的公眾號

想學習代碼之外的軟技能?不妨關注我的微信公眾號:生命團隊(id:vitateam)。

掃一掃,你將發現另一個全新的世界,而這將是一場美麗的意外:

轉載于:https://www.cnblogs.com/qianguyihao/p/8413602.html

總結

以上是生活随笔為你收集整理的JavaScript:事件对象Event和冒泡的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。