событие.stopPropagation () не работает — запись по-прежнему передается функции

#javascript #html

#javascript #HTML

Вопрос:

Прежде всего — я новичок. Извините, если этот вопрос достаточно простой. Второе — я попытался выполнить поиск и, как я вижу, применил решение в соответствии с инструкциями в других сообщениях.

С учетом сказанного… У меня есть три набора DIVS. Каждый набор состоит из 2 разделов (один внутри другого). Во ВНЕШНЕМ div есть функция, которая предлагает создать границу, если на нее щелкнуть.

Чтобы увидеть ошибку:

  1. Нажмите на слово OUTER.
  2. Нажмите на слово INNER.

Предполагается, что код создает границу только во внешнем.

HTML

 <html>
    <head>
        <title>Event Propagation</title>
        <meta charset="UTF-8" />

    </head>
    <body onload="onLoad()">

        <!--Squares 1-->
        <div style="display:inline-block">
            <div class="outer" style="height: 100px; width: 100px;">
                Outer
                <div class="inner" style="height: 50px; width: 50px;margin:20px"> 
                    Inner
                </div>
            </div>
        </div>
 <!--Squares 2-->
        <div style="display:inline-block">
            <div class="outer" style="height: 100px; width: 100px;">
                Outer
                <div class="inner" style="height: 50px; width: 50px;margin:20px"> 
                    Inner
                </div>
            </div>
        </div>

         <!--Squares 3-->
         <div style="display:inline-block">
            <div class="outer" style="height: 100px; width: 100px;">
                Outer
                <div class="inner" style="height: 50px; width: 50px;margin:20px"> 
                    Inner
                </div>
            </div>
        </div>


    </body>
</html>
  

JS

     <script>
        function onLoad(){
            
            const elOuter = document.querySelectorAll(".outer")

            elOuter.forEach(element=>{
                element.addEventListener('click', fnChangeColor,false)
            })
        }

        function fnChangeColor(e){

            e.target.style.border="1px solid black"

            if (e.stopPropagation) {
  
                e.stopPropagation()
            } else {
  
                e.cancelBubble = true
            }
        }

    </script>
  

К вашему СВЕДЕНИЮ — я решил вопрос, создавая события для дочерних элементов, приписывая им e.stopPropagation. Это сработало. Но я знаю, что это не лучший подход. Если у меня будет div с 100 разделениями внутри, это будет ад на земле.

Ответ №1:

это потому, что при нажатии на «Внутренний» e.целевой элемент является «внутренним», а не «Внешним».

Мне кажется, что вы пытаетесь понять делегирование событий, сделайте это таким образом:

 <!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>xxx</title>
  <style>
    body > div { display:inline-block; }
    .outer     { height: 100px; width: 100px; background: lightgrey; }    
    .inner     { height: 50px; width: 50px;margin:20px; background: lightblue; }
    .bordering { border: 1px solid black; }
  </style>
</head>
<body>
   <div> <div class="outer">  Outer <div class="inner">  Inner </div> </div> </div>
   <div> <div class="outer">  Outer <div class="inner">  Inner </div> </div> </div>
   <div> <div class="outer">  Outer <div class="inner">  Inner </div> </div> </div>
<script>
document.body.onclick= e => {
  if (!e.target.matches('.outer')) return // ignore other click events
  e.target.classList.toggle('bordering') 
  }
</script>
</body>
</html>
  

или таким образом

 document.querySelectorAll('.outer').forEach(el=>{
  el.onclick=e=>{

    // console.log(e.target.className)
    if (!e.target.matches('.outer')) return // ignore other click events
    e.target.classList.toggle('bordering') 
  }
})
  

В вашем коде используется только одно событие и нет способа для какого-либо распространения.

когда пользователь нажимает на .inner , событие добавляется к .inner элементу и никогда к .outer .
это похоже на пузырь, следующий по восходящему пути, а не наоборот. когда пузырь находит целевой код (прослушиватель avent), распространение прекращается и пузырь лопается.

Если вы хотите увидеть распространение события, вы должны установить 2 прослушивателя событий (что означает 2 буфера обмена).

Вы можете увидеть это, добавив console.log(например,target.className), как здесь:

 document.querySelectorAll(".outer, .inner") // => 6 event listeners
  .forEach(el=>{ el.addEventListener('click', getClick , false) })
 
var counter = 0

function getClick(e)
  {
  console.log( `${  counter} - event listener is on : ${e.currentTarget.className}
      clicked element is : ${e.target.className} `)
  }
  
cClear.onclick=_=>{ counter = 0; console.clear() }  
 body > div { display:inline-block; }
.outer     { height: 100px; width: 100px; background: lightgrey; }    
.inner     { height: 50px; width: 50px;margin:20px; background: lightblue; }  
 <div> <div class="outer"> Outer <div class="inner"> Inner </div> </div> </div>
<div> <div class="outer"> Outer <div class="inner"> Inner </div> </div> </div>
<div> <div class="outer"> Outer <div class="inner"> Inner </div> </div> </div>
<button id="cClear">clear console</button>  

Комментарии:

1. Моя функция применяется только к документу. querySelectorAll(«. Внешний»). По крайней мере, это то, что я вложил в код. Используя ваш способ, я буду прослушивать ВСЕ щелчки в теле, верно? И сравнение, чтобы увидеть, какой элемент предназначен для последующего применения функции. Это верно?

2. @KajiyamaVK Нет, ваша функция применяется не только к «. Элементы «Outer», но также и «.inner». Да, используя мой способ, я буду прослушивать ВСЕ щелчки в теле. Если вы предпочитаете, вы можете установить 3 прослушивателя событий (как вы уже сделали) с тем же кодом, что и у меня внутри, или поместить все «.outer» в контейнер div. Метод matches использует тот же синтаксис css для фильтрации элементов dom

3. Ох… Да… Из-за распространения, верно? Вот почему я использую функцию stopPropagation. Способы заставить это работать у меня есть. Я хочу знать, почему распространение не останавливается.

4. @KajiyamaVK Я изменил свой ответ, добавив дополнительные пояснения. Полезно ли это для вас?

5. Вы использовали решение и даже не заметили. lol currentTarget. Просто пришлось изменить «target» на currentTarget и все заработало. Больше ничего не создавал.

Ответ №2:

В этом случае у нас есть один внешний div — родительский, а внутренний div — дочерний.

Итак, проблема, которую нужно понять, заключается в:

цель: Кто вызвал событие. currentTarget: элемент, в котором установлена функция.

При нажатии на внутренний div вы нажимаете дочерние элементы, но элемент, у которого есть функция, является родительским. Итак, функция должна изменить currentTarget (внешний div), а не target (это внутренний div, на который был нажат).

Просто пришлось изменить

e.target.style.border=»сплошной черный размер 1 пиксель»

с

 e.currentTarget.style.border="1px solid black"