简体   繁体   中英

Prevent overlay click for elements with a higher z index

I have a simple overlay that I want to catch click events on. Problem is, I don't want any clicks that occur within the content of the overlay to trigger an event. For example, if you look at my code snippet below, clicking inside the .content div should not trigger the click event listener that I set on the overlay, but it does.

Basically I want to just know when someone clicks the black background of the overlay. Is there anyway to do this with how I currently have my code?

 const overlay = document.querySelector('.overlay') overlay.onclick = function() { console.log('click on overlay!') }
 body { margin: 0; }.overlay { position: fixed; top: 0; left: 0; background-color: rgba(0,0,0,0.5); width: 100%; height: 100%; z-index: 10; }.content { width: 200px; height: 200px; position: absolute; z-index: 11; top: calc(50% - 100px); left: calc(50% - 100px); background: white; display: flex; align-items: center; justify-content: center; }
 <div class="overlay"> <div class="content">Hello World</div> </div>

you can disable the click event for the content div

const content = document.querySelector('.content');
content.off('click');

Access the event target in the arguments of your function. From there use a conditional if statement to ensure that the target clicked is the overlay, and only do your action if the condition is true.

 const overlay = document.querySelector('.overlay') overlay.onclick = function(e) { if (e.target.classList.contains("overlay")) { console.log('click on overlay!') } }
 body { margin: 0; } .overlay { position: fixed; top: 0; left: 0; background-color: rgba(0,0,0,0.5); width: 100%; height: 100%; z-index: 10; } .content { width: 200px; height: 200px; position: absolute; z-index: 11; top: calc(50% - 100px); left: calc(50% - 100px); background: white; display: flex; align-items: center; justify-content: center; }
 <div class="overlay"> <div class="content">Hello World</div> </div>

@PsiKai solution is good. You can also handle it with closest (and use an event listener instead of onclick :

 document.querySelector('.overlay').addEventListener('click', event => { if (! event.target.parentElement.closest('.overlay')) { console.log('click on overlay !') } });
 body { margin: 0; } .overlay { position: fixed; top: 0; left: 0; background-color: rgba(0,0,0,0.5); width: 100%; height: 100%; z-index: 10; } .content { width: 200px; height: 200px; position: absolute; z-index: 11; top: calc(50% - 100px); left: calc(50% - 100px); background: white; display: flex; align-items: center; justify-content: center; }
 <div class="overlay"> <div class="content">Hello World</div> </div>

Just restructure your HTML code and it will work fine, as you have already set the z-index for overlay and content as well. so as content has a higher z-index than the overlay, so it will be hidden by the content.

Demo:

 const overlay = document.querySelector('.overlay') overlay.onclick = function() { console.log('click on overlay!') }
 body { margin: 0; } .popup { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 10;; } .overlay { position: fixed; top: 0; left: 0; background-color: rgba(0,0,0,0.5); width: 100%; height: 100%; z-index: 10; } .content { width: 200px; height: 200px; position: absolute; z-index: 11; top: calc(50% - 100px); left: calc(50% - 100px); background: white; display: flex; align-items: center; justify-content: center; }
 <div class="popup"> <div class="overlay"></div> <div class="content">Hello World</div> </div>

To solve this problem of yours you need to understand how javascript events works. There are three phases of event:

  1. Capturing phase
  2. Target phase
  3. Bubbling phase

Capturing phase:

When you trigger some event javascript starts to handle it by passing from the very top element(Window) to children. It happens until target( .content ) element reached. In your case event goes through .overlay element but event handler not triggered, because by default all event listeners triggers on bubbling or target phase

Target phase:

The event has arrived at the event's target. The very element on which element was triggered, which in your case is .content

Bubbling phase:

The event is propagating back up through the target's ancestors in reverse order, starting with the parent and eventually reaching the containing Window. During this phase your event passing through .overlay element and invokes event handler which was registered.

在此处输入图片说明

I don't know what is best solution for your problem but it can be solved in several ways:

  1. Solution proposed by @PsiKai and @Joulss where you're checking target element by class name. Registered event listener

  2. Solution proposed by @eMentorship. By changing the markup, event at bubbling phase doesn't touch .overlay element.

const content = document.querySelector('.element');
content.addEventListener('click', event => event.stopPropagation());

By calling stopPropagation you stoping event from going to the parent element and as a result .overlay event handler ignored as event not bubbling to the root element.

Event phase: https://developer.mozilla.org/en-US/docs/Web/API/Event/eventPhase

PS. According to MDN: The addEventListener() method is the recommended way to register an event listener. The benefits are as follows:

  • It allows adding more than one handler for an event. This is particularly useful for libraries, JavaScript modules, or any other
    kind of code that needs to work well with other libraries or
    extensions.
  • In contrast to using an onXYZ property, it gives you finer-grained control of the phase when the listener is activated (capturing vs. bubbling).
  • It works on any event target, not just HTML or SVG elements.

I had the same issue and it was resolved by not enclosing the content div within the overlay div:

For instance, instead of:

<div class="overlay">
  <div class="content">Hello World</div>
</div>

Did this:

<div class="overlay"></div>
<div class="content">Hello World</div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM