DOM Event.StopPropagation对子对象无效

问题描述

我正在做一个有关事件的教程,并且被Event.StopPropagation()方法所困扰。以我的示例看来,对孩子的冒泡影响正在受到影响。

StopPropagation的定义:

stopPropagation()方法可防止调用同一事件的传播。 传播意味着冒泡到父元素或捕获到子元素。

起初我以为是浏览器问题,但事实并非如此。我找不到有关此问题的解决方案。

代码

// Event Bubbling and Propagation
//  element.addEventListener( type,func,useCapture);

let m = document.getElementById('m');
let d = document.getElementById('d');
let p = document.getElementById('p');
let s = document.getElementById('s');   

let highlight = (ev)=>{
    //add CSS class "gold" to the clicked element
    ev.stopPropagation();
    let target = ev.currentTarget;
    target.className = 'gold';
    reset(target);
}

let reset = (_element)=>{
    setTimeout(()=>{
        _element.className = '';
    },2000);
}

d.addEventListener('click',(ev)=>{
    ev.stopImmediatePropagation();
    log('Hi I\'m a DIV');
});

[m,d,p,s].forEach((element)=>{
    element.addEventListener('click',highlight);
})
#m,#d,#p,#s{    
 border: 2px solid black; 
 padding: 15px;
 margin: 10px;
}
.gold{
    background-color: gold;
}
<main id="m"> m
        <div id="d"> d
            <p id="p"> p
                <span id="s"> s</span>
            </p>
        </div>
    </main>

解决方法

这不是事件的问题,您对此太想了。

您的示例只是将背景颜色应用于顶部元素,并且由于未定义子级,因此将背景颜色应用于其下方。

如果您删除stopImmediatePropagation(),颜色将被应用,因为定义如下:执行第一个事件处理程序,并停止执行其余的事件处理程序,第一个是只需log()

在下面的示例中,如果将背景色应用于子元素,则会看到它们将保持不变。自身的颜色仅应用于单击的颜色。

这意味着JS事件本身没有冒泡到父元素或捕获下来。并且仅在单击的一个上添加了类。使用开发工具进行检查或在每个元素上添加DOM更改事件侦听器。

您将CSS样式与JS事件冒泡混淆了。

示例:

// Event Bubbling and Propagation
//  element.addEventListener( type,func,useCapture);

let m = document.getElementById('m');
let d = document.getElementById('d');
let p = document.getElementById('p');
let s = document.getElementById('s');
let log = console.log;

let highlight = (ev)=>{
    //add CSS class "gold" to the clicked element
    ev.stopPropagation();
    let target = ev.currentTarget;
    target.className = 'gold';
    reset(target);
}

let reset = (_element)=>{
    setTimeout(()=>{
        _element.className = '';
    },2000);
}

d.addEventListener('click',(ev)=>{
    //ev.stopImmediatePropagation();
    log('Hi I\'m a DIV');
});

[m,d,p,s].forEach((element)=>{
    element.addEventListener('click',highlight);
})
#m,#d,#p,#s{    
 border: 2px solid black; 
 padding: 15px;
 margin: 10px;
}

#d {
background-color: blue;
}

#s {
background-color: red;
}

.gold{
    background-color: gold !important;
}
<main id="m"> m
        <div id="d"> d
            <p id="p"> p
                <span id="s"> s</span>
            </p>
        </div>
    </main>

编辑:

在您的示例子节点中,它没有背景属性(rgba(0,0)),这意味着您需要在单击时进行设置,以便被单击元素的背景颜色不会应用于其子元素。

在下面的代码中,您可以读取单击的父元素的CSS背景值,并读取其background属性。您将其应用于所有已单击的子项。

这将在您的示例中起作用。 如果父对象是透明的,还可以确保将白色应用于元素。

这是一个玩弄的小提琴: 但请确保取消注释m(父级)背景色以查看副作用。您需要对此进行调整以适合您的生产需求

const style = getComputedStyle(target.parentNode);
const backgroundColor = style.backgroundColor;

console.clear();
console.log(backgroundColor);


[...target.children].forEach(el => {
if (backgroundColor==="rgba(0,0)") {
  el.style.backgroundColor = "white";
  }else{
  el.style.backgroundColor = backgroundColor;}
})

// Event Bubbling and Propagation
//  element.addEventListener( type,useCapture);

let m = document.getElementById('m');
let d = document.getElementById('d');
let p = document.getElementById('p');
let s = document.getElementById('s');
let log = console.log;

let highlight = (ev)=>{
    //add CSS class "gold" to the clicked element
    ev.stopPropagation();
    let target = ev.currentTarget;
    target.className = 'gold';
    
    const style = getComputedStyle(target.parentNode);
    const backgroundColor = style.backgroundColor;
    
    console.clear();
    console.log(backgroundColor);
    
    
    [...target.children].forEach(el => {
    if (backgroundColor==="rgba(0,0)") {
      el.style.backgroundColor = "white";
      }else{
      el.style.backgroundColor = backgroundColor;}
    })

    reset(target);
}

let reset = (_element)=>{
    setTimeout(()=>{
        _element.className = '';
    },2000);
}


[m,#s{    
 border: 2px solid black; 
 padding: 15px;
 margin: 10px;
}


#m {
background-color: blue;
}


.gold{
    background-color: gold !important;
}
<main id="m"> m
        <div id="d"> d
            <p id="p"> p
                <span id="s"> s</span>
            </p>
        </div>
    </main>