谁能通过示例告诉我JavaScript 事件中的currentTarget
和target
属性之间的确切区别以及在哪种情况下使用哪个属性?
9 回答
默认情况下,事件冒泡。所以两者的区别是:
target
是触发事件的元素(例如,用户点击)currentTarget
是事件侦听器附加到的元素。
target
= 触发事件的元素。
currentTarget
= 具有事件侦听器的元素。
最小可运行示例
window.onload = function() {
var resultElem = document.getElementById('result')
document.getElementById('1').addEventListener(
'click',
function(event) {
resultElem.innerHTML += ('<div>target: ' + event.target.id + '</div>')
resultElem.innerHTML += ('<div>currentTarget: ' + event.currentTarget.id + '</div>')
},
false
)
document.getElementById('2').dispatchEvent(
new Event('click', { bubbles:true }))
}
<div id="1">1 click me
<div id="2">2 click me as well</div>
</div>
<div id="result">
<div>result:</div>
</div>
如果点击:
2 click me as well
然后1
听它,并附加到结果:
target: 2
currentTarget: 1
因为在那种情况下:
2
是引发事件的元素1
是监听事件的元素
如果点击:
1 click me
相反,结果是:
target: 1
currentTarget: 1
在铬 71 上测试。
如果这不坚持,试试这个:
current incurrentTarget
指的是现在。这是捕捉从其他地方冒出的事件的最新目标。
对于气泡为的事件true
,它们会冒泡。
大多数事件都会冒泡,除了几个,即focus,blur,mouseenter,mouseleave,...
如果事件evt
冒泡,evt.currentTarget
则在其冒泡路径中更改为当前目标,而evt.target
保留与触发事件的原始目标相同的值。
值得注意的是,如果您的事件处理程序(冒泡的事件)是异步的,并且处理程序使用evt.currentTarget
. currentTarget
应该在本地缓存,因为事件对象在冒泡链(codepen)中被重用。
const clickHandler = evt => {
const {currentTarget} = evt // cache property locally
setTimeout(() => {
console.log('evt.currentTarget changed', evt.currentTarget !== currentTarget)
}, 3000)
}
如果您使用 React,从 v17 开始,react 会删除事件池。
因此,事件对象在处理程序中被刷新,并且可以安全地用于异步调用 ( codepen )。
↑并不总是正确的。onClick
事件currentTarget
是undefined
在事件处理程序完成之后。总之,如果要在同步调用后使用事件属性,请始终在本地缓存它们。
来自反应文档
笔记:
从 v17 开始, e.persist() 不会做任何事情,因为 SyntheticEvent 不再被池化。
还有很多其他的东西太长无法粘贴在答案中,所以我在这里总结并发了一篇博文。
<style>
body * {
margin: 10px;
border: 1px solid blue;
}
</style>
<form onclick="alert('form')">FORM
<div onclick="alert('div')">DIV
<p onclick="alert('p')">P</p>
</div>
</form>
如果单击上面代码中的 P 标签,您将收到三个警报,如果您单击 div 标签,您将收到两个警报和一个单击表单标签的警报。现在看到下面的代码,
<style>
body * {
margin: 10px;
border: 1px solid blue;
}
</style>
<script>
function fun(event){
alert(event.target+" "+event.currentTarget);
}
</script>
<form>FORM
<div onclick="fun(event)">DIV
<p>P</p>
</div>
</form>
[对象 HTMLParagraphElement] [对象 HTMLDivElement]
这里 event.target 是 [object HTMLParagraphElement],而 event.curentTarget 是 [object HTMLDivElement]: 所以
event.target 是事件起源的节点,而 event.currentTarget 相反,是指附加当前事件侦听器的节点。要了解更多信息,请参阅冒泡
在这里,我们点击了 P 标签,但我们在 P 上没有侦听器,但在其父元素 div 上。
event.target是事件起源的节点,即。无论您将事件侦听器放置在何处(在段落或跨度上), event.target 都指的是节点(用户单击的位置)。
相反, event.currentTarget指的是附加了当前事件侦听器的节点。IE。如果我们在段落节点上附加了我们的事件监听器,那么 event.currentTarget 指的是段落,而 event.target 仍然指的是跨度。注意:如果我们在 body 上也有一个事件监听器,那么对于这个事件监听器,event.currentTarget 指的是 body(即,作为事件监听器的输入提供的事件在每次事件冒泡一个节点时更新)。
Event.currentTarget
是事件处理程序已附加到的元素,而不是Event.target
,它标识事件发生的元素并且可能是它的后代。
来源:MDN
target
总是指前面的元素addEventListener
——它是事件起源的元素。
currentTarget
告诉你 - 如果这是一个冒泡的事件 - 当前附加了事件侦听器的元素(如果事件发生,它将触发事件处理程序)。
有关示例,请参阅此 CodePen。如果您打开开发人员工具并单击方块,您会看到首先 div 是目标和 currentTarget,但事件会冒泡到主元素 - 然后主元素成为 currentTarget,而 div 仍然是目标. 请注意,事件侦听器需要附加到两个元素才能发生冒泡。
这是一个简单的场景来解释为什么需要它。假设您使用以下格式向用户显示了一些消息,但您也希望给他们关闭它们的自由(除非您有特殊的精神障碍),所以这里有一些消息窗格:
[此窗格中将显示一条消息 [x]]
[此窗格中将显示一条消息 [x]]
[此窗格中将显示一条消息 [x]]
并且当用户单击每个上的[x]按钮时,必须删除整个相应的窗格。
这是窗格的 HTML 代码:
<div class="pane">
A message will be here
<span class="remove-button">[x]</span>
</div>
现在你想在哪里添加点击事件监听器?用户单击[x],但您想删除窗格,因此:
如果将 click 事件侦听器添加到[x],那么您将不得不在 DOM 上找到它的父级并将其删除......这可能但丑陋且“依赖于 DOM”。
如果您将 click 事件侦听器添加到窗格,单击“窗格上的任何位置”将删除它,而不仅仅是单击其[x]按钮。
所以,我们能做些什么?我们可以使用事件系统的“冒泡”功能:
“无论是否存在任何事件处理程序,都会引发事件并在 DOM 树中冒泡。”
在我们的示例中,这意味着即使我们将事件处理程序添加到窗格中,我们也将能够捕获专门由单击 [x] 按钮引发的事件(因为事件会冒泡)。因此,引发事件的位置与我们捕获和处理它的位置之间可能存在差异。
它被提出的地方将在 中event.target
,它被捕获的地方将在event.currentTarget
(我们目前正在处理它的地方)。所以:
let panes = document.getElementsByClassName("pane");
for(let pane of panes){
pane.addEventListener('click', hndlr);
}
function hndlr(e){
if(e.target.classList.contains('remove-button')){
e.currentTarget.remove();
}
}
(这个例子的功劳归功于网站JavaScript.info)