【问题标题】:How to Fix 'One Closing Button Closes All Modals'如何修复“一个关闭按钮关闭所有模态”
【发布时间】:2019-09-23 07:08:37
【问题描述】:

我正在尝试创建一个 vanilla JavaScript 模态,当从 HTML 文件(或 JS 文件)实例化它时,它能够由用户自定义。但是,在处理 close() 函数关闭模态时,不是一次关闭一个模态,而是使用其关闭按钮,第一个模态的关闭按钮关闭页面的所有模态。我不确定我做错了什么......

我研究了其他类似的 vanilla JavaScript、可定制的模态库,但它们中的大多数要么使用 jQuery,要么使用一些框架,或者包含很多我不熟悉的复杂性(我还是个初学者)。我在 GitHub、CodePen、Google 和这里​​进行了研究;但我还没有找到满足我需要的解决方案。

由于代码比较长,建议你直接去我的CodePen账户,在那里你可以得到完整的代码。

https://codepen.io/jdriviere/pen/zYOyJvv?editors=0011

但这是我的 close() 函数:

Modal.prototype.close = function() {
  let modal = document.getElementById(this.options.id);
  let modalBody = modal.children[0];

  // Delete elements from Modal Body
  for (let i = 0; i < modalBody.children.length; i++) {
    modalBody.removeChild(modalBody.children[i]);
  } // End of LOOP

  // Delete Modal Body from Modal
  modal.removeChild(modalBody);

  // Delete Modal from DOM
  modal.style.display = 'none';
  document.body.removeChild(modal);

  return this;
};

我希望代码一次关闭一个模式,最好是具有正确 ID 的模式(应由用户分配或默认情况下具有“NoID”ID)。相反,如果我关闭后续模式,它会关闭它们;但如果我关闭第一个,它会关闭所有这些。另外,有没有办法在创建模态实例后立即初始化()模态功能(我讨厌手动启动它们)?如果是这样,请在此处也包括您的解决方案,如果没有太多要求的话。

已经有一段时间了。非常感谢您的帮助。

谢谢。 :)

【问题讨论】:

标签: javascript modal-dialog simplemodal


【解决方案1】:

您的代码中有几个错误:

  1. 始终为 HTML 元素使用正确的 id 模式。您已将 n/a 用于在其 options 对象中没有 id 属性的模式。当你使用 jQuery 时,使用这样的id 会破坏查询选择器。
  2. 因为,您调用了两次init() 函数,并且在每次调用init()closeBtn 都选择了两个模态的关闭按钮,并将单击事件处理程序分配给每个模态两次。这就是当您单击一个按钮时,另一个按钮的单击事件会自行执行的原因。因此,您可以做的是,仅将单击功能与调用 init() 函数的模态的关闭按钮关联一次。我使用let closeBtn = document.querySelector('#'+this.options.id + ' .modal-close'); 选择了init() 函数内的特定关闭按钮。

总体而言,您的 JS 代码将如下所示:

/**
* Blueprint function (class) that describes a Modal object.
* @param {Object} options Object parameter containing elements that describe the Modal.
* @returns {Object} options Returns options from current modal object.
*/
function Modal(options) {
    // If constructor params is available
    if (options) {
    this.options = options;
  } else {
    this.options = {};

  } // End of IF-ELSE

  // Add to options object
  if (options.id) {
    // Check type of ID entry
    if (typeof options.id === 'number') {
      this.options.id = options.id.toString();
    } else {
      this.options.id = options.id;
    } // End of IF-ELSE
  } else if (options.id === undefined) {
    this.options.id = 'NA';
  } // End of IF-ELSE
  if (options.name) {
    this.options.name = options.name;
  } // End of IF
  if (options.closable) {
    this.options.closable = options.closable;
  } // End of IF

  return this;
};

// Prototypes
/**
* Displays some information concerning the current Modal object.
* @returns {Object} this Returns current modal object.
*/
Modal.prototype.open = function() {
    let demo = document.getElementById('demo');

  return this;
};

/**
* Creates an instance of a Modal object with the specified object elements.
* @returns {Object} this Returns current Modal object.
*/
Modal.prototype.create = function() {
  // Create Modal Element
  let modal = document.createElement('div');
  let modalBody = document.createElement('div');

  // Create Modal
  !modal.classList.contains('modal') ?
    modal.classList.add('modal') :
    modal.classList.add('');
  modal.id = this.options.id || 'noID';

  // Create modal body element
  !modalBody.classList.contains('modal-body') ?
    modalBody.classList.add('modal-body') :
    modalBody.classList.add('');document.querySelector('#' + this.options.id + ' .modal-close');
  modal.appendChild(modalBody);

  // Adding modal sub-elements  
  if (this.options.title) {
    let modalTitle = document.createElement('h2');
    !modalTitle.classList.contains('modal-title') ?
      modalTitle.classList.add('modal-title') :
      modalTitle.classList.add('');
    modalTitle.textContent = this.options.title;
    modalBody.appendChild(modalTitle);
    console.log('Added title!');
  } // End of IF

  if (this.options.subtitle) {
    let modalSubtitle = document.createElement('h4');
    !modalSubtitle.classList.contains('modal-subtitle') ?
      modalSubtitle.classList.add('modal-subtitle') :
      modalSubtitle.classList.add('');
    modalSubtitle.textContent = this.options.subtitle;
    modalBody.appendChild(modalSubtitle);
    console.log('Added subtitle!');
  } // End of IF

  if (this.options.content) {
    let modalContent = document.createElement('p');
    !modalContent.classList.contains('modal-content') ?
      modalContent.classList.add('modal-content') :
      modalContent.classList.add('');
    modalContent.textContent = this.options.content;
    modalBody.appendChild(modalContent);
    console.log('Added contents!');
  } // End of IF

  if (this.options.closable) {
    let modalClose = document.createElement('span');
    !modalClose.classList.contains('modal-close') ?
      modalClose.classList.add('modal-close') :
      modalClose.classList.add('');
    modalClose.innerHTML = '&times;';
    modalBody.appendChild(modalClose);
    console.log('Close button added!');
  } // End of IF

  document.body.appendChild(modal);
  console.log('Modal created with ID', modal.id);

  return this;
};

/**
* Closes the current Modal object.
* @returns {Object} this Returns current Modal object.
*/
Modal.prototype.close = function() {    
  let modal = document.getElementById(this.options.id);
  let modalBody = modal.children[0];

  // Delete elements from Modal Body
  for (let i = 0; i < modalBody.children.length; i++) {
    modalBody.removeChild(modalBody.children[i]);
  } // End of LOOP

  // Delete Modal Body from Modal
  modal.removeChild(modalBody);

  // Delete Modal from DOM
  modal.style.display = 'none';
  document.body.removeChild(modal);

  return this;
};

/**
* Initializes the inner functions of the modal, such as the closing capacity.
* @returns {Object} this Returns current Modal object.
*/
Modal.prototype.init = function(e) {
  // let closeBtnAll = document.querySelectorAll('.modal-close');
  let closeBtn = document.querySelector('#'+this.options.id + ' .modal-close');

  // Assign close() function to all close buttons
  closeBtn.addEventListener('click', () => {
    if (this.options.closable) {
      this.close();
    }
  })

  // Press ESC to close ALL modals

  return this;
};

// Create a Modal object
let modal1 = new Modal({
  id: 'post1',
  name: 'modal',
  title: 'First Post',
  subtitle: 'I contain all the elements',
  content: 'This is awesome!',
  closable: true
});

let modal2 = new Modal({
  title: 'Second Post',
  subtitle: 'Trying new things',
  content: 'Hehehehehe',
  closable: true
});

modal1.open();
modal1.create();
modal1.init();

modal2.open();
modal2.create();
modal2.init();

只需在你的codepen中替换上面的JS代码并尝试。它会起作用的。

【讨论】:

  • 如果您必须再次查看该代码,有没有办法在创建模态后立即init() 模态,而不必手动调用它?感谢您的帮助。 :)
【解决方案2】:

问题在于初始化函数:

/**
* Initializes the inner functions of the modal, such as the closing capacity.
* @returns {Object} this Returns current Modal object.
*/
Modal.prototype.init = function() {
  // let closeBtnAll = document.querySelectorAll('.modal-close');
  let modal = document.getElementById(this.options.id);
  let closeBtn = modal.querySelector('.modal-close'); 
  
  // Assign close() function to all close buttons
  closeBtn.addEventListener('click', () => {
    console.log(this.options);
    if (this.options.closable) {
      this.close();
    }
  })
  
  // Press ESC to close ALL modals
  
  return this;
};

如果您没有指定要在当前模式上使用事件监听器,那么它将被设置为两个模式。

【讨论】:

  • 您是否修改了以下行:javascript closeBtn.addEventListener('click', () =&gt; { console.log(this.options); if (this.options.closable) { this.close(); }
  • 不,我在 init 方法中将:let closeBtn = document.querySelector('.modal-close'); 更改为:let modal = document.getElementById(this.options.id); let closeBtn = modal.querySelector('.modal-close');
  • 啊,好吧。非常感谢。我真的很感谢你的帮助。我开始明白我的选择器是问题所在。每当我调试时,它总是屈服于“空”或“未定义”。
猜你喜欢
  • 1970-01-01
  • 2022-12-18
  • 1970-01-01
  • 1970-01-01
  • 2021-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多