我想通过按钮激活一个“弹出”框,以减少所有其他元素的不透明度。当用户单击开箱即用时,它应消失并且不透明度应恢复正常。但是,这两个功能相互冲突。它要求我单击TWICE按钮才能调用showBox()。除非我在浏览器的控制台中重新调用hideOnClickOutside(document.querySelector('div'));,否则直接单击即可。

为什么我必须两次单击“新音频”,为什么hideOnClickOutside()除非重新调用,否则不起作用?



function showBox() {
  document.body.style.opacity = "0.5";
  document.querySelector('div').style.display = "block";
}

document.querySelector('button').addEventListener('click', showBox);
const isVisible = elem => !!elem && !!(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length); // source (2018-03-11): https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js
function hideOnClickOutside(element) {
  const outsideClickListener = event => {
    if (!element.contains(event.target) && isVisible(element)) { // or use: event.target.closest(selector) === null
      element.style.display = 'none';
      removeClickListener()
      document.body.style.opacity = "1";
    }
  }

  const removeClickListener = () => {
    document.removeEventListener('click', outsideClickListener)
  }

  document.addEventListener('click', outsideClickListener)
}

hideOnClickOutside(document.querySelector('div'));

<button>New Audio</button>

<div style="display: none">
  <button>Record Directly</button>
</div>





hideOnClickOutside()函数取自another StackOverflow answer

编辑

我发现它需要两次单击,因为在第一次单击时,调用了showBox(),但紧接着又调用了外部点击侦听器,这时该元素现在可见,并且用户单击了该元素的“外部”。这将还原showBox()的样式更改。

最佳答案

最简单的解决方法是存储对“新音频” button的引用,并检查其是否为单击targetdocument。如果是这样,则在不更新return的情况下从函数中选择DOM

const button = document.querySelector('button')
button.addEventListener('click', showBox);
// ..
function hideOnClickOutside(element) {
  const outsideClickListener = event => {
    if (event.target === button) return
// ..


请记住,在您拥有当前代码的情况下,hideOnClickOutside函数仅在第一次isVisible为true且target不是button时才会得到,因为您是在这种情况下删除了事件侦听器的。



function showBox(e) {
  document.body.style.opacity = "0.5";
  document.querySelector('div').style.display = "block";
}
const button = document.querySelector('button')
button.addEventListener('click', showBox);
const isVisible = elem => !!elem && !!(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length); // source (2018-03-11): https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js
function hideOnClickOutside(element) {
  const outsideClickListener = event => {
    if (event.target === button) return
    if (!element.contains(event.target) && isVisible(element)) { // or use: event.target.closest(selector) === null
      element.style.display = 'none';
      removeClickListener()
      document.body.style.opacity = "1";
    }
  }

  const removeClickListener = () => {
    document.removeEventListener('click', outsideClickListener)
  }

  document.addEventListener('click', outsideClickListener)
}

hideOnClickOutside(document.querySelector('div'));

<button>New Audio</button>

<div style="display: none">
  <button>Record Directly</button>
</div>





另一个问题是,一旦调用showBox函数,您实际上可能希望将button视为外部。让我们重构代码以存储对showButtonbox的引用,在disable showButton中添加标志,并仅在单击showButton的情况下将事件监听器添加到文档中,并仅删除事件监听器显示框时。

您以后可以重构它以适合您的特定用例。想法是考虑该应用程序可能处于的各种状态,并创建管理该状态的功能。



const box = document.querySelector('#box');
const showButton = document.querySelector('#show-button');
showButton.addEventListener('click', showBox);

let isDisabled = false;
const isVisible = elem => !!elem && !!(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length); // source (2018-03-11): https://github.com/jquery/jquery/blob/master/src/css/hiddenVisibleSelectors.js

function toggleDisabled(bool) {
    showButton.attributes.disabled = bool;
    isDisabled = bool;
}

function toggleDisplay(display, opacity) {
    document.body.style.opacity = opacity;
    box.style.display = display;
}

function showBox(event) {
  if (!isDisabled) {
    event.preventDefault();
    event.stopPropagation();
    toggleDisplay("block", 0.5);
    toggleDisabled(true);
    document.addEventListener('click', outsideClickListener);
  }
}

function outsideClickListener(event) {
  if (!box.contains(event.target) && isVisible(box)) { // or use: event.target.closest(selector) === null
    toggleDisplay("none", 1);
    toggleDisabled(false);
    document.removeEventListener('click', outsideClickListener)
  }
}

<button id="show-button">New Audio</button>

<div id="box" style="display: none">
  <button>Record Directly</button>
</div>

07-26 04:14