Как переключать стиль элемента как при наведении, так и при нажатии?

#javascript #css

#javascript #css

Вопрос:

У меня есть 4 круга SVG, и я хочу переключать их стиль при наведении и при нажатии. Я хочу, чтобы при щелчке по одному кругу одновременно отображался стиль, т.Е. Стиль удаляется из одного круга при щелчке по другому. Наведение работает с использованием CSS, но мой JavaScript не совсем корректен.

Он удаляет стиль из одного круга при нажатии на другой, но не позволяет переключать класс стиля из активного целевого круга. Также как я могу удалить стиль из круга, если щелкнуто что-либо за пределами кругов SVG?

 var circles = document.querySelectorAll('.svgcircle')
circles = Array.prototype.slice.call(circles);


for (i = 0; i < circles.length; i  ) {

  (function(index) {
    circles[index].addEventListener("click", function() {

      var targetcircle = event.target;

      for (var j = 0; j < circles.length; j  ) {
        circles[j].classList.remove("circleTarget");
      }

      targetcircle.classList.toggle("circleTarget");

    })
  })(i);
} 
 html,
body {
  height: 100%;
  width: 100%;
  overflow: hidden;
}

svg {
  position: absolute;
  top: 35%;
  left: 50%;
  margin-left: -200px;
  padding: 10px;
}

svg circle {
  fill: #B5EF8A;
  cursor: pointer;
  stroke: #56CBF9;
  stroke-width: 2px;
}

svg circle:hover {
  fill: #fff;
  stroke: #56CBF9;
}

.circleTarget {
  fill: #fff;
  stroke: #56CBF9;
} 
 <svg height="100" width="400" id="svg">
       <circle class="svgcircle" cx="50" cy="50" r="40" />
       <circle class="svgcircle" cx="150" cy="50" r="40" />     
       <circle class="svgcircle" cx="250" cy="50" r="40" />
       <circle class="svgcircle" cx="350" cy="50" r="40" />
</svg> 

Большое спасибо.

Ответ №1:

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

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

Кроме того, поскольку вы преобразуете свои круги в массив, используйте Array.forEach() метод to loop , который намного проще, чем управление индексами цикла.

Смотрите Комментарии встроенные:

 var circles = Array.prototype.slice.call(document.querySelectorAll('.svgcircle'));

// Setting the event listener on the document, kills two birds
// with one stone. It removes the need to set click event handlers
// on each circle and it allows for easy checking to see if you
// clicked on anything other than a circle.
document.addEventListener("click", function(evt){
  // Check to see if the clicked element was one of the circles:
  if(evt.target.classList.contains("svgcircle")){
    // It was, so capture whether the clicked circle is active already
    let active = evt.target.classList.contains("circleTarget");
  
    removeClass(); // Reset the class usage on all the circles
    
    // If the clicked circle was active, deactivate it. 
    // Otherwise, activate it:
    if(active){
      evt.target.classList.remove("circleTarget");
    } else {
      evt.target.classList.add("circleTarget");
    }  
  } else {
    // It wasn't, so clear all the styling from all the circles
    removeClass();
  }
});

function removeClass(){
    // Loop over all the circles and remove the target class
    circles.forEach(function(cir){
      cir.classList.remove("circleTarget");
    });
} 
 html,
body {
  height: 100%;
  width: 100%;
  overflow: hidden;
}

svg {
  position: absolute;
  top: 35%;
  left: 50%;
  margin-left: -200px;
  padding: 10px;
}

svg circle {
  fill: #B5EF8A;
  cursor: pointer;
  stroke: #56CBF9;
  stroke-width: 2px;
}

svg circle:hover {
  fill: #fff;
  stroke: #56CBF9;
}

.circleTarget {
  fill: #fff;
  stroke: #56CBF9;
} 
 <svg height="100" width="400" id="svg">
       <circle class="svgcircle" cx="50" cy="50" r="40" />
       <circle class="svgcircle" cx="150" cy="50" r="40" />     
       <circle class="svgcircle" cx="250" cy="50" r="40" />
       <circle class="svgcircle" cx="350" cy="50" r="40" />
</svg> 

Ответ №2:

Это будет работать так, как вы ожидаете:

 let circles = Array.from(document.querySelectorAll('.svgcircle'));

circles.forEach(circle => {
  circle.addEventListener("click", ({target}) => {
    circles.forEach(c => target !== c amp;amp; c.classList.remove("circleTarget"));
    target.classList.toggle("circleTarget");
  })
});

// Remove class if anything else is clicked
document.body.addEventListener('click', ({target}) =>
  !Array.from(target.classList).includes('svgcircle') 
  amp;amp; circles.forEach(c => c.classList.remove("circleTarget"))); 
 html,
body {
  height: 100%;
  width: 100%;
  overflow: hidden;
}

svg {
  position: absolute;
  top: 35%;
  left: 50%;
  margin-left: -200px;
  padding: 10px;
}

svg circle {
  fill: #B5EF8A;
  cursor: pointer;
  stroke: #56CBF9;
  stroke-width: 2px;
}

svg circle:hover {
  fill: #fff;
  stroke: #56CBF9;
}

.circleTarget {
  fill: #fff;
  stroke: #56CBF9;
} 
 <svg height="100" width="400" id="svg">
       <circle class="svgcircle" cx="50" cy="50" r="40" />
       <circle class="svgcircle" cx="150" cy="50" r="40" />     
       <circle class="svgcircle" cx="250" cy="50" r="40" />
       <circle class="svgcircle" cx="350" cy="50" r="40" />
</svg> 

Надеюсь, это поможет,

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

1. Это справедливый момент, я обновил свой ответ. .forEach() это было мое намерение, просто, должно быть, вылетело из головы в то время