Как удалить прослушиватель событий из функции

#javascript #function

#javascript #функция

Вопрос:

Я использую сборку аккордеона из школ W3. Это отлично работает, но я хотел бы немного навести порядок, создав для этого функцию в моем JS-файле (а не встроенные <script> теги). Проблема в том, что мне нужно немного подправить его, удалив прослушиватель событий, но мне не повезло (все еще изучаю JS). Как я могу этого добиться?

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

HTML:

 <button class="accordion" onclick="faqsAccordion()">Section 1</button>
<div class="panel">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>
 

JS

 function faqsAccordion() {
  var acc = document.getElementsByClassName("accordion");
  var i;

  for (i = 0; i < acc.length; i  ) {
    acc[i].addEventListener("click", function() {
      this.classList.toggle("faqs-active");
      var panel = this.nextElementSibling;
      if (panel.style.maxHeight) {
        panel.style.maxHeight = null;
      } else {
        panel.style.maxHeight = panel.scrollHeight   "px";
      } 
    });
  }
}
 

Ответ №1:

Суть

Сохраните версию функции, которую вы используете в качестве прослушивателя событий, например

 function MyHandler(){
    console.log("clicked!");
}
document.getElementById("MyButton").addEventListener("click", MyHandler);
 

затем вы можете позже удалить его, просто используя то же имя функции.

 document.getElementById("MyButton").removeEventListener("click", MyHandler);
 

Если вы настаиваете на использовании onclick свойства, вы также можете установить для него значение null вручную в коде; однако я не рекомендую это. onclick в HTML сбивает с толку, он выполняет код внутри строки, а не просто устанавливает обработчик события «click» для функции с таким именем.

 document.getElementById("MyButton").onclick = null;
 

Как ни странно, изменение его на другую строку не работает. Многие из этих старых атрибутов HTML, приклеенных к JS, работают нелогичными способами. Это не работает, потому что свойство onclick принимает указатель на функцию и отказывается от чего-либо еще, в то время как атрибут onclick принимает строку, которая выполняется.

Что вы хотите сделать

Вы хотите превратить это

 function faqsAccordion() {
  var acc = document.getElementsByClassName("accordion");
  var i;

  for (i = 0; i < acc.length; i  ) {
    acc[i].addEventListener("click", function() {
      this.classList.toggle("faqs-active");
      var panel = this.nextElementSibling;
      if (panel.style.maxHeight) {
        panel.style.maxHeight = null;
      } else {
        panel.style.maxHeight = panel.scrollHeight   "px";
      } 
    });
  }
}
 

В это

 <button class="accordion" id="faqsAccordian">Section 1</button>
<div class="panel">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
</div>
 
 document.getElementById("faqsAccordian").addEventListener("click",faqsAccordian);
function myfunc(e){ // Added the "event" parameter for you, for future use :)
  this.classList.toggle("faqs-active");
  var panel = this.nextElementSibling;
  if (panel.style.maxHeight) {
    panel.style.maxHeight = null;
  } else {
    panel.style.maxHeight = panel.scrollHeight   "px";
  } 
}
function faqsAccordion() {
  var acc = document.getElementsByClassName("accordion");
  var i;
  
  for (i = 0; i < acc.length; i  ) {
    acc[i].addEventListener("click", myfunc);
  }
}
// ... some time later...
var acc = document.getElementsByClassName("accordion");
const whichever = 0;

// Randomly remove an event listener... muahuahua...
acc[whichever].removeEventListener("click", myfunc);

 

Однако…

Что, если вы хотите использовать анонимные функции, потому что хотите, чтобы многие из тех же функций действовали как прослушиватель событий? Допустим, мы хотим, чтобы при нажатии кнопки MyButton ниже появилось еще одно окно с предупреждением.

 <html>
<body>
<button id="MyButton">Add alert to the bottom button</button><br>
<button id="MyAlertButton">Popup please!</button>

<script>
var MyAlertButtonFunctionPointers = [];
function MyAlertButtonClickWrapper(e){
    MyAlertButtonFunctionPointers.forEach(f=>f(e))
}
document.getElementById("MyAlertButton").addEventListener("click", MyAlertButtonClickWrapper);

document.getElementById("MyButton").addEventListener("click", function(e){
  MyAlertButtonFunctionPointers.push(e=>{
    alert("Hi! I'm a button with the name "   this.id   "nThe event that lead to me being clicked happened at ("   e.screenX   ", "   e.screenY   ")"); 
  })
})
</script>
</body>
</html>
 

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

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

1. Спасибо за ответ. Я немного запутался в том, как реализовать это в моей ситуации. Не могли бы вы уточнить?

2. Ах, извините, неправильно истолковал ваш вопрос. Вы бы сделали эту анонимную функцию (ту, которая устанавливает высоту панелей на значение null или scrollHeight и переключает classlist с / class faq-active) именованной функцией и просто добавили ее в качестве прослушивателя событий. При вызове функций вызывающий объект передает их контекст — «this» все равно приведет к объекту button, на который вы хотите повлиять. Добавил ответ в качестве правки.

3. Спасибо за обновление! Используется ли это с или без onclick ? Я вставил ваш код, и мне все равно нужно дважды щелкнуть, чтобы активировать аккордеон.

4. мой код не касается onclick; предполагается, что вы ранее добавили к своей первой кнопке accordian прослушиватель событий faqsAccordian. Если вам нужно индивидуальное поведение для определенного элемента, я рекомендую присвоить ему идентификатор, чтобы упростить задачу. Если вы действительно хотите, вы можете просто getElementsByClassName("accordian") использовать индекс, в котором, как вы знаете, будет находиться эта кнопка. Я обновил свой код, чтобы он соответствовал вашему; то, что я написал, теперь должно быть доступно для вас.

5. Я точно подключил ваш код (не анонимный), но он не работает. Консоль выдает эту ошибку в JS: «Uncaught TypeError: не удается прочитать свойство ‘addEventListener’ null»