如何减少JavaScript事件监听器的重复性?

时间:2018-12-14 11:21:02

标签: javascript addeventlistener

我在思考优化此代码块的新方法时遇到了一些麻烦。现在,它看起来过于重复和冗长。我可以将函数与EventListener分开编写,但只会编写更多行代码,甚至更长。

let modalIntro = document.getElementById('modal-intro');
let buttonIntro = document.getElementById('button-intro');
let close = document.getElementsByClassName('close')[0];

buttonIntro.addEventListener ('click', function(){
    modalIntro.classList.remove("out");
    modalIntro.classList.add("in");
});

close.addEventListener('click', function (){
    modalIntro.classList.add("out");
});

let modalWork = document.getElementById('modal-work');
let buttonWork = document.getElementById('button-work');
let close1 = document.getElementsByClassName('close')[1];

buttonWork.addEventListener ('click', function(){
    modalWork.classList.remove("out");
    modalWork.classList.add("in");
});

close1.addEventListener('click', function (){
    modalWork.classList.add("out");
});

let modalAbout = document.getElementById('modal-about');
let buttonAbout = document.getElementById('button-about');
let close2 = document.getElementsByClassName('close')[2];

buttonAbout.addEventListener ('click', function(){
    modalAbout.classList.remove("out");
    modalAbout.classList.add("in");
});

close2.addEventListener('click', function (){
    modalAbout.classList.add("out");
});

let modalContact = document.getElementById('modal-contact');
let buttonContact = document.getElementById('button-contact');
let close3 = document.getElementsByClassName('close')[3];

buttonContact.addEventListener ('click', function(){
    modalContact.classList.remove("out");
    modalContact.classList.add("in");
});

close3.addEventListener('click', function (){
    modalContact.classList.add("out");
});

任何帮助将不胜感激。

5 个答案:

答案 0 :(得分:1)

看到您有一个通用的命名模式,并假设关闭按钮是每个模式的子代,则可以执行以下操作:

注意,我在关闭按钮上添加了modal.classList.remove('in');

解决方案

function bindModals(modals) {
  modals.forEach(name => {
    let modal = document.getElementById(`modal-${name}`)
    let button = document.getElementById(`button-${name}`)
    let close = modal.querySelector('.close');

    button.addEventListener ('click', function(){
      modal.classList.remove('out');
      modal.classList.add('in');
    });
    close.addEventListener('click', function (){
      modal.classList.remove('in');
      modal.classList.add('out');
    });
  });
}
bindModals(['intro', 'work', 'about', 'contact'])
.out {
  display: none;
}
.in {
  display: block;
  border: 1px solid red;
  height: 200px;
  width: 400px;
}
<section>
  <button id="button-intro">Intro</button>
  <button id="button-work">Work</button>
  <button id="button-about">About</button>
  <button id="button-contact">Contact</button>
</section>
<section id="modal-intro" class="out">
  <button class="close">Close</button>
  <p>Intro Modal</p>
</section>
<section id="modal-work" class="out">
  <button class="close">Close</button>
  <p>Work Modal</p>
</section>
<section id="modal-about" class="out">
  <button class="close">Close</button>
  <p>About Modal</p>
</section>
<section id="modal-contact" class="out">
  <button class="close">Close</button>
  <p>Contact Modal</p>
</section>

答案 1 :(得分:0)

最简单的方法就是简单地创建一个函数:

function MakeModal(modalId, buttonId, closeId)
    let modal = document.getElementById(modalId);
    let button = document.getElementById(buttonId);
    let close = document.getElementsById(closeId);

    button.addEventListener ('click', function(){
        modal.classList.remove("out");
        modal.classList.add("in");
    });

    close.addEventListener('click', function (){
        modal.classList.add("out");
    });
}

然后您可以调用:

MakeModal('modal-intro', 'button-into', 'close-intro');
MakeModal('modal-about', 'button-about', 'close-about');
MakeModal('modal-contact', 'button-contact', 'close-contact');

那只是编程基础:DRY

请注意,您需要在关闭按钮而不是类中添加ID(或者您可以将其重写为let close = modal.find('.close');或其他内容,在这种情况下,您可以摆脱第三个参数closeId )。而且,如果您严格遵守此处使用的命名约定,甚至可以简化多个MakeModal(...)调用:

['intro', 'about', 'contact'].forEach(function(e) { 
    MakeModal('modal-' + e, 'button-' + e, 'close-' + e); 
});

或者,如果您摆脱了第三个参数并使用了.find(...)建议:

['intro', 'about', 'contact'].forEach(function(e) { 
    MakeModal('modal-' + e, 'button-' + e); 
});

无论如何我都不是jQuery专家,但如果我没记错的话

modal.classList.remove("out");
modal.classList.add("in");

可以写为:

modal.classList.switchClass("out", "in");

答案 2 :(得分:0)

您可以使用函数获取元素ID以使其更短:

function getElem(el) {
  return document.getElementById(el);
}

现在删除以下所有代码:

let modalIntro = document.getElementById('modal-intro');
let buttonIntro = document.getElementById('button-intro');

let modalWork = document.getElementById('modal-work');
let buttonWork = document.getElementById('button-work');


let modalContact = document.getElementById('modal-contact');
let buttonContact = document.getElementById('button-contact');

–并用getElem('elem-id')替换变量,例如下面的

    getElem('modal-intro').classList.remove("out");
    getElem('modal-intro').classList.add("in");

类似地,您可以使通用函数按类获取Element并添加事件侦听器。

答案 3 :(得分:0)

如果没有任何HTML,我不确定这是否会非常准确,但是我可以尝试一下。

我看到每个模式的行为方式都相同...我将向每个按钮添加一个属性,以标识它激活了哪个模式,并添加一个类,以便我们可以引用所有这些模式:

<input type="button" value="intro" class="modalButton" id="button-intro" data-activates="modal-intro">
<input type="button" value="work" class="modalButton" id="button-work" data-activates="modal-work">
<input type="button" value="about" class="modalButton" id="button-about" data-activates="modal-about">
<input type="button" value="contact" class="modalButton" id="button-contact" data-activates="modal-contact">

现在,我们可以使用以下代码行来引用和操作:

document.getElementsByClassName("modalButton").forEach(function(btn) {
    btn.addEventListener ('click', function() {
        var modal = document.getElementById(btn.getAttribute("data-activates"));
        modal.classList.remove("out");
        modal.classList.add("in");
    });
});

假设模态中的按钮是这样的:

<!-- Example of a modal with a close button -->
<div id="modal-intro" class="modal out">
    <input type="button" class="close" value="close">
    <!-- content -->
</div>

我们可以通过在DOM树中向上移动来进入模态:

document.getElementsByClassName("close").forEach(function(closeBtn) {
    closeBtn.addEventListener ('click', function(){
        // In this case the modal is the button's parent
        closeBtn.parentElement.classList().remove("in");
        closeBtn.parentElement.classList().add("out");
        // P.S I also suppose you want to remove the "in" class
    });
});

奇怪的是,如果按钮位于模式内部更深的位置,则只需调用'parentElement'属性,直到获得它为止。

答案 4 :(得分:0)

这是使用具有相同结构乘以三的事实的另一种方法。 如果我使用jQuery,这会短很多,但由于您似乎并未使用它,所以我将其保留为香草:

document.querySelectorAll("nav a").forEach(a => a.addEventListener("click", function(e) {
  e.preventDefault(); // don't navigate to href
  // hide all modals, i.e. remove the one potentially still open
  document.querySelectorAll("#modals > div").forEach(modal => modal.classList.remove("in"));
  // finally, show modal
  document.getElementById(this.dataset.modal).classList.add("in");
}));

document.querySelectorAll("#modals > div").forEach(modal =>
  // for each modal, grab its close button
  modal.querySelector(".close").addEventListener("click", function(e) {
    e.preventDefault(); // don't navigate to href
    modal.classList.remove("in"); // and hide the modal
  })
);
#modals>div {
  position: fixed;
  width: 50%;
  left: 25%;
  box-sizing: border-box;
  border: 1px solid black;
  padding: 0.5em;
  top: -300px;
  transition: .5s
}

#modals .close {
  float: right
}

.in {
  top: 50px !important;
}
<nav>
  <a data-modal="intro" href="">Intro</a>
  <a data-modal="work" href="">Work</a>
  <a data-modal="about" href="">About</a>
</nav>
<div id="modals">
  <div id="intro"><a href="" class="close">X</a>
    <p>Intro modal</p>
  </div>
  <div id="work"><a href="" class="close">X</a>
    <p>Work modal</p>
  </div>
  <div id="about"><a href="" class="close">X</a>
    <p>About modal</p>
  </div>
</div>

通过通过菜单链接的data-modal将代码指向模式,我不再需要使用任何特定于元素的代码,从而实现了理想的可重用代码。