<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>事件冒泡、事件捕获、事件委托 on Last Stand</title><link>https://amatsuzero.github.io/LastStand/tags/%E4%BA%8B%E4%BB%B6%E5%86%92%E6%B3%A1%E4%BA%8B%E4%BB%B6%E6%8D%95%E8%8E%B7%E4%BA%8B%E4%BB%B6%E5%A7%94%E6%89%98/</link><description>Recent content in 事件冒泡、事件捕获、事件委托 on Last Stand</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Fri, 08 Nov 2024 00:00:00 +0800</lastBuildDate><atom:link href="https://amatsuzero.github.io/LastStand/tags/%E4%BA%8B%E4%BB%B6%E5%86%92%E6%B3%A1%E4%BA%8B%E4%BB%B6%E6%8D%95%E8%8E%B7%E4%BA%8B%E4%BB%B6%E5%A7%94%E6%89%98/index.xml" rel="self" type="application/rss+xml"/><item><title>事件冒泡、事件捕获、事件委托</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/</guid><description>&lt;p&gt;&lt;code&gt;DOM&lt;/code&gt;事件流（&lt;code&gt;event flow&lt;/code&gt; ）存在三个阶段：事件捕获阶段、处于目标阶段、事件冒泡阶段。&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-01.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Dom&lt;/code&gt;标准事件流的触发的先后顺序为：先捕获再冒泡。即当触发&lt;code&gt;dom&lt;/code&gt;事件时，会先进行事件捕获，捕获到事件源之后通过事件传播进行事件冒泡。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;addEventListener的第三个参数&lt;/strong&gt;&lt;br&gt;
在我们平常用的&lt;code&gt;addEventListener&lt;/code&gt;方法中，一般只会用到两个参数，一个是需要绑定的事件，另一个是触发事件后要执行的函数，然而&lt;code&gt;addEventListener&lt;/code&gt;还可以传入第三个参数：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;element&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;addEventListener&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;event&lt;/span&gt;, &lt;span style="color:#66d9ef"&gt;function&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;useCapture&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第三个参数默认值是&lt;code&gt;false&lt;/code&gt;，表示在事件冒泡阶段调用事件处理函数;如果参数为&lt;code&gt;true&lt;/code&gt;，则表示在事件捕获阶段调用处理函数。如果不写第三个参数则默认在事件冒泡阶段调用事件处理函数。&lt;/p&gt;
&lt;p&gt;下面先介绍事件冒泡：&lt;/p&gt;
&lt;h2 id="1-事件冒泡"&gt;1. 事件冒泡&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;事件冒泡（dubbed bubbling）&lt;/code&gt;：当一个元素接收到事件的时候，会把他接收到的事件传给自己的父级，一直到 &lt;code&gt;window&lt;/code&gt; （注意这里传递的仅仅是事件，例如&lt;code&gt;click、focus&lt;/code&gt;等等这些事件， 并不传递所绑定的事件函数。）&lt;/p&gt;
&lt;p&gt;事件源 =&amp;gt;根节点（由内到外）进行事件传播。&lt;/p&gt;
&lt;p&gt;举例说明：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-02.webp"&gt;&lt;/p&gt;
&lt;p&gt;给三个盒子依次绑定点击事件，当点击盒子的时候，会依次触发父级元素的点击事件。 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-03.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click small box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-04.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click center box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-05.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click big box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-06.webp"&gt;&lt;/p&gt;
&lt;p&gt;如果父元素没有绑定点击事件则只会触发点击盒子的事件。 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-07.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click small box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-08.webp"&gt;&lt;/p&gt;
&lt;p&gt;如果子元素（&lt;code&gt;small&lt;/code&gt;）的点击事件去掉，当我们点击&lt;code&gt;small&lt;/code&gt;的时候会把当前操作的点击事件传递给父元素（因为父元素绑定了点击函数） &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-09.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click small box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-10.webp"&gt;&lt;/p&gt;
&lt;p&gt;有些时候我们不希望产生事件冒泡，所以可以 &lt;strong&gt;在子事件中加入e.stopPropagation()&lt;/strong&gt; 取消冒泡 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-11.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click small box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-12.webp"&gt;&lt;/p&gt;
&lt;h2 id="2-事件捕获"&gt;2. 事件捕获&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;事件捕获（event capturing）&lt;/code&gt;： 当鼠标点击或者触发&lt;code&gt;dom&lt;/code&gt;事件时（被触发&lt;code&gt;dom&lt;/code&gt;事件的这个元素被叫作事件源），浏览器会从根节点 =&amp;gt;事件源（由外到内）进行事件传播。&lt;/p&gt;
&lt;p&gt;事件捕获与事件冒泡是比较类似的，最大的不同在于事件传播的方向。&lt;/p&gt;
&lt;p&gt;还是举上面的例子： &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-13.webp"&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;click small box&lt;/code&gt; &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-14.webp"&gt;&lt;/p&gt;
&lt;h2 id="3-事件委托"&gt;3. 事件委托&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;事件委托&lt;/code&gt;也称为&lt;code&gt;事件代理&lt;/code&gt;。就是利用&lt;code&gt;事件冒泡&lt;/code&gt;，把子元素的事件都绑定到父元素上。如果子元素阻止了事件冒泡，那么委托就无法实现。&lt;/p&gt;
&lt;p&gt;原理实现：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;不是每个子节点单独设置事件监听器&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;而是事件监听器设置在其父节点上&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;，&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;然后利用冒泡原理影响设置每个子节点&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;应用场景：&lt;code&gt;1000&lt;/code&gt;个&lt;code&gt;button&lt;/code&gt;需要注册点击事件&lt;/p&gt;
&lt;p&gt;如果循环给每个按钮添加点击事件，那么会增加内存损耗，影响性能 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-15.webp"&gt;&lt;/p&gt;
&lt;p&gt;此时可以给&lt;code&gt;button&lt;/code&gt;的父元素添加点击事件 &lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-16.webp"&gt;&lt;/p&gt;
&lt;p&gt;这时相当于每个按钮都绑定了点击事件&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-018/image-17.webp"&gt;&lt;/p&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;替代循环绑定事件的操作，减少内存消耗，提高性能。比如：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;在&lt;code&gt;table&lt;/code&gt;上代理所有&lt;code&gt;td&lt;/code&gt;的&lt;code&gt;click&lt;/code&gt;事件。&lt;/li&gt;
&lt;li&gt;在&lt;code&gt;ul&lt;/code&gt;上代理所有&lt;code&gt;li&lt;/code&gt;的&lt;code&gt;click&lt;/code&gt;事件。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="2"&gt;
&lt;li&gt;简化了&lt;code&gt;dom&lt;/code&gt;节点更新时，相应事件的更新。比如：&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;不用在新添加的&lt;code&gt;li&lt;/code&gt;上绑定&lt;code&gt;click&lt;/code&gt;事件。&lt;/li&gt;
&lt;li&gt;当删除某个&lt;code&gt;li&lt;/code&gt;时，不用移解绑上面的&lt;code&gt;click&lt;/code&gt;事件。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缺点：&lt;/p&gt;</description></item></channel></rss>