继续传播
Continue propagation
我的页面上有一些嵌套元素,它们上面有相同的处理程序,它们应该只为事件目标调用,而不会影响 DOM 树中较高的元素。为了实现这种行为,我使用了 stopPropagation 方法,它没问题。然后我必须在嵌套 div 之外为 body 和其他元素添加一些处理程序,这些处理程序在任何情况下都应该被调用。当然 stopPropagation 现在不是一个选项,但我怎样才能让它工作?
这是一个示例:
html:
<div id="container">
<div id="nested1" class="nested">
<div id="nested2" class="nested">
<div id="nested3" class="nested">
<div id="no-handler"></div>
</div>
</div>
</div>
</div>
css:
#container {
display: block;
width: 398px;
height: 398px;
padding: 30px;
border: solid 1px #888;
}
#nested1 {
width: 336px;
height: 336px;
padding: 30px;
}
#nested2 {
width: 274px;
height: 274px;
padding: 30px;
}
#nested3 {
width: 212px;
height: 212px;
padding: 30px;
}
#no-handler {
width: 150px;
height: 150px;
padding: 30px;
border: solid 1px #888;
}
.nested {
border: solid 1px #888;
}
.nested-clicked {
background-color: red;
}
.outer-clicked {
background-color: green;
}
js:
var container = document.getElementById("container");
var nested = document.getElementsByClassName("nested");
function outerHandler(e) {
this.classList.add("outer-clicked");
}
function nestedHandler(e) {
e.stopPropagation();
this.classList.add("nested-clicked");
}
container.addEventListener("click", outerHandler, false);
document.body.addEventListener("click", outerHandler, false);
for (var i = 0; i < nested.length; i++) {
nested[i].addEventListener("click", nestedHandler, false);
}
jsfiddle link:
http://jsfiddle.net/6kgnu7fr/
单击 .nested
应为单击的元素添加红色背景颜色,并为外部 body
和 #container
添加绿色背景
UPD:
http://jsfiddle.net/6kgnu7fr/2/
单击 #no-event
或 .nested
内的任何其他元素也应该为此 .nested
元素调用 nestedHandler。
您可以在 nestedHandler
中检查事件的 target
而不是停止传播。仅当目标为 this
时才更改 class
,这样效果将仅应用于事件发生的 div
:
function nestedHandler(e) {
if (e.target === this) {
this.classList.add("nested-clicked");
}
}
编辑
在你的编辑之后,这更难了。方法是找到 e.target
与 "nested" class 的第一个祖先,然后用它而不是 target
:
进行比较
function findAncestorWithClass(dom, targetClass){
if(!dom){
return; // (undefined)
}
if(dom.classList.contains(targetClass)){
return dom;
}
// terminal recursion
return findAncestorWithClass(dom.parentNode, targetClass);
}
这是天真的镜头。您可能想寻找一种方法来提高效率,例如通过避免在每个 .nested
div.
上寻找第一个祖先
请参阅下面的工作片段。
var container = document.getElementById("container");
var nested = document.getElementsByClassName("nested");
function outerHandler(e) {
this.classList.add("outer-clicked");
}
function findAncestorWithClass(dom, targetClass){
if(!dom){
return; // (undefined)
}
if(dom.classList.contains(targetClass)){
return dom;
}
// terminal recursion
return findAncestorWithClass(dom.parentNode, targetClass);
}
function nestedHandler(e) {
var nestedParent = findAncestorWithClass(e.target, "nested");
if (this === nestedParent) {
nestedParent.classList.add("nested-clicked");
}
}
container.addEventListener("click", outerHandler, false);
document.body.addEventListener("click", outerHandler, false);
for (var i = 0; i < nested.length; i++) {
nested[i].addEventListener("click", nestedHandler, false);
}
#container {
display: block;
width: 398px;
height: 398px;
padding: 30px;
border: solid 1px #888;
}
#nested1 {
width: 336px;
height: 336px;
padding: 30px;
}
#nested2 {
width: 274px;
height: 274px;
padding: 30px;
}
#nested3 {
width: 212px;
height: 212px;
padding: 30px;
}
#sub-nested {
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
}
.nested {
border: solid 1px #888;
}
.nested-clicked {
background-color: red;
}
.outer-clicked {
background-color: green;
}
<div id="container">
<div id="nested1" class="nested">
<div id="nested2" class="nested">
<div id="nested3" class="nested">
<div id="sub-nested"></div>
</div>
</div>
</div>
</div>
我的页面上有一些嵌套元素,它们上面有相同的处理程序,它们应该只为事件目标调用,而不会影响 DOM 树中较高的元素。为了实现这种行为,我使用了 stopPropagation 方法,它没问题。然后我必须在嵌套 div 之外为 body 和其他元素添加一些处理程序,这些处理程序在任何情况下都应该被调用。当然 stopPropagation 现在不是一个选项,但我怎样才能让它工作?
这是一个示例:
html:
<div id="container">
<div id="nested1" class="nested">
<div id="nested2" class="nested">
<div id="nested3" class="nested">
<div id="no-handler"></div>
</div>
</div>
</div>
</div>
css:
#container {
display: block;
width: 398px;
height: 398px;
padding: 30px;
border: solid 1px #888;
}
#nested1 {
width: 336px;
height: 336px;
padding: 30px;
}
#nested2 {
width: 274px;
height: 274px;
padding: 30px;
}
#nested3 {
width: 212px;
height: 212px;
padding: 30px;
}
#no-handler {
width: 150px;
height: 150px;
padding: 30px;
border: solid 1px #888;
}
.nested {
border: solid 1px #888;
}
.nested-clicked {
background-color: red;
}
.outer-clicked {
background-color: green;
}
js:
var container = document.getElementById("container");
var nested = document.getElementsByClassName("nested");
function outerHandler(e) {
this.classList.add("outer-clicked");
}
function nestedHandler(e) {
e.stopPropagation();
this.classList.add("nested-clicked");
}
container.addEventListener("click", outerHandler, false);
document.body.addEventListener("click", outerHandler, false);
for (var i = 0; i < nested.length; i++) {
nested[i].addEventListener("click", nestedHandler, false);
}
jsfiddle link: http://jsfiddle.net/6kgnu7fr/
单击 .nested
应为单击的元素添加红色背景颜色,并为外部 body
和 #container
UPD:
http://jsfiddle.net/6kgnu7fr/2/
单击 #no-event
或 .nested
内的任何其他元素也应该为此 .nested
元素调用 nestedHandler。
您可以在 nestedHandler
中检查事件的 target
而不是停止传播。仅当目标为 this
时才更改 class
,这样效果将仅应用于事件发生的 div
:
function nestedHandler(e) {
if (e.target === this) {
this.classList.add("nested-clicked");
}
}
编辑
在你的编辑之后,这更难了。方法是找到 e.target
与 "nested" class 的第一个祖先,然后用它而不是 target
:
function findAncestorWithClass(dom, targetClass){
if(!dom){
return; // (undefined)
}
if(dom.classList.contains(targetClass)){
return dom;
}
// terminal recursion
return findAncestorWithClass(dom.parentNode, targetClass);
}
这是天真的镜头。您可能想寻找一种方法来提高效率,例如通过避免在每个 .nested
div.
请参阅下面的工作片段。
var container = document.getElementById("container");
var nested = document.getElementsByClassName("nested");
function outerHandler(e) {
this.classList.add("outer-clicked");
}
function findAncestorWithClass(dom, targetClass){
if(!dom){
return; // (undefined)
}
if(dom.classList.contains(targetClass)){
return dom;
}
// terminal recursion
return findAncestorWithClass(dom.parentNode, targetClass);
}
function nestedHandler(e) {
var nestedParent = findAncestorWithClass(e.target, "nested");
if (this === nestedParent) {
nestedParent.classList.add("nested-clicked");
}
}
container.addEventListener("click", outerHandler, false);
document.body.addEventListener("click", outerHandler, false);
for (var i = 0; i < nested.length; i++) {
nested[i].addEventListener("click", nestedHandler, false);
}
#container {
display: block;
width: 398px;
height: 398px;
padding: 30px;
border: solid 1px #888;
}
#nested1 {
width: 336px;
height: 336px;
padding: 30px;
}
#nested2 {
width: 274px;
height: 274px;
padding: 30px;
}
#nested3 {
width: 212px;
height: 212px;
padding: 30px;
}
#sub-nested {
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
}
.nested {
border: solid 1px #888;
}
.nested-clicked {
background-color: red;
}
.outer-clicked {
background-color: green;
}
<div id="container">
<div id="nested1" class="nested">
<div id="nested2" class="nested">
<div id="nested3" class="nested">
<div id="sub-nested"></div>
</div>
</div>
</div>
</div>