继续传播

时间:2015-10-23 08:38:05

标签: javascript event-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链接: http://jsfiddle.net/6kgnu7fr/

点击.nested会为点击的元素添加红色背景颜色,并将绿色添加到外部body#container

UPD:

http://jsfiddle.net/6kgnu7fr/2/

点击#no-event.nested内的任何其他元素也应该为此.nested元素调用nestedHandler。

1 个答案:

答案 0 :(得分:1)

您可以在target中检查事件的nestedHandler,而不是停止传播。仅当目标为class时才更改this,以便仅对发生事件的div应用效果:

function nestedHandler(e) {
  if (e.target === this) {
    this.classList.add("nested-clicked");
  }
}

修改 编辑之后,这就更难了。这样做的方法是使用“嵌套”类找到e.target的第一个祖先,然后用它来代替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>