How could I simplify this code? JavaScript + css3

Viewed 107

I'm fairly new to programming and still getting the hang of programming logic. I've wasted a few hours trying to simplify this code but no cigar. Given the fact that the base of programming is to simplify tasks, how could I make the following code shorter?

var card1 = document.getElementById('card1');
var card2 = document.getElementById('card2');
var card3 = document.getElementById('card3');
var card4 = document.getElementById('card4');

// card 1
card1.addEventListener('mouseenter', function(){
    card2.classList.add('blur');
    card3.classList.add('blur');
    card4.classList.add('blur');
})

card1.addEventListener('mouseleave', function(){
    card2.classList.remove('blur');
    card3.classList.remove('blur');
    card4.classList.remove('blur');
})

// card 2
card2.addEventListener('mouseenter', function(){
    card1.classList.add('blur');
    card3.classList.add('blur');
    card4.classList.add('blur');
})

card2.addEventListener('mouseleave', function(){
    card1.classList.remove('blur');
    card3.classList.remove('blur');
    card4.classList.remove('blur');
})

// card 3
card3.addEventListener('mouseenter', function(){
    card1.classList.add('blur');
    card2.classList.add('blur');
    card4.classList.add('blur');
})

card3.addEventListener('mouseleave', function(){
    card1.classList.remove('blur');
    card2.classList.remove('blur');
    card4.classList.remove('blur');
})

// card 4
card4.addEventListener('mouseenter', function(){
    card1.classList.add('blur');
    card2.classList.add('blur');
    card3.classList.add('blur');
})

card4.addEventListener('mouseleave', function(){
    card1.classList.remove('blur');
    card2.classList.remove('blur');
    card3.classList.remove('blur');
})

Thanks in advance, Thiago

EDIT: I was eventually able to come up with something, based on @CertainPerformance's answer, that met my needs:

const cards = document.querySelectorAll('.modalidade__card');
const cardsArray = Array.apply(null, cards);
for (let i = 0; i < cardsArray.length; i++) {
    cardsArray[i].addEventListener('mouseenter', (e) => {
        for (let c = 0; c < cardsArray.length; c++) {
            cardsArray[c].classList.add('blur');
        };
        e.target.classList.remove('blur');
    });
    cardsArray[i].addEventListener('mouseleave', (e) => {
        for (let c = 0; c < cardsArray.length; c++) {
            if (cardsArray[c].classList.contains('blur')) {
                cardsArray[c].classList.remove('blur');
            };
        };
    });
};

4 Answers

You can use classes instead of IDs to get a collection of all cards. Then you can use event delegation on the container of all the cards. When one of the cards is entered, loop over the collection and blur the rest. When one of the cards is left, loop over the collection and remove the blur:

const cards = document.querySelectorAll('.card');
container.addEventListener('mouseover', (e) => {
  if (e.target.matches('.card')) {
    for (const card of cards) {
      card.classList.add('blur');
    }
    e.target.classList.remove('blur');
  }
});
container.addEventListener('mouseout', (e) => {
  if (e.target.matches('.card')) {
    for (const card of cards) {
      card.classList.remove('blur');
    }
  }
});

Note that for event delegation to work, you have to use an event that bubbles - mouseover and mouseout bubble, but mouseenter and mouseleave don't. (Or you could iterate over each card and add a listener to each with mouseenter and mouseleave)

You could use the css :hover pseudo-selector instead of javascript.

.cards {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
  list-style: none;
  margin: 0;
  padding: 0;
  pointer-events: none;
}

li {
    pointer-events: auto;
}
.cards:hover > * {
  filter: blur(5px);
  transition: filter .1s;
}

.cards > * {
  padding: 2rem;
  margin: 8px;
  background: bisque;
}

.cards > *:hover {
  filter: none;
}
<ul class="cards">
  <li>Card 1</li>
  <li>Card 2</li>
  <li>Card 3</li>
  <li>Card 4</li>  
</ul>

For example, we can

var card1 = document.getElementById('card1');
var card2 = document.getElementById('card2');
var card3 = document.getElementById('card3');
var card4 = document.getElementById('card4');

var mouseenter = function(){
    if(this != card1) card1.classList.add('blur');
    if(this != card2) card2.classList.add('blur');
    if(this != card3) card3.classList.add('blur');
    if(this != card4) card4.classList.add('blur');
};
var mouseleave = function(){
    if(this != card1) card1.classList.remove('blur');
    if(this != card2) card2.classList.remove('blur');
    if(this != card3) card3.classList.remove('blur');
    if(this != card4) card4.classList.remove('blur');
};

card1.addEventListener('mouseenter', mouseenter);
card1.addEventListener('mouseleave', mouseleave);
card2.addEventListener('mouseenter', mouseenter);
card2.addEventListener('mouseleave', mouseleave);
card3.addEventListener('mouseenter', mouseenter);
card3.addEventListener('mouseleave', mouseleave);
card4.addEventListener('mouseenter', mouseenter);
card4.addEventListener('mouseleave', mouseleave);

Try the following way

const card1 = document.getElementById("card1"),
  card2 = document.getElementById("card2"),
  card3 = document.getElementById("card3"),
  card4 = document.getElementById("card4");

// onMouse Effect
const onMouse = (ele, type = "enter") => {
  ele.forEach((item) =>
    type === "enter"
      ? item.classList.add("blur")
      : item.classList.remove("blur")
  );
};
// Card 1
card1.addEventListener("mouseenter", () => onMouse([card2, card3, card4]));
card1.addEventListener("mouseleave", () =>
  onMouse([card2, card3, card4], "leave")
);
// Card 2
card2.addEventListener("mouseenter", () => onMouse([card1, card3, card4]));
card2.addEventListener("mouseleave", () =>
  onMouse([card1, card3, card4], "leave")
);
// Card 3
card3.addEventListener("mouseenter", () => onMouse([card2, card1, card4]));
card3.addEventListener("mouseleave", () =>
  onMouse([card2, card1, card4], "leave")
);
// Card 4
card4.addEventListener("mouseenter", () => onMouse([card2, card3, card1]));
card4.addEventListener("mouseleave", () =>
  onMouse([card2, card3, card1], "leave")
);
.cursor-pointer {
  cursor: pointer;
}
h1 {
  font-size: 2em;
}
.blur h1 {
  font-size: 1em;
  text-align: center;
  color: transparent;
  text-shadow: #111 0 0 15px;
  transition: 0.4s;
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link
      rel="stylesheet"
      href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
      integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
      crossorigin="anonymous"
    />
  </head>
  <body>
    <section class="container">
      <div class="p-5 m-5 text-center bg-primary cursor-pointer" id="card1">
        <h1>Card 1</h1>
      </div>
      <div class="p-5 m-5 text-center bg-primary cursor-pointer" id="card2">
        <h1>Card 2</h1>
      </div>
      <div class="p-5 m-5 text-center bg-primary cursor-pointer" id="card3">
        <h1>Card 3</h1>
      </div>
      <div class="p-5 m-5 text-center bg-primary cursor-pointer" id="card4">
        <h1>Card 4</h1>
      </div>
    </section>
  </body>
</html>

Related