diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/zh-cn/web/api/eventtarget | |
parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
download | translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2 translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip |
initial commit
Diffstat (limited to 'files/zh-cn/web/api/eventtarget')
8 files changed, 1470 insertions, 0 deletions
diff --git a/files/zh-cn/web/api/eventtarget/addeventlistener/index.html b/files/zh-cn/web/api/eventtarget/addeventlistener/index.html new file mode 100644 index 0000000000..7414ff3c38 --- /dev/null +++ b/files/zh-cn/web/api/eventtarget/addeventlistener/index.html @@ -0,0 +1,684 @@ +--- +title: EventTarget.addEventListener() +slug: Web/API/EventTarget/addEventListener +tags: + - API + - DOM + - Event + - e.stopImmediatePropagation() + - once capture bubbling propagation + - '{{Non-standard_inline}}' + - 参考 + - 方法 +translation_of: Web/API/EventTarget/addEventListener +--- +<p>{{APIRef("DOM Events")}}</p> + +<p><strong>EventTarget.addEventListener() </strong>方法将指定的监听器注册到 {{domxref("EventTarget")}} 上,当该对象触发指定的事件时,指定的回调函数就会被执行。 事件目标可以是一个文档上的元素 {{domxref("Element")}},{{domxref("Document")}}和{{domxref("Window")}}或者任何其他支持事件的对象 (比如 <code><a href="/zh-cn/DOM/XMLHttpRequest" title="zh-cn/XMLHttpRequest">XMLHttpRequest</a></code>)<code>。</code></p> + +<p><code>addEventListener()</code>的工作原理是将实现{{domxref("EventListener")}}的函数或对象添加到调用它的{{domxref("EventTarget")}}上的指定事件类型的事件侦听器列表中。</p> + +<h2 id="Syntax" name="Syntax">语法</h2> + +<pre class="syntaxbox notranslate">target.addEventListener(type, listener, options); +<em>target</em>.addEventListener(<em>type</em>, <em>listener</em>, <em>useCapture</em>); +<em>target</em>.addEventListener(<em>type</em>, <em>listener</em>, <em>useCapture</em>, <em>wantsUntrusted </em>{{ +Non-standard_inline}}); // Gecko/Mozilla only +</pre> + +<dl> + <dt> + <h3 id="参数">参数</h3> + </dt> + <dt><code>type</code></dt> + <dd>表示监听<a href="/zh-CN/docs/Web/Events">事件类型</a>的字符串。</dd> + <dt><code>listener</code></dt> + <dd>当所监听的事件类型触发时,会接收到一个事件通知(实现了 {{domxref("Event")}} 接口的对象)对象。<code>listener</code> 必须是一个实现了 {{domxref("EventListener")}} 接口的对象,或者是一个<a href="/zh-CN/docs/Web/JavaScript/Guide/Functions">函数</a>。有关回调本身的详细信息,请参阅{{anch("The event listener callback")}} </dd> + <dt>options {{optional_inline}}</dt> + <dd>一个指定有关 <code>listener </code>属性的可选参数<strong>对象</strong>。可用的选项如下: + <ul> + <li><code>capture</code>: {{jsxref("Boolean")}},表示 <code>listener</code> 会在该类型的事件捕获阶段传播到该 <code>EventTarget</code> 时触发。</li> + <li><code>once</code>: {{jsxref("Boolean")}},表示 <code>listener 在添加之后最多只调用一次。如果是</code> <code>true,</code> <code>listener</code> 会在其被调用之后自动移除。</li> + <li><code>passive</code>: {{jsxref("Boolean")}},设置为true时,表示 <code>listener</code> 永远不会调用 <code>preventDefault()</code>。如果 listener 仍然调用了这个函数,客户端将会忽略它并抛出一个控制台警告。查看 {{anch("使用 passive 改善的滚屏性能")}} 了解更多.</li> + <li>{{non-standard_inline}}<code> mozSystemGroup</code>: 只能在 XBL 或者是 Firefox' chrome 使用,这是个 {{jsxref("Boolean")}},表示 <code>listener </code>被添加到 system group。</li> + </ul> + </dd> + <dt><code>useCapture</code> {{optional_inline}}</dt> + <dd>{{jsxref("Boolean")}},在DOM树中,注册了listener的元素, 是否要先于它下面的EventTarget,调用该listener。 当useCapture(设为true) 时,沿着DOM树向上冒泡的事件,不会触发listener。当一个元素嵌套了另一个元素,并且两个元素都对同一事件注册了一个处理函数时,所发生的事件冒泡和事件捕获是两种不同的事件传播方式。事件传播模式决定了元素以哪个顺序接收事件。进一步的解释可以查看 <a class="external" href="http://www.w3.org/TR/DOM-Level-3-Events/#event-flow" title="http://www.w3.org/TR/DOM-Level-3-Events/#event-flow">事件流</a> 及 <a href="http://www.quirksmode.org/js/events_order.html#link4">JavaScript Event order</a> 文档。 如果没有指定, <code>useCapture</code> 默认为 false 。 </dd> +</dl> + +<div class="note"><strong>注意:</strong> 对于事件目标上的事件监听器来说,事件会处于“目标阶段”,而不是冒泡阶段或者捕获阶段。在目标阶段的事件会触发该元素(即事件目标)上的所有监听器,而不在乎这个监听器到底在注册时<code>useCapture</code> 参数值是true还是false。</div> + +<div class="note"><strong>注意:</strong><span> </span><code>useCapture</code> 仅仅在现代浏览器最近的几个版本中是可选的。 例如 Firefox 6以前的版本都不是可选的。为了能够提供更广泛的支持,你应该提供这个参数。</div> + +<dl> + <dt><code>wantsUntrusted</code> {{Non-standard_inline}}</dt> + <dd>如果为 <code>true </code>, 则事件处理程序会接收网页自定义的事件。此参数只适用于 Gecko({{glossary("chrome")}}的默认值为true,其他常规网页的默认值为false),主要用于附加组件的代码和浏览器本身。</dd> +</dl> + +<h3 id="返回值">返回值</h3> + +<p><code>undefined</code>.</p> + +<h2 id="用法说明"><strong>用法说明</strong></h2> + +<h3 id="事件监听回调">事件监听回调</h3> + +<p>事件监听器可以被指定为回调函数或实现 {{domxref("EventListener")}}的对象,其{{domxref("EventListener.handleEvent", "handleEvent()")}} 方法用作回调函数。</p> + +<p>回调函数本身具有与<code>handleEvent()</code>方法相同的参数和返回值;也就是说,回调接受一个参数:一个基于{{domxref("Event")}} 的对象,描述已发生的事件,并且它不返回任何内容。</p> + +<p>例如,一个可用于处理{{event("fullscreenchange")}}和{{event("fullscreenerror")}}的事件处理函数可以像这样:</p> + +<pre class="brush: js notranslate">function eventHandler(event) { + if (event.type == fullscreenchange) { + /* handle a full screen toggle */ + } else /* fullscreenerror */ { + /* handle a full screen toggle error */ + } +}</pre> + +<h3 id="option支持的安全检测">option支持的安全检测</h3> + +<p>在旧版本的DOM的规定中, <code>addEventListener()</code>的第三个参数是一个布尔值表示是否在捕获阶段调用事件处理程序。随着时间的推移,很明显需要更多的选项。与其在方法之中添加更多参数(传递可选值将会变得异常复杂),倒不如把第三个参数改为一个包含了各种属性的对象,这些属性的值用来被配置删除事件侦听器的过程。</p> + +<p>因为旧版本的浏览器(以及一些相对不算古老的)仍然假定第三个参数是布尔值,你需要编写一些代码来有效地处理这种情况。你可以对每一个你感兴趣的options值进行特性检测。</p> + +<p>如果你想检测 <code>passive</code> 值可以参考下面这个例子:</p> + +<pre class="brush: js notranslate">var passiveSupported = false; + +try { + var options = Object.defineProperty({}, "passive", { + get: function() { + passiveSupported = true; + } + }); + + window.addEventListener("test", null, options); +} catch(err) {} +</pre> + +<p>这段代码为 <code>passive</code> 属性创建了一个带有getter函数的 <code>options</code> 对象;getter设定了一个标识, <code>passiveSupported</code>,被调用后就会把其设为<code>true</code>。那意味着如果浏览器检查 <code>options</code> 对象上的 <code>passive</code> 值时, <code>passiveSupported</code> 将会被设置为 <code>true</code>;否则它将保持 <code>false</code>。然后我们调用 <code>addEventListener()</code> 去设置一个指定这些选项的空事件处理器,这样如果浏览器将第三个参数认定为对象的话,这些选项值就会被检查。</p> + +<p>你可以利用这个方法检查options之中任一个值。只需使用与上面类似的代码,为选项设定一个getter。</p> + +<p>然后,当你想实际创建一个是否支持options的事件侦听器时,你可以这样做:</p> + +<pre class="brush: js notranslate">someElement.addEventListener("mouseup", handleMouseUp, passiveSupported + ? { passive: true } : false); +</pre> + +<p>我们在 <code>someElement</code> 这里添加了一个{{event("mouseup")}}。对于第三个参数,如果 <code>passiveSupported</code> 是 <code>true</code> ,我们传递了一个 <code>passive</code> 值为 <code>true</code> 的 <code>options</code> 对象;如果相反的话,我们知道要传递一个布尔值,于是就传递 <code>false</code> 作为 <code>useCapture</code> 的参数。</p> + +<p>如果你愿意,你可以用一个类似 <a href="https://modernizr.com/docs">Modernizr</a> 或 <a href="https://github.com/rafrex/detect-it">Detect It</a> 的第三方库来帮助你做这项测试。</p> + +<p>你可以在 <a href="https://wicg.github.io/admin/charter.html">Web Incubator Community Group</a> 里关于<code><a href="https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection">EventListenerOptions</a></code> 的文章中了解更多。</p> + +<h2 id="Example" name="Example">示例</h2> + +<h3 id="添加一个简单的监听器">添加一个简单的监听器</h3> + +<p class="syntaxbox">下面这个例子用来展示如何使用 <code>addEventListener()</code> 监听鼠标点击一个元素。</p> + +<pre class="brush: html notranslate"><table id="outside"> + <tr><td id="t1">one</td></tr> + <tr><td id="t2">two</td></tr> +</table> +</pre> + +<pre class="brush: js notranslate">// 改变t2的函数 +function modifyText() { + var t2 = document.getElementById("t2"); + if (t2.firstChild.nodeValue == "three") { + t2.firstChild.nodeValue = "two"; + } else { + t2.firstChild.nodeValue = "three"; + } +} + +// 为table添加事件监听器 +var el = document.getElementById("outside"); +el.addEventListener("click", modifyText, false); +</pre> + +<p>在上个例子中,<code>modifyText()</code> 是一个 <code>click</code> 事件的监听器,通过使用<code>addEventListenter()</code>注册到table对象上。在表格中任何位置单击都会触发事件并执行<code>modifyText()</code>。</p> + +<h4 id="结果">结果</h4> + +<p>{{EmbedLiveSample('添加一个简单的监听器')}}</p> + +<h3 id="带有匿名函数的监听器">带有匿名函数的监听器</h3> + +<p>现在我们来看看如何使用匿名函数来为事件监听器进行传参。</p> + +<pre class="brush: html language-html notranslate"><table id="outside"> + <tr><td id="t1">one</td></tr> + <tr><td id="t2">two</td></tr> +</table> +</pre> + +<pre class="brush: js language-js notranslate">// 改变t2值的函数 +function modifyText(new_text) { + var t2 = document.getElementById("t2"); + t2.firstChild.nodeValue = new_text; +} + +// 为table对象添加事件监听器 +var el = document.getElementById("outside"); +el.addEventListener("click", function(){modifyText("four")}, false);</pre> + +<p>请注意,侦听器是一个匿名函数,它封装了代码,然后代码可以将参数发送到<code>modifyText()</code>函数,该函数负责实际响应事件。</p> + +<h4 id="结果_2">结果</h4> + +<p>{{EmbedLiveSample('带有匿名函数的监听器')}}</p> + +<h3 id="带有箭头函数的监听器">带有箭头函数的监听器</h3> + +<p>这个例子用来展示如何通过箭头函数来实现一个监听器。</p> + +<h4 id="HTML">HTML</h4> + +<pre class="brush: html notranslate"><table id="outside"> + <tr><td id="t1">one</td></tr> + <tr><td id="t2">two</td></tr> +</table></pre> + +<h4 id="JavaScript">JavaScript</h4> + +<pre class="brush: js notranslate">// Function to change the content of t2 +function modifyText(new_text) { + var t2 = document.getElementById("t2"); + t2.firstChild.nodeValue = new_text; +} + +// Add event listener to table with an arrow function +var el = document.getElementById("outside"); +el.addEventListener("click", () => { modifyText("four"); }, false);</pre> + +<h4 id="结果_3">结果</h4> + +<p>{{EmbedLiveSample('带有箭头函数的监听器')}}</p> + +<p>请注意尽管匿名函数和箭头函数有些类似,但是他们绑定不同的<code>this</code>对象。匿名函数(和所有传统的Javascript函数)创建他们独有的<code>this</code>对象,而箭头函数则继承绑定他所在函数的<code>this</code>对象。</p> + +<p>这意味着在使用箭头函数时,原函数中可用的变量和常量在事件处理器中同样可用。</p> + +<h3 id="options用法示例">options用法示例</h3> + +<h4 id="HTML_2">HTML</h4> + +<pre class="brush: html notranslate"><div class="outer"> + outer, once & none-once + <div class="middle" target="_blank"> + middle, capture & none-capture + <a class="inner1" href="https://www.mozilla.org" target="_blank"> + inner1, passive & preventDefault(which is not allowed) + </a> + <a class="inner2" href="https://developer.mozilla.org/" target="_blank"> + inner2, none-passive & preventDefault(not open new page) + </a> + </div> +</div></pre> + +<h4 id="CSS">CSS</h4> + +<pre class="brush: css notranslate"> .outer, .middle, .inner1, .inner2 { + display:block; + width:520px; + padding:15px; + margin:15px; + text-decoration:none; + } + .outer{ + border:1px solid red; + color:red; + } + .middle{ + border:1px solid green; + color:green; + width:460px; + } + .inner1, .inner2{ + border:1px solid purple; + color:purple; + width:400px; + }</pre> + +<h4 id="JavaScript_2">JavaScript</h4> + +<pre class="brush: js notranslate">let outer = document.getElementsByClassName('outer') [0]; + let middle = document.getElementsByClassName('middle')[0]; + let inner1 = document.getElementsByClassName('inner1')[0]; + let inner2 = document.getElementsByClassName('inner2')[0]; + + let capture = { + capture : true + }; + let noneCapture = { + capture : false + }; + let once = { + once : true + }; + let noneOnce = { + once : false + }; + let passive = { + passive : true + }; + let nonePassive = { + passive : false + }; + + + outer .addEventListener('click', onceHandler, once); + outer .addEventListener('click', noneOnceHandler, noneOnce); + middle.addEventListener('click', captureHandler, capture); + middle.addEventListener('click', noneCaptureHandler, noneCapture); + inner1.addEventListener('click', passiveHandler, passive); + inner2.addEventListener('click', nonePassiveHandler, nonePassive); + + function onceHandler(event) + { + alert('outer, once'); + } + function noneOnceHandler(event) + { + alert('outer, none-once, default'); + } + function captureHandler(event) + { + //event.stopImmediatePropagation(); + alert('middle, capture'); + } + function noneCaptureHandler(event) + { + alert('middle, none-capture, default'); + } + function passiveHandler(event) + { + // Unable to preventDefault inside passive event listener invocation. + //在调用passive事件监听器内部不能使用preventDefault + event.preventDefault(); + alert('inner1, passive, open new page'); + } + function nonePassiveHandler(event) + { + event.preventDefault(); + //event.stopPropagation(); + alert('inner2, none-passive, default, not open new page'); + } +</pre> + +<h4 id="结果_4">结果</h4> + +<p>分别点击 outer, middle, inner 以查看选项的工作方式。</p> + +<p>{{ EmbedLiveSample('options用法示例', 600, 310, '', 'Web/API/EventTarget/addEventListener') }}</p> + +<p>在使用<code>options</code>对象中具体的值前,最好确保用户的浏览器支持它,因为这些是历史上并非所有浏览器都支持的附加功能。你可以查看{{anch("Safely detecting option support")}}以了解更多</p> + +<h2 id="备注">备注</h2> + +<h3 id="Why_use_addEventListener.3F" name="Why_use_addEventListener.3F">为什么要使用 <code>addEventListener</code>?</h3> + +<p><code>addEventListener()</code> 是 W3C DOM 规范中提供的注册事件监听器的方法。它的优点包括:</p> + +<ul> + <li>它允许给一个事件注册多个监听器。 特别是在使用{{Glossary("AJAX")}}库,JavaScript模块,或其他需要第三方库/插件的代码。</li> + <li>它提供了一种更精细的手段控制 <code>listener</code> 的触发阶段。(即可以选择捕获或者冒泡)。</li> + <li>它对任何 DOM 元素都是有效的,而不仅仅只对 HTML 元素有效。</li> +</ul> + +<p>除了这种方法以外,后文会简单阐述一些<a href="#注册 listener 的旧方法">注册事件监听器的旧方法 </a>。</p> + +<h3 id="Adding_a_listener_during_event_dispatch" name="Adding_a_listener_during_event_dispatch">在事件分派时添加事件处理器</h3> + +<p>当一个 <code>EventListener </code>在 <code>EventTarget </code>正在处理事件的时候被注册到 <code>EventTarget </code>上,它不会被立即触发,但可能在事件流后面的事件触发阶段被触发,例如可能在捕获阶段添加,然后在冒泡阶段被触发。</p> + +<h3 id="Multiple_identical_event_listeners" name="Multiple_identical_event_listeners">多个相同的事件处理器</h3> + +<p>同一个 <code>EventTarget 注册了多个相同的 EventListener</code>,那么重复的实例会被抛弃。所以这么做不会使得 <code>EventListener</code> 被调用两次,也不需要用 <a href="/zh-CN/docs/Web/API/EventTarget/removeEventListener" title="zh-cn/DOM/element.removeEventListener">removeEventListener</a> 手动清除多余的<code>EventListener</code> ,因为重复的都被自动抛弃了,前提是<code>options</code>中的<code>capture</code>的参数值一致,如果<code>capture</code>的值不一致,此时就算重复定义,也不会被抛弃掉。</p> + +<h3 id="The_value_of_this_within_the_handler" name="The_value_of_this_within_the_handler">处理过程中 <code>this</code> 的值的问题</h3> + +<p>通常来说this的值是触发事件的元素的引用,这种特性在多个相似的元素使用同一个通用事件监听器时非常让人满意。</p> + +<p>当使用 <code>addEventListener()</code> 为一个元素注册事件的时候,句柄里的 this 值是该元素的引用。其与传递给句柄的 event 参数的 <code>currentTarget 属性的值一样。</code></p> + +<p>如果一个事件的属性( 例如. onClick)是指定在一个HTML的元素上的,则这个属性中的JavaScript语句实际上会被包裹在一个处理函数中,在这个处理函数中使用this的效果和使用addEventListener来绑定事件的效果是一样的; this的出现代表了元素的引用。注意到在一个函数里this调用的的效果和标准规则里面是一样的。</p> + +<p>比如下面的例子:</p> + +<pre class="brush: html notranslate"><table id="t" onclick="modifyText();"> +. . . +</pre> + +<p>这时<code>modifyText()</code>中的<code>this</code> 的值会变成全局 (window) 对象的引用(在<a href="/zh-CN/docs/Web/JavaScript/Reference/Strict_mode">严格模式</a>中为 <code>undefined)</code>。</p> + +<div class="note"><strong>注意:</strong> JavaScript 1.8.5 引入了<code><a href="/zh-cn/JavaScript/Reference/Global_Objects/Function/bind" title="zh-cn/JavaScript/Reference/Global Objects/Function/bind">Function.prototype.bind()</a></code> 方法,允许制定函数调用时的 <code>this</code> 的值。这使得想要绕开由于调用情况不同,this 取值不同的问题变得十分容易 。然而请注意,你应该保留一个 <code>listener 的</code>引用,以便在未来需要的时候能够比较好地移除。</div> + +<p>下面是 <code>bind</code> 相关的例子:</p> + +<pre class="brush: js notranslate">var Something = function(element) { + // |this| is a newly created object + this.name = 'Something Good'; + this.onclick1 = function(event) { + console.log(this.name); // undefined, as |this| is the element + }; + this.onclick2 = function(event) { + console.log(this.name); // 'Something Good', as |this| is bound to newly created object + }; + element.addEventListener('click', this.onclick1, false); + element.addEventListener('click', this.onclick2.bind(this), false); // Trick +} +var s = new Something(document.body);</pre> + +<p>上面这个例子的一个问题是不可能移除使用了 <code>bind</code> 的监听器。一种解决办法是使用定制的函数'handleEvent'去捕获任意类型:</p> + +<pre class="brush: js notranslate">var Something = function(element) { + // |this| is a newly created object + this.name = 'Something Good'; + this.handleEvent = function(event) { + console.log(this.name); // 'Something Good', as this is bound to newly created object + switch(event.type) { + case 'click': + // some code here... + break; + case 'dblclick': + // some code here... + break; + } + }; + + // Note that the listeners in this case are |this|, not this.handleEvent + element.addEventListener('click', this, false); + element.addEventListener('dblclick', this, false); + + // You can properly remove the listeners + element.removeEventListener('click', this, false); + element.removeEventListener('dblclick', this, false); +} +var s = new Something(document.body);</pre> + +<p>另一种控制this指向的方法是,给 <code>EventListener</code> 传递一个函数,调用想要访问对应作用域对象的方法:</p> + +<pre class="brush: js notranslate">class SomeClass { + + constructor() { + this.name = 'Something Good'; + } + + register() { + var that = this; + window.addEventListener('keydown', function(e) {return that.someMethod(e);}); + } + + someMethod(e) { + console.log(this.name); + switch(e.keyCode) { + case 5: + // some code here... + break; + case 6: + // some code here... + break; + } + } + +} + +var myObject = new SomeClass(); +myObject.register(); +</pre> + +<h3 id="Compatibility" name="Compatibility">传统的 Internet Explorer 及其 attachEvent 方法</h3> + +<p>对于 Internet Explorer 来说,在IE 9之前,你必须使用 <code><a class="external" href="http://msdn.microsoft.com/en-us/library/ms536343(VS.85).aspx">attachEvent</a></code> 而不是使用标准方<code>法 addEventListener</code>。为了支持IE,前面的例子需要改成这样:</p> + +<pre class="brush: js notranslate">if (el.addEventListener) { + el.addEventListener('click', modifyText, false); +} else if (el.attachEvent) { + el.attachEvent('onclick', modifyText); +} +</pre> + +<p>使用 <code>attachEvent </code>方法有个缺点,<code>this</code> 的值会变成 <code>window</code> 对象的引用而不是触发事件的元素。</p> + +<p><code>attachEvent()</code>方法可以与<code>onresize</code>事件配对,以检测何时调整网页中的某些元素的大小。专有的<code>mselementresize</code>事件与注册事件处理程序的<code>addEventListener</code>方法配对时,提供与<code>onresize</code>类似的功能,在调整某些HTML元素大小时触发。</p> + +<h3 id="兼容性">兼容性</h3> + +<p>在你的script的开头添加以下方法,你就可以使用以下如 <code>addEventListener</code>, <code>removeEventListener</code>, <code>Event.preventDefault</code> 和<code>Event.stopPropagation</code> 等不被IE8支持的方法。 这些代码支持 <code>handleEvent</code> 的使用 ,包含 <code>DOMContentLoaded</code> 事件.</p> + +<div class="note"><strong>Note: </strong>IE8 不具有任何替代 useCapture 的方法,useCapture 是 IE8 不支持的。 请注意下面的代码只能添加 IE8。另外请注意,下面这个 IE8 polyfill 只适用于标准模式:需要 DOCTYPE 声明。</div> + +<pre class="brush: js notranslate">(function() { + if (!Event.prototype.preventDefault) { + Event.prototype.preventDefault=function() { + this.returnValue=false; + }; + } + if (!Event.prototype.stopPropagation) { + Event.prototype.stopPropagation=function() { + this.cancelBubble=true; + }; + } + if (!Element.prototype.addEventListener) { + var eventListeners=[]; + + var addEventListener=function(type,listener /*, useCapture (will be ignored) */) { + var self=this; + var wrapper=function(e) { + e.target=e.srcElement; + e.currentTarget=self; + if (typeof listener.handleEvent != 'undefined') { + listener.handleEvent(e); + } else { + listener.call(self,e); + } + }; + if (type=="DOMContentLoaded") { + var wrapper2=function(e) { + if (document.readyState=="complete") { + wrapper(e); + } + }; + document.attachEvent("onreadystatechange",wrapper2); + eventListeners.push({object:this,type:type,listener:listener,wrapper:wrapper2}); + + if (document.readyState=="complete") { + var e=new Event(); + e.srcElement=window; + wrapper2(e); + } + } else { + this.attachEvent("on"+type,wrapper); + eventListeners.push({object:this,type:type,listener:listener,wrapper:wrapper}); + } + }; + var removeEventListener=function(type,listener /*, useCapture (will be ignored) */) { + var counter=0; + while (counter<eventListeners.length) { + var eventListener=eventListeners[counter]; + if (eventListener.object==this && eventListener.type==type && eventListener.listener==listener) { + if (type=="DOMContentLoaded") { + this.detachEvent("onreadystatechange",eventListener.wrapper); + } else { + this.detachEvent("on"+type,eventListener.wrapper); + } + eventListeners.splice(counter, 1); + break; + } + ++counter; + } + }; + Element.prototype.addEventListener=addEventListener; + Element.prototype.removeEventListener=removeEventListener; + if (HTMLDocument) { + HTMLDocument.prototype.addEventListener=addEventListener; + HTMLDocument.prototype.removeEventListener=removeEventListener; + } + if (Window) { + Window.prototype.addEventListener=addEventListener; + Window.prototype.removeEventListener=removeEventListener; + } + } +})();</pre> + +<h3 id="Older_way_to_register_event_listeners" name="Older_way_to_register_event_listeners">注册 <code>listener </code>的旧方法</h3> + +<p><code>addEventListener()</code> 在DOM 2 <a class="external" href="http://www.w3.org/TR/DOM-Level-2-Events">Events</a> 规范中引入。在这之前,事件监听器应该用以下的方法注册:</p> + +<pre class="brush: js notranslate">// Pass a function reference — do not add '()' after it, which would call the function! +el.onclick = modifyText; + +// Using a function expression +element.onclick = function() { + // ... function logic ... +}; +</pre> + +<p>这个方法会替换这个元素上所有已存在的 on<code>click</code> 事件。对于其他事件是类似的,比如 <code>blur</code> (<code>onblur</code>)、 <code>keypress</code> (<code>onkeypress</code>)等等。</p> + +<p>由于这是 DOM 0 规范的基本内容,几乎所有浏览器都支持这个,而且不需要特殊的跨浏览器兼容代码。因此通常这个方法被用于动态地注册事件处理器,除非必须使用 <code>addEventListener()</code> 才能提供的特殊特性。</p> + +<h3 id="Memory_issues" name="Memory_issues">内存问题</h3> + +<pre class="brush: js notranslate">var i; +var els = document.getElementsByTagName('*'); + +// Case 1 +for(i=0 ; i<els.length ; i++){ + els[i].addEventListener("click", function(e){/*do something*/}, false}); +} + +// Case 2 +function processEvent(e){ + /*do something*/ +} + +for(i=0 ; i<els.length ; i++){ + els[i].addEventListener("click", processEvent, false}); +} +</pre> + +<p>在第一种情况下,每个循环中都会创建一个新的(匿名)函数。在第二种情况下,会使用先前声明的相同的函数作为事件处理器。这样的结果是占用的存储空间更小。而且,在第一种情况中,由于没有保持到匿名函数的引用,它不可能被调用 <code><a href="/zh-cn/DOM/element.removeEventListener" title="zh-cn/DOM/element.removeEventListener">element.removeEventListener</a></code>,这是因为我们没有一个可参考的处理器,而在第二种情况,它可以被 <code>myElement.removeEventListener("click", processEvent, false)</code>。</p> + +<p>但是,真正影响内存的并不是没有保持函数引用,而是没有保持 <strong>静态</strong> 函数引用。在下面的两个示例中,每一个循环都重新定义了一个函数,并且保持了函数引用,但是并不是动态的函数引用。第三个示例中,在每次循环中都重新赋值了一个匿名函数的引用。第四个示例,函数定义始终没有改变,但是依然是非静态的,因为每次都重新定义了函数(除非被编译器变量[[提升]])。尽管表现上看起来很好理解([[重复添加相同的事件监听]]),但是每次循环都是将事件处理函数指向了一个唯一的新创建的函数的引用。同时,因为函数定义本身没有改变,每次触发事件监听器时调用的还是同一个方法(特别是在经过优化的代码中)。</p> + +<p>在这两个示例中,每次循环都会重复定义函数并保持函数引用,所以上面的移除语句也可以移除对应的监听器,但是只能移除最后一个。</p> + +<pre class="notranslate"><code>// For illustration only: Note "MISTAKE" of [j] for [i] thus causing desired events to all attach to SAME element + +// Case 3 +for(var i=0, j=0 ; i<els.length ; i++){ + /*do lots of stuff with j*/ + els[j].addEventListener("click", processEvent = function(e){/*do something*/}, false); +} + +// Case 4 +for(var i=0, j=0 ; i<els.length ; i++){ + /*do lots of stuff with j*/ + function processEvent(e){/*do something*/}; + els[j].addEventListener("click", processEvent, false); </code> +</pre> + +<h3 id="使用_passive_改善的滚屏性能">使用 passive 改善的滚屏性能</h3> + +<p>根据规范,<code>passive</code> 选项的默认值始终为false。但是,这引入了处理某些触摸事件(以及其他)的事件监听器在尝试处理滚动时阻止浏览器的主线程的可能性,从而导致滚动处理期间性能可能大大降低。</p> + +<p>为防止出现此问题,某些浏览器(特别是Chrome和Firefox)已将文档级节点 {{domxref("Window")}},{{domxref("Document")}}和{{domxref("Document.body")}}的{{event("touchstart")}}和{{event("touchmove")}}事件的<code>passive</code>选项的默认值更改为true。这可以防止调用事件监听器,因此在用户滚动时无法阻止页面呈现。</p> + +<pre class="brush: js notranslate">var elem = document.getElementById('elem'); +elem.addEventListener('<code>touchmove</code>', function listener() { /* do something */ }, { passive: true }); +</pre> + +<p>添加passive参数后,<code>touchmove</code>事件不会阻塞页面的滚动(同样适用于鼠标的滚轮事件)。在这里查看<a href="https://developers.google.com/web/updates/2016/06/passive-event-listeners">demo</a>(需要翻墙)。</p> + +<div class="note"> +<p><strong>注意:</strong>那些不支持参数<code>options</code>的浏览器,会把第三个参数默认为<code>useCapture</code>,即设置<code>useCapture</code>为true</p> +</div> + +<p>您可以通过将<code>passive</code>的值显式设置为<code>false</code>来覆盖此行为,如下所示:</p> + +<pre class="notranslate"><code>/* Feature detection */ +/*特诊检测*/ +var passiveIfSupported = false; + +try { + window.addEventListener("test", null, Object.defineProperty({}, "passive", { get: function() { passiveIfSupported = { passive: true }; } })); +} catch(err) {} + +window.addEventListener('scroll', function(event) { + /* do something */ + // can't use event.preventDefault(); + // 不能使用event.prevebt. +}, passiveIfSupported );</code></pre> + +<p>在不支持<code>addEventListener()</code>的<code>options</code>参数的旧浏览器上,尝试使用它会阻止使用<code>useCapture</code>参数而不正确使用特征检测。</p> + +<p>您无需担心基本{{event("scroll")}} 事件的<code>passive</code>值。由于无法取消,因此事件监听器无法阻止页面呈现。</p> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th>Specification</th> + <th>Status</th> + <th>Comment</th> + </tr> + <tr> + <td>{{SpecName("DOM WHATWG", "#dom-eventtarget-addeventlistener", "EventTarget.addEventListener()")}}</td> + <td>{{Spec2("DOM WHATWG")}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName("DOM4", "#dom-eventtarget-addeventlistener", "EventTarget.addEventListener()")}}</td> + <td>{{Spec2("DOM4")}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName("DOM2 Events", "#Events-EventTarget-addEventListener", "EventTarget.addEventListener()")}}</td> + <td>{{Spec2("DOM2 Events")}}</td> + <td>Initial definition</td> + </tr> + </tbody> +</table> + +<h2 id="Browser_Compatibility" name="Browser_Compatibility">浏览器兼容性</h2> + +<div class="hidden"> +<p>该页面上的浏览器兼容性数据是来自已收集的数据。可以通过给<a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a>提PR的方式贡献新的数据。</p> +</div> + +<div id="compat-desktop"> +<p>{{Compat("api.EventTarget.addEventListener", 3)}}</p> +</div> + +<h2 id="Specification" name="Specification">相关链接</h2> + +<ul> + <li>{{domxref("EventTarget.removeEventListener()")}}</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events">Creating and triggering custom events</a></li> + <li><a class="external" href="http://www.quirksmode.org/js/this.html" title="http://www.quirksmode.org/js/this.html">More details on the use of <code>this</code> in event handlers</a></li> +</ul> + +<div class="content-27EWd_0" id="translate-man-app"> +<div class="outputBox-mGAYH_0"> +<div class="outputBox-6zQWc_0"></div> + +<div class="outputBox-23yoE_0"> +<div class="outputBox-mOJr9_0"></div> +</div> + +<div class="outputBox-2JiL2_0"></div> + +<div class="outputBox-EXeNH_0" style="display: none;"> +<div></div> +</div> +</div> +</div> diff --git a/files/zh-cn/web/api/eventtarget/attachevent/index.html b/files/zh-cn/web/api/eventtarget/attachevent/index.html new file mode 100644 index 0000000000..3ddf224034 --- /dev/null +++ b/files/zh-cn/web/api/eventtarget/attachevent/index.html @@ -0,0 +1,96 @@ +--- +title: 为这个EventTarget附加事件. +slug: Web/API/EventTarget/attachEvent +translation_of: Web/API/EventTarget/addEventListener +--- +<p>{{APIRef("DOM Events")}}</p> + +<p>{{ Non-standard_header() }}</p> + +<h2 id="摘要">摘要</h2> + +<p>这是早期IE浏览器(IE8及早期版本)的一个专有的替代性标准,替代EventTarget.addEventListener()方法,{{domxref("EventTarget.addEventListener()")}} 方法</p> + +<h2 id="Syntax" name="Syntax">语法</h2> + +<pre class="syntaxbox"><em>attached</em> = <em>target</em>.attachEvent(<em>eventNameWithOn</em>, <em>callback</em>) + +</pre> + +<dl> + <dt> 作用的元素(target)</dt> + <dd>一个用于监听事件的文档对象模型元素</dd> + <dt>事件名伴随On(eventNameWithOn)</dt> + <dd>监听的事件名以on前置,类似一个属性的管理者,譬如当你使用onclick时能够监听你的click事件</dd> + <dt>回调函数</dt> + <dd>当目标触发事件时回调函数被调用。这个函数被调用时不带参数,并且这些都将设置在<a href="/en-US/docs/Web/API/Window/window"><code>window</code> object.</a>这个对象中</dd> + <dt>附加</dt> + <dt> 是否成功附加上属性会以布尔值表示</dt> +</dl> + +<h2 id="规范">规范</h2> + +<p>不存在于任何标准规范中</p> + +<p>微软在MSDN有详细描述 <a href="https://msdn.microsoft.com/en-us/library/ms536343(v=vs.85).aspx">has a description on MSDN</a>.</p> + +<h2 id="Browser_Compatibility" name="Browser_Compatibility">浏览器是否合适</h2> + +<p>{{ CompatibilityTable() }}</p> + +<div id="compat-desktop"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Chrome</th> + <th>Firefox (Gecko)</th> + <th>Internet Explorer</th> + <th>Opera</th> + <th>Safari (WebKit)</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{ CompatNo() }}</td> + <td>{{ CompatNo() }}</td> + <td>6 thru 10 [1]</td> + <td>{{ CompatUnknown() }}</td> + <td>{{ CompatNo() }}</td> + </tr> + </tbody> +</table> +</div> + +<div id="compat-mobile"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Android</th> + <th>Firefox Mobile (Gecko)</th> + <th>IE Phone</th> + <th>Opera Mobile</th> + <th>Safari Mobile</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{ CompatNo() }}</td> + <td>{{ CompatNo() }}</td> + <td>{{ CompatUnknown() }}</td> + <td>{{ CompatUnknown() }}</td> + <td>{{ CompatNo() }}</td> + </tr> + </tbody> +</table> +</div> + +<p>[1]: <code>attachEvent()</code> 不再被IE11支持。</p> + +<p>{{domxref("EventTarget.addEventListener()")}}被IE9+支持.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li>{{domxref("EventTarget.detachEvent()")}}</li> + <li>{{domxref("EventTarget.fireEvent()")}}</li> +</ul> diff --git a/files/zh-cn/web/api/eventtarget/detachevent/index.html b/files/zh-cn/web/api/eventtarget/detachevent/index.html new file mode 100644 index 0000000000..c9ed7b6199 --- /dev/null +++ b/files/zh-cn/web/api/eventtarget/detachevent/index.html @@ -0,0 +1,96 @@ +--- +title: EventTarget.detachEvent() +slug: Web/API/EventTarget/detachEvent +tags: + - API + - DOM + - Method + - Non-standard +translation_of: Web/API/EventTarget/removeEventListener +--- +<p>{{APIRef("DOM Events")}}</p> + +<p>{{ Non-standard_header() }}</p> + +<h2 id="简介">简介</h2> + +<p>这是Microsoft Internet Explorer专有的用于替代标准的 {{domxref("EventTarget.removeEventListener()")}} 的方法。</p> + +<h2 id="Syntax" name="Syntax">语法</h2> + +<pre class="syntaxbox"><em>target</em>.detachEvent(<em>eventNameWithOn</em>, <em>callback</em>) +</pre> + +<dl> + <dt>target</dt> + <dd>将要移除事件的DOM节点</dd> + <dt>eventNameWithOn</dt> + <dd>将要移除的事件名,以“on”为前缀(例如它是一个事件处理程序)。 例如,您可以使用“onclick”移除点击事件的事件处理程序。</dd> + <dt>callback</dt> + <dd>注销事件后的回调函数</dd> +</dl> + +<h2 id="详细">详细</h2> + +<p>任何规范没有此部分。</p> + +<p>微软在 <a href="https://msdn.microsoft.com/en-us/library/ms536411(v=vs.85).aspx">MSDN</a> 上有相关描述。</p> + +<h2 id="Browser_Compatibility" name="Browser_Compatibility">浏览器兼容性</h2> + +<p>{{ CompatibilityTable() }}</p> + +<div id="compat-desktop"> +<table class="compat-table"> + <tbody> + <tr> + <th>特征</th> + <th>Chrome</th> + <th>Firefox (Gecko)</th> + <th>Internet Explorer</th> + <th>Opera</th> + <th>Safari (WebKit)</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{ CompatNo() }}</td> + <td>{{ CompatNo() }}</td> + <td>6 至 10 [1]</td> + <td>{{ CompatUnknown() }}</td> + <td>{{ CompatNo() }}</td> + </tr> + </tbody> +</table> +</div> + +<div id="compat-mobile"> +<table class="compat-table"> + <tbody> + <tr> + <th>特征</th> + <th>Android</th> + <th>Firefox Mobile (Gecko)</th> + <th>IE Phone</th> + <th>Opera Mobile</th> + <th>Safari Mobile</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{ CompatNo() }}</td> + <td>{{ CompatNo() }}</td> + <td>{{ CompatUnknown() }}</td> + <td>{{ CompatUnknown() }}</td> + <td>{{ CompatNo() }}</td> + </tr> + </tbody> +</table> +</div> + +<p>[1]: <code>detachEvent()</code> 在 IE11+ 中不再支持。 {{domxref("EventTarget.removeEventListener()")}} 在 IE9+ 中支持。</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li>{{ domxref("EventTarget.attachEvent()") }}</li> + <li>{{ domxref("EventTarget.fireEvent()") }}</li> +</ul> diff --git a/files/zh-cn/web/api/eventtarget/dispatchevent/index.html b/files/zh-cn/web/api/eventtarget/dispatchevent/index.html new file mode 100644 index 0000000000..3371377a73 --- /dev/null +++ b/files/zh-cn/web/api/eventtarget/dispatchevent/index.html @@ -0,0 +1,73 @@ +--- +title: EventTarget.dispatchEvent +slug: Web/API/EventTarget/dispatchEvent +tags: + - API + - DOM + - events +translation_of: Web/API/EventTarget/dispatchEvent +--- +<p>{{APIRef("DOM Events")}}</p> + +<p>向一个指定的事件目标派发一个<a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Event">事件</a>, 并以合适的顺序<strong>同步调用</strong>目标元素相关的事件处理函数。<span style="line-height: 1.5;">标准事件处理规则(包括事件捕获和可选的冒泡过程)同样适用于通过手动的使用</span><code style="font-style: normal; line-height: 1.5;">dispatchEvent()</code><span style="line-height: 1.5;">方法</span><span style="line-height: 1.5;">派发的事件。</span></p> + +<h2 id="Syntax" name="Syntax">语法</h2> + +<pre class="syntaxbox notranslate"><em>cancelled</em> = !<em>target</em>.dispatchEvent(<em>event</em>) +</pre> + +<h3 id="参数">参数</h3> + +<ul> + <li><code>event</code> 是要被派发的事件对象。</li> + <li><code>target</code> 被用来初始化 事件 和 决定将会触发 目标.</li> +</ul> + +<h3 id="返回值">返回值</h3> + +<ul> + <li>当该事件是可取消的(cancelable为true)并且至少一个该事件的 事件处理方法 调用了{{domxref("Event.preventDefault()")}},则返回值为<code>false</code>;否则返回<code>true</code>。</li> +</ul> + +<p>如果该被派发的事件的事件类型(event's type)在方法调用之前没有被经过初始化被指定,就会抛出一个 <code>UNSPECIFIED_EVENT_TYPE_ERR</code> 异常,或者如果事件类型是<code>null</code><span style="line-height: 1.5;">或一个空字符串</span><span style="line-height: 1.5;">. event handler 就会抛出未捕获的异常; 这些 event handlers 运行在一个嵌套的调用栈中: 他们会阻塞调用直到他们处理完毕,但是异常不会冒泡。</span></p> + +<h2 id="Notes" name="Notes">注意</h2> + +<p>与浏览器原生事件不同,原生事件是由DOM派发的,并通过<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop">event loop</a>异步调用事件处理程序,而<code>dispatchEvent()</code>则是同步调用事件处理程序。在调用<code>dispatchEvent()</code>后,所有监听该事件的事件处理程序将在代码继续前执行并返回。</p> + +<p><code>dispatchEvent()</code>是create-init-dispatch过程的最后一步,用于将事件调度到实现的事件模型中。可以使用<a href="/zh-CN/docs/Web/API/Event/Event">Event</a>构造函数来创建事件。</p> + +<p>另请参阅 <a href="/en-US/docs/DOM/event" title="DOM/event">Event object reference</a>.</p> + +<h2 id="Example" name="Example">例子</h2> + +<p>参考 <a href="/en-US/docs/Web/Guide/DOM/Events/Creating_and_triggering_events" title="/en-US/docs/Web/Guide/DOM/Events/Creating_and_triggering_events">Creating and triggering events</a>.</p> + +<h2 id="Specification" name="Specification">规范</h2> + +<ul> + <li><a class="external" href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget-dispatchEvent">DOM Level 2 Events: dispatchEvent</a></li> +</ul> + +<table> + <thead> + <tr> + <th scope="col">Specification</th> + <th scope="col">Status</th> + <th scope="col">Comment</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName('DOM WHATWG', '#dom-eventtarget-dispatchevent', 'EventTarget.dispatchEvent()')}}</td> + <td>{{ Spec2('DOM WHATWG') }}</td> + <td>Initial definition in the DOM 2 Events specification.</td> + </tr> + </tbody> +</table> + +<h2 id="Browser_Compatibility" name="Browser_Compatibility">Browser compatibility</h2> + + + +<p>{{Compat("api.EventTarget.dispatchEvent")}}</p> diff --git a/files/zh-cn/web/api/eventtarget/eventtarget/index.html b/files/zh-cn/web/api/eventtarget/eventtarget/index.html new file mode 100644 index 0000000000..89ff7132d7 --- /dev/null +++ b/files/zh-cn/web/api/eventtarget/eventtarget/index.html @@ -0,0 +1,74 @@ +--- +title: EventTarget() +slug: Web/API/EventTarget/EventTarget +translation_of: Web/API/EventTarget/EventTarget +--- +<div> +<p>{{APIRef("DOM Events")}}</p> + +<p><code><strong>EventTarget()</strong></code> 构造方法将会创建一个新的{{domxref("EventTarget")}} 对象实例。</p> + +<h2 id="语法">语法</h2> + +<pre>var <var>myEventTarget</var> = new EventTarget();</pre> + +<h3 id="参数">参数</h3> + +<p>无。</p> + +<h3 id="返回值">返回值</h3> + +<p>一个 {{domxref("EventTarget")}} 实例。</p> + +<h2 id="例子">例子</h2> + +<pre id="ct-20">class MyEventTarget extends EventTarget { + constructor(mySecret) { + super(); + this._secret = mySecret; + } + + get secret() { return this._secret; } +}; + +let myEventTarget = new MyEventTarget(5); +let value = myEventTarget.secret; // == 5 +myEventTarget.addEventListener("foo", function(e) { + this._secret = e.detail; +}); + +let event = new CustomEvent("foo", { detail: 7 }); +myEventTarget.dispatchEvent(event); +let newValue = myEventTarget.secret; // == 7</pre> + +<h2 id="Specifications">Specifications</h2> + +<table> + <tbody> + <tr> + <th scope="col">Specification</th> + <th scope="col">Status</th> + <th scope="col">Comment</th> + </tr> + <tr> + <td>{{SpecName('DOM WHATWG', '#dom-eventtarget-eventtarget', 'EventTarget() constructor')}}</td> + <td>{{Spec2('DOM WHATWG')}}</td> + <td> </td> + </tr> + </tbody> +</table> + +<h2 id="浏览器兼容性">浏览器兼容性</h2> + +<p>The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</p> + +<p>{{Compat("api.EventTarget.EventTarget")}}</p> + +<h2 id="另见">另见</h2> + +<ul> + <li>{{domxref("EventTarget")}}</li> +</ul> +</div> + +<p> </p> diff --git a/files/zh-cn/web/api/eventtarget/fireevent/index.html b/files/zh-cn/web/api/eventtarget/fireevent/index.html new file mode 100644 index 0000000000..b9c89fa883 --- /dev/null +++ b/files/zh-cn/web/api/eventtarget/fireevent/index.html @@ -0,0 +1,92 @@ +--- +title: EventTarget.fireEvent() +slug: Web/API/EventTarget/fireEvent +translation_of: Web/API/EventTarget/dispatchEvent +--- +<p>{{APIRef("DOM Events")}}</p> + +<p>{{ Non-standard_header() }}</p> + +<h2 id="概述">概述</h2> + +<p>这是微软IE浏览器用以替代{{domxref("EventTarget.dispatchEvent()")}}的私有方法,与{{domxref("EventTarget.dispatchEvent()")}}不同的是通过<code>fireEvent()</code> 触发的事件不会触发事件的默认行为,例如,通过fireEvent()触发<input type="checkbox">的点击事件并不会切换checkbox的选中状态</p> + +<p>语法</p> + +<pre class="syntaxbox"><em>cancelled</em> = <em>target</em>.fireEvent(<em>eventNameWithOn</em>, <em>event</em>) +</pre> + +<dl> + <dt>target</dt> + <dd>要触发事件的元素</dd> + <dt>eventNameWithOn</dt> + <dd>要触发事件的名字,前缀为“on”,例如,可以用过"onclick"来触发点击事件</dd> + <dt>event</dt> + <dd>要触发的事件对象</dd> + <dt>cancelled</dt> + <dd>布尔值,事件是否被事件句柄取消</dd> +</dl> + +<h2 id="规范">规范</h2> + +<p>无此部分的规范</p> + +<p>微软的描述: <a href="https://msdn.microsoft.com/en-us/library/ms536423(v=vs.85).aspx">has a description on MSDN</a>.</p> + +<h2 id="Browser_Compatibility" name="Browser_Compatibility">浏览器兼容性</h2> + +<p>{{ CompatibilityTable() }}</p> + +<div id="compat-desktop"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Chrome</th> + <th>Firefox (Gecko)</th> + <th>Internet Explorer</th> + <th>Opera</th> + <th>Safari (WebKit)</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{ CompatNo() }}</td> + <td>{{ CompatNo() }}</td> + <td>6 到 10 [1]</td> + <td>{{ CompatUnknown() }}</td> + <td>{{ CompatNo() }}</td> + </tr> + </tbody> +</table> +</div> + +<div id="compat-mobile"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Android</th> + <th>Firefox Mobile (Gecko)</th> + <th>IE Phone</th> + <th>Opera Mobile</th> + <th>Safari Mobile</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{ CompatNo() }}</td> + <td>{{ CompatNo() }}</td> + <td>{{ CompatUnknown() }}</td> + <td>{{ CompatUnknown() }}</td> + <td>{{ CompatNo() }}</td> + </tr> + </tbody> +</table> +</div> + +<p>[1]: fireEvent()在IE11+已经不再支持,{{domxref("EventTarget.dispatchEvent()")}}在IE9+已经支持</p> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li><a href="http://help.dottoro.com/ljvtddtm.php">Dottoro Web Reference article</a></li> +</ul> diff --git a/files/zh-cn/web/api/eventtarget/index.html b/files/zh-cn/web/api/eventtarget/index.html new file mode 100644 index 0000000000..3793a8b749 --- /dev/null +++ b/files/zh-cn/web/api/eventtarget/index.html @@ -0,0 +1,128 @@ +--- +title: EventTarget +slug: Web/API/EventTarget +tags: + - API + - DOM + - DOM Events + - Interface +translation_of: Web/API/EventTarget +--- +<p>{{ApiRef("DOM Events")}}</p> + +<p><code>EventTarget</code> 是一个 DOM 接口,由可以接收事件、并且可以创建侦听器的对象实现。</p> + +<p>{{domxref("Element")}},{{domxref("document")}} 和 {{domxref("window")}} 是最常见的 event targets ,但是其他对象也可以作为 event targets,比如 {{domxref("XMLHttpRequest")}},{{domxref("AudioNode")}},{{domxref("AudioContext")}} 等等。</p> + +<p>许多 event targets (包括 elements, documents 和 windows)支持通过 <code>onevent</code> 特性和属性设置<a href="/zh-CN/docs/Web/Guide/DOM/Events/Event_handlers">事件处理程序</a> (<a href="https://wiki.developer.mozilla.org/en-US/docs/Web/Guide/DOM/Events/Event_handlers">event handlers</a>)。</p> + +<p>{{InheritanceDiagram}}</p> + +<h2 id="构造函数">构造函数</h2> + +<dl> + <dt>{{domxref("EventTarget.EventTarget()","EventTarget()")}}</dt> + <dd>创建一个新的 <code>EventTarget</code> 对象实例。</dd> +</dl> + +<h2 id="Methods" name="Methods">方法</h2> + +<dl> + <dt>{{domxref("EventTarget.addEventListener()")}}</dt> + <dd>在EventTarget上注册特定事件类型的事件处理程序。</dd> + <dt>{{domxref("EventTarget.removeEventListener()")}}</dt> + <dd>EventTarget中删除事件侦听器。</dd> + <dt>{{domxref("EventTarget.dispatchEvent()")}}</dt> + <dd>将事件分派到此EventTarget。</dd> +</dl> + +<h3 id="Mozilla_chrome_代码的其他方法">Mozilla chrome 代码的其他方法</h3> + +<p>Mozilla扩展,供JS实现的事件目标使用以 实现 on* 属性。另见 <a href="https://developer.mozilla.org/en-US/docs/Mozilla/WebIDL_bindings">WebIDL bindings</a> 绑定。</p> + +<ul> + <li>void <strong>setEventHandler</strong>(DOMString type, EventHandler handler) {{non-standard_inline}}</li> + <li>EventHandler <strong>getEventHandler</strong>(DOMString type) {{non-standard_inline}}</li> +</ul> + +<h2 id="示例">示例</h2> + +<h3 id="EventTarget_的简单实现">EventTarget 的简单实现</h3> + +<pre class="brush: js">var EventTarget = function() { + this.listeners = {}; +}; + +EventTarget.prototype.listeners = null; +EventTarget.prototype.addEventListener = function(type, callback) { + if(!(type in this.listeners)) { + this.listeners[type] = []; + } + this.listeners[type].push(callback); +}; + +EventTarget.prototype.removeEventListener = function(type, callback) { + if(!(type in this.listeners)) { + return; + } + var stack = this.listeners[type]; + for(var i = 0, l = stack.length; i < l; i++) { + if(stack[i] === callback){ + stack.splice(i, 1); + return this.removeEventListener(type, callback); + } + } +}; + +EventTarget.prototype.dispatchEvent = function(event) { + if(!(event.type in this.listeners)) { + return; + } + var stack = this.listeners[event.type]; + event.target = this; + for(var i = 0, l = stack.length; i < l; i++) { + stack[i].call(this, event); + } +}; +</pre> + +<h2 id="Specification" name="Specification">规范</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">规范</th> + <th scope="col">状态</th> + <th scope="col">注释</th> + </tr> + <tr> + <td>{{SpecName('DOM WHATWG', '#interface-eventtarget', 'EventTarget')}}</td> + <td>{{Spec2('DOM WHATWG')}}</td> + <td>No change.</td> + </tr> + <tr> + <td>{{SpecName('DOM3 Events', 'DOM3-Events.html#interface-EventTarget', 'EventTarget')}}</td> + <td>{{Spec2('DOM3 Events')}}</td> + <td>A few parameters are now optional (<code>listener</code>), or accepts the <code>null</code> value (<code>useCapture</code>).</td> + </tr> + <tr> + <td>{{SpecName('DOM2 Events', 'events.html#Events-EventTarget', 'EventTarget')}}</td> + <td>{{Spec2('DOM2 Events')}}</td> + <td>Initial definition.</td> + </tr> + </tbody> +</table> + +<h2 id="Browser_Compatibility" name="Browser_Compatibility">浏览器兼容性</h2> + + + +<p>{{Compat("api.EventTarget")}}</p> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/Reference/Events">Event reference</a> - the events available in the platform.</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/Guide/DOM/Events">Event developer guide</a></li> + <li>{{domxref("Event")}} interface</li> +</ul> diff --git a/files/zh-cn/web/api/eventtarget/removeeventlistener/index.html b/files/zh-cn/web/api/eventtarget/removeeventlistener/index.html new file mode 100644 index 0000000000..1541167537 --- /dev/null +++ b/files/zh-cn/web/api/eventtarget/removeeventlistener/index.html @@ -0,0 +1,227 @@ +--- +title: EventTarget.removeEventListener +slug: Web/API/EventTarget/removeEventListener +tags: + - API + - DOM + - Gecko + - removeEventListener + - 事件 +translation_of: Web/API/EventTarget/removeEventListener +--- +<p>{{APIRef("DOM Events")}}</p> + +<p>删除使用 {{domxref("EventTarget.addEventListener()")}} 方法添加的事件。使用事件类型,事件侦听器函数本身,以及可能影响匹配过程的各种可选择的选项的组合来标识要删除的事件侦听器。</p> + +<h2 id="Syntax" name="Syntax">语法</h2> + +<pre class="syntaxbox"><em>target</em>.removeEventListener(<em>type</em>, <em>listener</em>[, options]); +<em>target</em>.removeEventListener(<em>type</em>, <em>listener</em>[, <em>useCapture</em>]);</pre> + +<h3 id="参数">参数</h3> + +<dl> + <dt><code>type</code></dt> + <dd>一个字符串,表示需要移除的事件类型,如 <code>"click"</code>。</dd> + <dt><code>listener</code></dt> + <dd>需要从目标事件移除的 {{ domxref("EventListener") }} 函数。</dd> + <dt><code>options</code> {{optional_inline}}</dt> + <dd>一个指定事件侦听器特征的可选对象。可选项有:</dd> +</dl> + +<ul> + <li><code>capture</code>: 一个 {{jsxref("Boolean")}} 表示这个类型的事件将会被派遣到已经注册的侦听器,然后再派遣到DOM树中它下面的任何 <code>EventTarget</code>。</li> + <li>{{non-standard_inline}} <code>mozSystemGroup</code>: 仅可运行于 XBL 或者 Firefox Chrome,它是一个 {{jsxref("Boolean")}},用于定义是否将侦听器添加到系统组。</li> +</ul> + +<dl> + <dt><code>useCapture</code> {{ optional_inline }}</dt> + <dd>指定需要移除的 {{ domxref("EventListener") }} 函数是否为捕获监听器。如果无此参数,默认值为 <code>false</code>。</dd> + <dd>如果同一个监听事件分别为“事件捕获”和“事件冒泡”注册了一次,这两次事件需要分别移除。两者不会互相干扰。移除捕获监听器不会影响非捕获版本的相同监听器,反之亦然。</dd> +</dl> + +<h3 id="返回值">返回值</h3> + +<p><code>undefined</code>.</p> + +<h3 id="匹配要删除的事件监听">匹配要删除的事件监听</h3> + +<p>需要提供以前调用{{domxref("EventTarget.addEventListener", "addEventListener()")}}所提供的监听事件, 这样你或许可以达到移除此监听事件的目的. 很明显, 你需要提供相同的 <code>type</code> 和 <code>listener</code> 参数给 <code>removeEventListener()</code>, 但是 <code>options</code> 或者 <code>useCapture</code> 参数呢?</p> + +<p>当使用 <code>addEventListener()</code> 时, 如果 <code>options</code>参数不同, 那么你可以在相同的<code>type</code> 上多次添加相同的监听, 唯一需要 <code>removeEventListener()</code> 检测的是 <code>capture</code>/<code>useCapture</code> 标志. 这个标志必须与 <code>removeEventListener()</code> 的对应标志匹配, 但是其他的值不需要.</p> + +<p>举个例子, 思考一下下面的 <code>addEventListener()</code>:</p> + +<pre class="brush: js">element.addEventListener("mousedown", handleMouseDown, true);</pre> + +<p>现在思考下下面两个 <code>removeEventListener()</code>:</p> + +<pre class="brush: js">element.removeEventListener("mousedown", handleMouseDown, false); // 失败 +element.removeEventListener("mousedown", handleMouseDown, true); // 成功 +</pre> + +<p>第一个调用失败是因为 <code>useCapture</code> 没有匹配. 第二个调用成功,是因为<code>useCapture</code> 匹配相同.</p> + +<p>现在再思考下这个:</p> + +<pre class="brush: js">element.addEventListener("mousedown", handleMouseDown, { passive: true });</pre> + +<p>这里, 我们在<code>options</code> 对象里将 <code>passive</code> 设成 <code>true</code>, 其他<code>options</code>配置都是默认值 <code>false</code>.</p> + +<p>现在我们看下下面的 <code>removeEventListener()</code> . 当配置 <code>capture</code> 或 <code>useCapture</code> 为 <code>true</code> 时, 移除事件失败; 其他所有都是成功的. 只有 <code>capture</code> 配置影响 <code>removeEventListener()</code>.</p> + +<pre class="brush: js">element.removeEventListener("mousedown", handleMouseDown, { passive: true }); // Succeeds +element.removeEventListener("mousedown", handleMouseDown, { capture: false }); // Succeeds +element.removeEventListener("mousedown", handleMouseDown, { capture: true }); // Fails +element.removeEventListener("mousedown", handleMouseDown, { passive: false }); // Succeeds +element.removeEventListener("mousedown", handleMouseDown, false); // Succeeds +element.removeEventListener("mousedown", handleMouseDown, true); // Fails</pre> + +<p>值得注意的是,一些浏览器版本在这方面会有些不一致, 除非你有特别的理由, 使用与调用 <code>addEventListener()</code> 时配置的参数去调用<code>removeEventListener()是明智的</code>.</p> + +<h2 id="Compatibility" name="Compatibility">备注</h2> + +<p>一个 {{ domxref("EventTarget") }} 上的 {{ domxref("EventListener") }} 被移除之后,如果此事件正在执行,会立即停止。 {{ domxref("EventListener") }} 移除之后不能被触发,但可以重新绑定。</p> + +<p>在<code>EventTarget</code>上使用任何未识别当前注册的{{ domxref("EventListener") }} 调用 <code>removeEventListener()</code> 不会起任何作用。</p> + +<h2 id="示例">示例</h2> + +<p>以下例子展示了添加与删除监听事件:</p> + +<pre class="brush: js">var body = document.querySelector('body'), + clickTarget = document.getElementById('click-target'), + mouseOverTarget = document.getElementById('mouse-over-target'), + toggle = false; + +function makeBackgroundYellow() { + 'use strict'; + + if (toggle) { + body.style.backgroundColor = 'white'; + } else { + body.style.backgroundColor = 'yellow'; + } + + toggle = !toggle; +} + +clickTarget.addEventListener('click', + makeBackgroundYellow, + false +); + +mouseOverTarget.addEventListener('mouseover', function () { + 'use strict'; + + clickTarget.removeEventListener('click', + makeBackgroundYellow, + false + ); +}); +</pre> + +<h2 id="规范">规范</h2> + +<table class="standard-table"> + <thead> + <tr> + <th>Specification</th> + <th>Status</th> + <th>Comment</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName("DOM WHATWG", "#dom-eventtarget-removeeventlistener", "EventTarget.removeEventListener()")}}</td> + <td>{{Spec2("DOM WHATWG")}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName("DOM4", "#dom-eventtarget-removeeventlistener", "EventTarget.removeEventListener()")}}</td> + <td>{{Spec2("DOM4")}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName("DOM2 Events", "#Events-EventTarget-removeEventListener", "EventTarget.removeEventListener()")}}</td> + <td>{{Spec2("DOM2 Events")}}</td> + <td>Initial definition</td> + </tr> + </tbody> +</table> + +<h2 id="Browser_Compatibility" name="Browser_Compatibility">浏览器兼容性</h2> + +<p>{{Compat("api.EventTarget.removeEventListener", 3)}}</p> + +<h2 id="Polyfill">Polyfill</h2> + +<p>一些比较旧的浏览器不支持 <code>addEventListener()</code> 和 <code>removeEventListener()</code> 方法。可以将以下代码复制到脚本的开头来兼容这些旧版本的浏览器。值得注意的是,这个解决方案仍然不适用于 IE 7 及更早的 IE,因为 <code>Element.prototype</code> 属性直至 IE 8 才支持。</p> + +<pre class="brush: js">if (!Element.prototype.addEventListener) { + var oListeners = {}; + function runListeners(oEvent) { + if (!oEvent) { oEvent = window.event; } + for (var iLstId = 0, iElId = 0, oEvtListeners = oListeners[oEvent.type]; iElId < oEvtListeners.aEls.length; iElId++) { + if (oEvtListeners.aEls[iElId] === this) { + for (iLstId; iLstId < oEvtListeners.aEvts[iElId].length; iLstId++) { oEvtListeners.aEvts[iElId][iLstId].call(this, oEvent); } + break; + } + } + } + Element.prototype.addEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) { + if (oListeners.hasOwnProperty(sEventType)) { + var oEvtListeners = oListeners[sEventType]; + for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) { + if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; } + } + if (nElIdx === -1) { + oEvtListeners.aEls.push(this); + oEvtListeners.aEvts.push([fListener]); + this["on" + sEventType] = runListeners; + } else { + var aElListeners = oEvtListeners.aEvts[nElIdx]; + if (this["on" + sEventType] !== runListeners) { + aElListeners.splice(0); + this["on" + sEventType] = runListeners; + } + for (var iLstId = 0; iLstId < aElListeners.length; iLstId++) { + if (aElListeners[iLstId] === fListener) { return; } + } + aElListeners.push(fListener); + } + } else { + oListeners[sEventType] = { aEls: [this], aEvts: [ [fListener] ] }; + this["on" + sEventType] = runListeners; + } + }; + Element.prototype.removeEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) { + if (!oListeners.hasOwnProperty(sEventType)) { return; } + var oEvtListeners = oListeners[sEventType]; + for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) { + if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; } + } + if (nElIdx === -1) { return; } + for (var iLstId = 0, aElListeners = oEvtListeners.aEvts[nElIdx]; iLstId < aElListeners.length; iLstId++) { + if (aElListeners[iLstId] === fListener) { aElListeners.splice(iLstId, 1); } + } + }; +} +</pre> + +<h2 id="相关链接">相关链接</h2> + +<ul> + <li>{{domxref("EventTarget.addEventListener()")}}.</li> + <li>{{non-standard_inline}}{{domxref("EventTarget.detachEvent()")}}.</li> +</ul> + +<h2 id="注意:">注意:</h2> + + + +<p>document.removeEventListener() 方法用于移除由 document.addEventListener() 方法添加的事件句柄。</p> + +<p><strong>注意:</strong> 如果要移除事件句柄,addEventListener() 的执行函数必须使用外部函数,如(myFunction)匿名函数,类似 "document.removeEventListener("<em>event</em>", function(){ <em>myScript</em> });" 该事件是无法移除的。</p> + +<p><strong>提示:</strong> 使用 <em>element</em>.addEventListener() 和 <em>element</em>.removeEventListener() 方法来添加或移除指定元素的事件句柄。</p> |