#javascript #html
#javascript #HTML
Вопрос:
Прежде всего — я новичок. Извините, если этот вопрос достаточно простой. Второе — я попытался выполнить поиск и, как я вижу, применил решение в соответствии с инструкциями в других сообщениях.
С учетом сказанного… У меня есть три набора DIVS. Каждый набор состоит из 2 разделов (один внутри другого). Во ВНЕШНЕМ div есть функция, которая предлагает создать границу, если на нее щелкнуть.
Чтобы увидеть ошибку:
- Нажмите на слово OUTER.
- Нажмите на слово 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"