javascript – How to compare CSS path of an element using JS?

Question:

I don't know if "path" is the best definition. But, using the QuerySelector is possible to get an element specifying a "path", such as:

main section.sobre .view-more

But how can I do the opposite?

If I have an element, like <button class="view-more"> , how can I make sure it's the main section.sobre .view-more ?

The only way I could find it would be to do a QuerySelector and then compare this element to the current element:

window.document.addEventListener("click", function(e) {

  [].forEach.call(window.document.querySelectorAll("main section.sobre .view-more"), function(el) {
    if (el == e.target) {
      window.console.log("Isso é o main section.sobre .view-more");
    }
  });

}, true);
<html lang="en">

<body>
  <main>
    <section class="sobre">
      <button class="view-less">View Less</button>
      <button class="view-close">View Less</button>

      <button class="view-more">View More</button>
      <button class="view-more">View More</button>
    </section>
  </main>
</body>

</html>

The problem is if you are going to search for several "paths" you will have to execute several querySelectorAll . That is, if you want to know if the element is main .a , main .b , main .c , main .d , you would have to do a querySelectorAll for each one, then compare. This gets even worse if there are multiple elements with the same "path", as the case above, as you will have to iterate through the querySelectorAll itself.

This works, but it doesn't feel right. Is there another, more efficient and native way to achieve this goal?

Answer:

There is a function for this, matchesSelector

Syntax:

element.matchesSelector(selectorString)

Where element is any HTML element and selectorString is a string representing a valid CSS selector. The function returns a boolean, true if the CSS selector represents a possible path to the element, and false otherwise

Many browsers implement this function with your prefix, for example chrome has the webkitMatchesSelector , you can use this polyfill which is in the MDN documentation:

if (!Element.prototype.matches)
    Element.prototype.matches = 
        Element.prototype.matchesSelector || 
        Element.prototype.mozMatchesSelector ||
        Element.prototype.msMatchesSelector || 
        Element.prototype.oMatchesSelector || 
        Element.prototype.webkitMatchesSelector ||
        function(s) {
            var matches = (this.document || this.ownerDocument).querySelectorAll(s),
                i = matches.length
            while (--i >= 0 && matches.item(i) !== this) {}
            return i > -1            
        }

Example of use:

if (!Element.prototype.matches)
    Element.prototype.matches = 
        Element.prototype.matchesSelector || 
        Element.prototype.mozMatchesSelector ||
        Element.prototype.msMatchesSelector || 
        Element.prototype.oMatchesSelector || 
        Element.prototype.webkitMatchesSelector ||
        function(s) {
            var matches = (this.document || this.ownerDocument).querySelectorAll(s),
                i = matches.length
            while (--i >= 0 && matches.item(i) !== this) {}
            return i > -1            
        }

document.addEventListener("click", function(e) {
  if (e.target.matches('main section.sobre .view-more'))
    console.log("Isso é o main section.sobre .view-more");
}, true);
<html lang="en">
<head>
</head>
<body>
  <main>
    <section class="sobre">
      <button class="view-less">View Less</button>
      <button class="view-close">View Less</button>

      <button class="view-more">View More</button>
      <button class="view-more">View More</button>
    </section>
  </main>
</body>
</html>
Scroll to Top