Js 事件原理與事件委托


事件原理三階段

捕獲(由外向內)、目標、冒泡(由內向外)

事件冒泡(event bubbling),即事件開始時由最具體的元素(文檔中嵌套層次最深的那個節點)接收,然后逐級向上傳播到較為不具體的節點(文檔)。即子標簽發生事件后,向父級發送該事件,一直追溯到document。如:點擊一個嵌套在 body中的button,則該button的onclick事件也會傳遞給body、document中,觸發他們的onclick里觸發的函數。

案例

    <style>
        div{
            position: absolute;
            left:0;
            right:0;
            top:0;
            bottom:0;
        }
        .div0
        {
            width: 200px;
            height: 200px;
            background-color: skyblue;
            margin: auto;
        }
        .div1{
            width: 100px;
            height: 100px;
            background-color: yellowgreen;
            margin: auto;
        }
        .div2{
            width: 50px;
            height: 50px;
            background-color: orange;
            margin: auto;
        }
    </style>
</head>
<body>
    <div class="div0">
        <div class="div1">
            <div class="div2"></div>
        </div>
    </div>
    <script>
        
        div0.addEventListener("click",clickHandler0);
        div1.addEventListener("click",clickHandler1);
        div2.addEventListener("click",clickHandler2);

        function clickHandler0(e){
            console.log("點擊div0")
        }

        function clickHandler1(e){
            console.log("點擊div1")
        }

       
    </script>

三階段原理過程:

阻止事件冒泡

當對子元素添加了事件偵聽后,執行的時候會觸發父元素相同類型的事件,此時需要阻止事件冒泡。
早期IE是沒有捕獲階段的,只有冒泡,cancelBubble為阻止冒泡。后來的stopPropagaiton,既有阻止冒泡的功能,也有阻止捕獲的功能,但如果譯為阻止傳播,那么跟cancel就是兩個東西了,所以還是叫做阻止冒泡。阻止事件冒泡(傳播)的方法是:

  • e.stopPropagation();通用
  • e.cancelBubble=true;僅適用在IE8及以下
<script>

    div0.addEventListener("click",clickHandler0,true);//開啟捕獲時就執行
    div1.addEventListener("click",clickHandler1);
    div2.addEventListener("click",clickHandler2,true);//開啟捕獲時就執行

    function clickHandler2(e){
        console.log("點擊div2")
        // console.log(e);
        // 停止冒泡,后面的就不會冒泡了
        e.stopPropagation();
        // 僅適用在IE8及以下
        // e.cancelBubble=true;

    } 
/script>


div0.addEventListener(事件類型,事件回調函數,是否捕獲時執行);
事件類型 必須是字符串,可以設置為任意字符串,但是部分字符串是系統事件類型
事件回調函數 指向一個函數,當收到事件時執行該函數,如果沒有收到不執行函數,寫偵聽事件時不執行函數
是否捕獲時執行 默認值是false,在冒泡時執行,捕獲時不執行,

點擊div2發現執行順序發生改變

事件委托

事件偵聽添加(注冊事件)占有內存的,盡量減少事件偵聽的數量,將子元素的事件委托給父元素來執行,叫做事件委托。
當刪除對象時,一定要將對象上的偵聽事件移除,否則會造成內存泄露。
應用於:在多個元素進行偵聽事件中,如果這些元素有容器嵌套關系,就需要考慮阻止冒泡。
當多個元素需要偵聽事件時,可以給這些元素的父容器增加事件,達到偵聽所有元素,即是事件委托效果。
案例:點擊 li ,讓其子元素 ul 切換顯示。

<body>
<ul id="skils">
<li>H5
    <ul>
        <li>JS
            <ul>
            <li>原生</li>
                <li>框架
                    <ul>
                        <li>VUEJs</li>
                        <li>ReactJs</li>
                        <li>AngularJs</li>
                    </ul>
                </li>
            <li>App</li>
            <li>小程序</li>
            <li>網頁開發</li>
            </ul>
        </li>
    </ul>
</li>
<li>JAVA</li>
<li>PHP</li>
<li>LINUX</li>
<li>PYTHON</li>
</ul>					
<script>
        //把子元素的偵聽事件全部委托給最外層的父元素,叫做事件委托

	init();

	function init(){
		var skils = document.getElementById("skils");
		//給父元素添加偵聽事件
		skils.addEventListener("click",clickHandler);
	}

	function clickHandler(e){
		//e.target 事件的目標 真實點擊到最終的目標對象
		//阻止冒泡,到此就結束,不再冒泡
		e.stopPropagation();
		//判斷點擊目標的節點名是不是“LI” ,不是就不執行 
		if(e.target.nodeName !== "LI") return;
		//判斷點擊目標有沒有子元素
		if(e.target.firstElementChild){
			// 設置開關,顯示和隱藏ul
			// 第一次默認是隱藏
			if(!e.target.bool){
				e.target.firstElementChild.style.display = "none";
			}else{
				e.target.firstElementChild.style.display = "block";
			}
			//點擊完后將e.target.bool 取反,進行顯示操作
			e.target.bool = !e.target.bool;
			}
		}
        </script>
</body>

擴展:

  • e.currentTarget 是事件偵聽事件對象(什么對象執行addEventListener函數就是誰)
  • e.target 事件的目標對象 真實點擊的最終目標對象
  • e.srcElement 事件的目標對象,兼容IE
  • 事件函數中this默認等同於e.currentTarget,都是事件偵聽的對象


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM