Смена цвета разным текстам с одинаковым именем класса(Всплытие и погружение)
Всем счастья и здоровья! Создал скрипт, который при наведении на блок изменяет цвет текста на красный, а затем сбрасывает его. По задумке, скрипт должен менять цвет тексту только тому блоку на который навелся курсор.
Но у меня меняется цвет текста только первого блока слева от экрана и еще цвет меняется, если навести на два соседних блока. Как исправить этот баг? Знаю, что можно дать разные имена классов в трех блоках, но это костыль, что если блоков будет не 3, а 100? В этом случае, код в CSS станет очень большим, да и в JS то же.
let News_Main_Block = document.querySelector('.Сategory_Main_Block');
let News_Name = document.querySelector('.Сategory_name_1');
News_Main_Block.addEventListener('mouseover', function(e){
let child = e.target.className;
if(child == 'Сategory_Link_1'){
News_Name.style.color = 'red';
}
});
News_Main_Block.addEventListener('mouseout', function(e){
let child = e.target.className;
if(child == 'Сategory_Link_1'){
News_Name.style.color = '';
}
});
.Сategory_Main_Block{
padding-top:2vw;
padding-bottom: 2vw;
display: grid;
grid-template-columns: repeat(6, 30%);
column-gap:1vw;
row-gap:3vw;
margin-left:2vw;
}
.Сategory_Block_1{
background:rgba(255, 255, 255, 1);
border-radius: 1.5vw;
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
margin:0;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
}
.Сategory_name_1{
text-align:center;
flex: 1;
display: flex;
align-items: center;
padding:10px;
font-size:18px;
color:black;
font-family:arial;
}
.Сategory_img_1{
border-top-right-radius: 1.5vw;
border-top-left-radius: 1.5vw;
width:100%;
height:25vw;
}
.Сategory_Link_1{
border-top-right-radius: 1.5vw;
border-top-left-radius: 1.5vw;
width:100%;
height:25vw;
position:absolute;
display:flex;
box-sizing: border-box;
}
<section class="Сategory_Main_Block">
<figure class="Сategory_Block_1">
<a class ="Сategory_Link_1" href="/"><div></div></a>
<img class="Сategory_img_1" src="https://i.ibb.co/ZW3xn2G/5-1.jpg">
<figcaption class="Сategory_name_1">1 ПЕС И ЛИСА</figcaption>
</figure>
<figure class="Сategory_Block_1">
<a class ="Сategory_Link_1" href="/"><div></div></a>
<img class="Сategory_img_1" src="https://i.ibb.co/N9L9rjq/scale-1200.webp">
<figcaption class="Сategory_name_1">2 ВОЛК И ЛАПША</figcaption>
</figure>
<figure class="Сategory_Block_1">
<a class ="Сategory_Link_1" href="/"><div></div></a>
<img class="Сategory_img_1" src="https://i.ibb.co/sHrLCtS/1412772681-kitajskaya-lapsha-v-domashnix-usloviyax.jpg">
<figcaption class="Сategory_name_1">3 КИДО И ХАДО</figcaption>
</figure>
</section>
Ответы (1 шт):
Метод .querySelector() всегда возвращает один элемент.
Для вашей задачи нужен .querySelectorAll() который возьмёт все элементы.
Ещё ошибка в том, что вы обращались не к карточкам, а их родителю
document.querySelector('.Сategory_Main_Block')
После чего нужно пройтись по коллекции элементов и каждому назначить .addEventListener(), для прохода по всем советую использовать .forEach().
Так же советую почитать отличие ивентов mouseover\mouseout с mouseenter\mouseleave, думаю в вашем случае лучше использовать второй вариант
let News_Main_Block = document.querySelector('.Сategory_Main_Block');
let News_Block = document.querySelectorAll('.Сategory_Block_1');
News_Block.forEach(function (e) {
e.addEventListener('mouseenter', function(e) {
let target = e.target,
name = target.querySelector('.Сategory_name_1');
if(name) {
name.style.color = 'red';
}
});
e.addEventListener('mouseleave', function(e) {
let target = e.target,
name = target.querySelector('.Сategory_name_1');
if(name) {
name.style.color = '';
}
});
});
.Сategory_Main_Block {
padding-top: 2vw;
padding-bottom: 2vw;
display: grid;
grid-template-columns: repeat(6, 30%);
column-gap: 1vw;
row-gap: 3vw;
margin-left: 2vw;
}
.Сategory_Block_1 {
background: rgba(255, 255, 255, 1);
border-radius: 1.5vw;
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
margin: 0;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
}
.Сategory_name_1 {
text-align: center;
flex: 1;
display: flex;
align-items: center;
padding: 10px;
font-size: 18px;
color: black;
font-family: arial;
}
.Сategory_img_1 {
border-top-right-radius: 1.5vw;
border-top-left-radius: 1.5vw;
width: 100%;
height: 25vw;
}
.Сategory_Link_1 {
border-top-right-radius: 1.5vw;
border-top-left-radius: 1.5vw;
width: 100%;
height: 25vw;
position: absolute;
display: flex;
box-sizing: border-box;
}
<section class="Сategory_Main_Block">
<figure class="Сategory_Block_1">
<a class="Сategory_Link_1" href="/">
<div></div>
</a>
<img class="Сategory_img_1" src="https://i.ibb.co/ZW3xn2G/5-1.jpg">
<figcaption class="Сategory_name_1">1 ПЕС И ЛИСА</figcaption>
</figure>
<figure class="Сategory_Block_1">
<a class="Сategory_Link_1" href="/">
<div></div>
</a>
<img class="Сategory_img_1" src="https://i.ibb.co/N9L9rjq/scale-1200.webp">
<figcaption class="Сategory_name_1">2 ВОЛК И ЛАПША</figcaption>
</figure>
<figure class="Сategory_Block_1">
<a class="Сategory_Link_1" href="/">
<div></div>
</a>
<img class="Сategory_img_1" src="https://i.ibb.co/sHrLCtS/1412772681-kitajskaya-lapsha-v-domashnix-usloviyax.jpg">
<figcaption class="Сategory_name_1">3 КИДО И ХАДО</figcaption>
</figure>
</section>
Ответы на вопросы:
Благодарю, почему в моём случае лучше использовать mouseenter/mouseleave? А если блоков будет 100, то в этом случае ваш способ не приведет ли к проблеме с оптимизацией/производительностью?
mouseover\mouseoutвешается на элемент и вызывает событие когда мышь наводится на этот или дочерний элемент, так жеtargetбудет возвращать элемент на котором находится курсор.
В то время какmouseenter\mouseleaveигнорирует вложенные элементы и генерирует событие только при наведение на блок, на котором вызван.
В этом примере это хорошо видно.100 блоков в любом случае будет влиять на производительность, это уже другой вопрос.
------------------------------
А зачем аргумент (e) в родительской функции перебора News_Block.forEach(function (e)? Что выступает в качестве аргумента функции?
Функции могут что-то возвращать (callback), в данном случае .addEventListener('mouseenter') возвращаешь объект в переменную e, в которую мы указали (e сокращённо от event).
В переменной e различная информация соответствующая выбранному ивенту, но нам нужен именно e.target - в нём содержится информация о элемент, в котором данный ивент сработал.
У вас каждая карточка с событием mouseenter, если на вести на вторую, то e.target будет ссылкой на вторую карточку.
------------------------------
У меня еще остался последний вопрос: forEach это же метод перебора для массива? Но у меня нет массива, или я чего-то не понимаю?
Почти, .querySelectorAll() возвращает коллекцию элементов в NodeList, это не совсем массив, но .forEach() его может обработать.
Обычно такое действие заменяют на [...NodeList].map(e => {}) - где NodeList "конвертируется" в массив при помощи оператора Spread [...] и .map() уже проходит по всем элементам.
Но это более новый спецификации JS и без "компиляторов" под старые браузеры, типо Babel - лучше не использовать. Да и пока это вам не нужно