我有一个包含其他div元素的容器div:
<div id="container">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
如何在纯JS中重写以下jQuery?
$('#container').on('mouseenter', 'div', myFunction)
也就是说,我怎样才能听哪个鼠标悬停在它上面以便应用myFunction
?我已尝试过以下操作,但这只适用于myFunction
到容器div:
container.addEventListener('mouseenter', function(event) {
let hoveredElement = event.target;
if (hoveredElement.tagName === 'DIV') {
myFunction(hoveredElement);
}
});
&#13;
#container { width: 200px; }
#container > div { height: 100px; background-color: red; }
&#13;
<div id="container">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
&#13;
我也试过了event.currentTarget
,但它仍然会给出相同的结果。
P.S。我不想把事件监听器放在容器div的子节点上,因为有很多孩子。
编辑:我已删除console.log(hoveredElement);
这是一条调试线。
答案 0 :(得分:1)
我在Chrome上调试了jQuery, jQuery mouseenter
事件实际上是在幕后使用mouseover
事件。
在jQuery源代码4095行中,每次触发事件时都会运行一行:
jQuery.event.dispatch.apply( elem, arguments );
如果您暂停并检查arguments
,您会发现它是类型为mouseover
的MouseEvent。
哪种有意义,因为您使用了jQuery的委托事件处理程序语法,而jQuery足够聪明,可以用mouseenter
替换mouseover
which doesn't bubble and doesn't trigger as you move through the event handler's descendents which does fire when you move through the listener's children。
所以,你的解决方案基本上就是在做jQuery正在做的事情 - 使用mouseover
:
container.addEventListener('mouseover', function(event) {
console.log("mouseover target", event.target);
console.log("mouseover currentTarget", event.currentTarget);
});
container.addEventListener('mouseenter', function(event) {
console.log("mouseenter target", event.target);
console.log("mouseenter currentTarget", event.currentTarget);
});
$('#container').on('mouseenter', '.child', function(event) {
console.log('jquery mouseenter target', event.target);
console.log('jquery mouseenter currentTarget', event.currentTarget);
console.log('jquery mouseenter delegateTarget', event.delegateTarget);
});
&#13;
.child {
border: 1px solid #007;
height: 50px;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.js"></script>
<div id="container">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
&#13;
答案 1 :(得分:0)
您需要从e.target
开始,并遍历祖先,在您找到的每个div
上调用处理程序。当你到达绑定元素时,你停止遍历祖先。
同时将事件类型更改为mouseover
,因为mouseenter
不会冒泡,因此event.target
始终是绑定元素。
const container = document.querySelector("#container");
container.addEventListener('mouseover', function(event) {
let el = event.target;
do {
if (el.tagName === 'DIV') {
myFunction.call(el, event);
}
} while((el = el.parentNode) !== this);
});
function myFunction(event) {
console.log(this.id);
}
<div id=container>
<section>
<div id=foo>
<p>Hover me to invoke the function</p>
</div>
<p>This one does not invoke</p>
</section>
</div>
没有注意到你有小写"div"
,所以我也大写了。
请注意,为方便起见,您可以将其抽象为可重用的函数。您还可以使用CSS选择器和.matches()
使其更通用,而不是仅限于标记名称比较。
const container = document.querySelector("#container");
delegate("mouseenter", container, "div", myFunction);
function myFunction(event) {
console.log(this.id);
}
// Reusable event delegation maker
function delegate(type, container, selector, handler) {
if (type === "mouseenter") {
type = "mouseover";
} else if (type === "mouseleave") {
type = "mouseout";
}
container.addEventListener(type, function(event) {
let el = event.target;
do {
if (el.matches(selector)) {
handler.call(el, event);
}
} while ((el = el.parentNode) !== this);
});
}
<div id=container>
<section>
<div id=foo>
<p>Hover me to invoke the function</p>
</div>
<p>This one does not invoke</p>
</section>
</div>
答案 2 :(得分:0)
您要做的是一种称为事件委派的做法。鉴于今天的JavaScript状态,这很容易做到。要复制JavaScript语法,我习惯于创建一个可以使用的可返回对象。
使用$get( query )
获取要执行委派的元素。在那里,您使用on
方法和参数(event, query for child elements, function)
当您为on
方法编写函数时,它将按照惯例传递event
参数,但下一个参数将是元素的索引,在此案件,鼠标过度。
参数没有安全保护,因为这不是问题的一部分,而且可以通过一点点肘部油脂轻松解决:)
let $get = (query) => {
if (document.querySelector(query)) {
let returnableObj = {
ele: document.querySelector(query),
list(q) {
return Array.from(this.ele.querySelectorAll(q))
},
getIndex(ele) {
return function(q) {
let foundIndex;
returnableObj.list(q).filter((itm, ind) => {
let bool = ele.isSameNode(itm);
if (bool) foundIndex = ind;
return bool;
});
return foundIndex >= 0 ? foundIndex : false;
}
}
}
returnableObj.on = function(evt, childquery, fn) {
this.ele.addEventListener(evt, function(e) {
if (e.target.matches(childquery)) {
let myIndex = returnableObj.getIndex(e.target)(childquery);
fn(e, myIndex);
}
});
}
return returnableObj;
} else alert('invalid query');
}
let $get = (query) => {
if (document.querySelector(query)) {
let returnableObj = {
ele: document.querySelector(query),
list(q) {
return Array.from(this.ele.querySelectorAll(q))
},
getIndex(ele) {
return function(q) {
let foundIndex;
returnableObj.list(q).filter((itm, ind) => {
let bool = ele.isSameNode(itm);
if (bool) foundIndex = ind;
return bool;
});
return foundIndex >= 0 ? foundIndex : false;
}
}
}
returnableObj.on = function(evt, childquery, fn) {
this.ele.addEventListener(evt, function(e) {
if (e.target.matches(childquery)) {
let myIndex = returnableObj.getIndex(e.target)(childquery);
fn(e, myIndex);
}
});
}
return returnableObj;
} else alert('invalid query');
}
let ele = $get("#mydiv");
ele.on("mouseover", ".child", function(e, ind) {
alert('Peanut Butter! Child ' + (ind+1));
})
h1,h2,h3 {
width: 200px;
}
<div id="mydiv">
<span>hiya</span>
<h1 class="child"> child 1 want some candy?</h1>
<h2 class="child"> child 2 I choose you, spirit dragon</h2>
<h3 class="child"> child 3, Scoreboard </h3>
</div>