当用香草 javascript 关闭模态时,从正文中删除 class

Remove class from body when modal is closed with vanilla javascript

我的页面上有多个模态框,当单击相应按钮时会打开这些模态框。 当模式打开时,它会将 class .has-modal-open 添加到正文以防止页面滚动。 问题是当我关闭模态时 class 没有从正文标签中删除。我试过 body.classList.remove('has-modal-open'); 但出于某种原因它就是行不通。 我正在寻找香草 javascript 解决方案。

谢谢。

  const modal = document.querySelectorAll('.modal');
  const modalOpenButtons = document.querySelectorAll('[data-open-modal]');
  const modalCloseButtons = document.querySelectorAll('[data-close-modal]');
  const body = document.querySelector('body');
  
  for (let i = 0; i < modalOpenButtons.length; i++) {
    const modalOpenButton = modalOpenButtons[i];
    modalOpenButton.addEventListener('click', e => {
      body.classList.add('has-modal-open');
      const modalDataAttribute = e.target.getAttribute('data-open-modal');
      document.querySelector('.modal[data-open-modal=\''.concat(modalDataAttribute, '\']')).classList.add('modal--is-open');
    });
  }
  
  for (let i = 0; i < modalCloseButtons.length; i++) {
    body.classList.remove('has-modal-open');
    const modalCloseButton = modalCloseButtons[i];
    modalCloseButton.addEventListener('click', e => {
      e.target.closest('.modal').classList.remove('modal--is-open');
    });
  }
  
  for (let i = 0; i < modal.length; i++) {
    const modals = modal[i];
    document.addEventListener('keydown', e => {
      if (e.keyCode === 27) {
        modals.classList.remove('modal--is-open')
      }
    })
    modals.addEventListener('click', e => {
      e.target.classList.remove('modal--is-open')
    })
  }
.modal {
  display: none;
  justify-content: center;
  align-items: center;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  max-height: calc(100% - 48px);
  background: rgba(0, 0, 0, 0.45);
  z-index: 90;
}

.modal__header {
  position: relative;
  border-radius: 4px 4px 0 0;
  background-color: white;
  width: 100%;
  min-height: 60px;
  overflow: auto;
}

.modal__body {
  position: relative;
  width: calc(100% - 48px);
  max-width: 900px;
  max-height: calc(100% - 48px);
  overflow: hidden;
  border-radius: 4px;
  max-height: 700px;
  background: white;
}

.modal__content {
  padding: 0 40px 40px;
  overflow: auto;
  height: 100px;
}

.modal--is-open {
  display: flex;
}

.has-modal-open {
  overflow-y: hidden;
}


.modal__close {
  position: absolute;
  top: 32px;
  right: 12px;
  transform: translateY(-50%);
  width: 56px;
  height: 56px;
  padding: 0;
}
<button class="button" data-open-modal="open-modal-1">Open modal</button>

<div class="modal" data-open-modal="open-modal-1">
  <div class="modal__body">
    <div class="modal__header">
      <button class="modal__close" data-close-modal>X</button>
    </div>
    <div class="modal__content">
      My modal
    </div>
  </div>
</div>

你的错误只是说

"message": "Uncaught TypeError: Cannot read properties of null (reading 'classList')",

这意味着在您的代码中 body 代表 null 发生这种情况可能有多种原因 一个可能是你没有以正确的方式访问它

您的代码有 2 个问题:

  • body.classList.remove('has-modal-open'); 应该在关闭按钮的 eventListener 内部调用,但您之前调用了它。
  • modalOpenButtons = document.querySelectorAll('[data-open-modal]'); 不仅选择按钮,还选择具有属性 data-open-modal 的模式。当您单击关闭按钮时,模式也会被单击,因此在您的情况下调用附加到 modalOpenButtons 的 eventListener。您应该只将按钮放在 modalOpenButtons 中,例如:

const modalOpenButtons = document.querySelectorAll('button[data-open-modal]');

我在下面制作了一个片段,您可以在其中看到 class 正确地得到 added/removed

const modal = document.querySelectorAll('.modal');
  const modalOpenButtons = document.querySelectorAll('button[data-open-modal]');
  const modalCloseButtons = document.querySelectorAll('[data-close-modal]');
  const body = document.querySelector('body');
  
  for (let i = 0; i < modalOpenButtons.length; i++) {
    const modalOpenButton = modalOpenButtons[i];
    modalOpenButton.addEventListener('click', e => {
      body.classList.add('has-modal-open');
      const modalDataAttribute = e.target.getAttribute('data-open-modal');
      //document.querySelector(`.modal[data-open-modal="${modalDataAttribute}"]`).classList.add('modal--is-open');
      document.querySelector('.modal[data-open-modal=\''.concat(modalDataAttribute, '\']')).classList.add('modal--is-open');
    });
  }
  
  for (let i = 0; i < modalCloseButtons.length; i++) {
    const modalCloseButton = modalCloseButtons[i];
    modalCloseButton.addEventListener('click', e => {
      body.classList.remove('has-modal-open');
      e.target.closest('.modal').classList.remove('modal--is-open');
    });
  }
  
  for (let i = 0; i < modal.length; i++) {
    const modals = modal[i];
    document.addEventListener('keydown', e => {
      if (e.keyCode === 27) {
        modals.classList.remove('modal--is-open')
      }
    })
    modals.addEventListener('click', e => {
      e.target.classList.remove('modal--is-open')
    })
  }
.modal {
  display: none;
  justify-content: center;
  align-items: center;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  max-height: calc(100% - 48px);
  background: rgba(0, 0, 0, 0.45);
  z-index: 90;
}

.modal__header {
  position: relative;
  border-radius: 4px 4px 0 0;
  background-color: white;
  width: 100%;
  min-height: 60px;
  overflow: auto;
}

.modal__body {
  position: relative;
  width: calc(100% - 48px);
  max-width: 900px;
  max-height: calc(100% - 48px);
  overflow: hidden;
  border-radius: 4px;
  max-height: 700px;
  background: white;
}

.modal__content {
  padding: 0 40px 40px;
  overflow: auto;
  height: 100px;
}

.modal--is-open {
  display: flex;
}

.has-modal-open {
  overflow-y: hidden;
}


.modal__close {
  position: absolute;
  top: 32px;
  right: 12px;
  transform: translateY(-50%);
  width: 56px;
  height: 56px;
  padding: 0;
}
<button class="button" data-open-modal="open-modal-1">Open modal</button>

<div class="modal" data-open-modal="open-modal-1">
  <div class="modal__body">
    <div class="modal__header">
      <button class="modal__close" data-close-modal>X</button>
    </div>
    <div class="modal__content">
      My modal
    </div>
  </div>
</div>