Проверьте, существует ли класс где-то в родительском - vanilla JS

Я действительно пытаюсь понять, как это сделать. Я хочу проверить, если класс exesits где-то в одном из родительских элементов элемента.

Я не хочу использовать какую-либо библиотеку, просто ваниль JS.

В приведенных ниже примерах он должен возвращать значение true, если рассматриваемый элемент находится где-то в дочерних элементах элемента с "классом" в качестве имени класса.

Я думаю, что это будет что-то вроде этого с jQuery:

if( $('#the-element').parents().hasClass('the-class') ) {
    return true;
}

Итак, это возвращает true:

<div>
    <div class="the-class">
        <div id="the-element"></div>
    </div>
</div>

Так делает это:

<div class="the-class">
    <div>
        <div id="the-element"></div>
    </div>
</div>

... но это возвращает false:

<div>
    <div class="the-class">
    </div>
    <div id="the-element"></div>
</div>

Ответ 1

Вам нужно будет сделать это рекурсивно:

// returns true if the element or one of its parents has the class classname
function hasSomeParentTheClass(element, classname) {
    if (element.className.split(' ').indexOf(classname)>=0) return true;
    return element.parentNode && hasSomeParentTheClass(element.parentNode, classname);
}

Демонстрация (откройте консоль, чтобы увидеть true)

Ответ 2

fiddle

Код

function hasClass(element, className) {
  var regex = new RegExp('\\b' + className + '\\b');
  do {
    if (regex.exec(element.className)) {
      return true;
    }
    element = element.parentNode;
  } while (element);
  return false;
}

ИЛИ

function hasClass(element, className) {
  do {
    if (element.classList && element.classList.contains(className)) {
      return true;
    }
    element = element.parentNode;
  } while (element);
  return false;
}

Ответ 3

Вы можете использовать some и contains для достижения результата:

function hasParentWithMatchingSelector (target, selector) {
  return [...document.querySelectorAll(selector)].some(el =>
    el !== target && el.contains(target)
  )
}

// usage
hasParentWithMatchingSelector(myElement, '.some-class-name');

Ответ 4

Я в порядке с функцией, которую Denys Séguret опубликовал, выглядит элегантно, и мне это нравится. Я немного изменил эту функцию, поскольку, если класс, указанный в параметре, отсутствует во всей DOM, он терпит неудачу, когда рекурсия достигает объекта документа, потому что это правда, что мы управляем, если элемент имеет родительский node ( в последней строке, а когда документ является элементом, родительский node имеет значение NULL), но перед тем, как мы выполним предыдущую строку, а когда этот элемент является документом, document.className - undefined, и он не работает, поэтому элемент управления должен быть перемещен в верхнюю часть.

function hasSomeParentTheClass(element, classname) {
    //
    // If we are here we didn't find the searched class in any parents node
    //
    if (!element.parentNode) return false;
    //
    // If the current node has the class return true, otherwise we will search
    // it in the parent node
    //
    if (element.className.split(' ').indexOf(classname)>=0) return true;
    return hasSomeParentTheClass(element.parentNode, classname);
}

Ответ 5

Я считаю, if( $('#the-element').parents('.the-class').length ) быть более эффективным, но, возможно, не таким, как читаемый человеком; который с querySelector на картинке может быть заменен следующим образом:

function hasParent(element, parentSelector) {
    var potentialParents = document.querySelectorAll(parentSelector);
    for(i in potentialParents) if(potentialParents[i].contains(element))
        return potentialParents[i];
    return false;
}

Это даст вам возможность:

var elm = document.getElementById('the-element');
if(hasParent(elm, '.the-class')) return true;

Ответ 6

Вы можете использовать метод closest() Element, который пересекает родительские элементы (направляясь к корню документа) Элемента, пока не найдет узел, который соответствует предоставленной строке selectorString. Вернет себя или соответствующего предка. Если такого элемента не существует, возвращается ноль.

Вы можете преобразовать возвращаемое значение в логическое значение

const el = document.getElementById('div-03');

const r1 = el.closest("#div-02");  
console.log(Boolean(r1));
// returns the element with the id=div-02

const r2 = el.closest("#div-not-exists");
console.log(Boolean(r2));
<article>
  <div id="div-01">Here is div-01
    <div id="div-02">Here is div-02
      <div id="div-03">Here is div-03</div>
    </div>
  </div>
</article>

Ответ 7

Мой пример для Vanilla JS, он использует ванильный эквивалент parents() из jQuery

var htmlElement = <htmlElement>,
    parents = [],
    classExist;
while (htmlElement = htmlElement.parentNode.closest(<parentSelector>)) {
    parents.push(htmlElement);
}
classExist = (parents > 0);

Итак, ваш селектор должен быть .className

И просто проверьте, является ли родительский > 0

Ответ 8

Еще одна альтернатива для тех, кто любит этот стиль для современных/многозадачных браузеров.

const hasClass = (element, className) => {
    return element.classList.contains(className);
};

const hasParent = (element, className) => {
    if (!element.parentNode) {
        return false;
    }

    if (hasClass(element, className)) {
        return true;
    }

    return hasParent(element.parentNode, className)
};

Рабочая демонстрация:

const hasClass = (element, className) => {
    return element.classList.contains(className);
};

const hasParent = (element, className) => {
    if (!element.parentNode) {
        return false;
    }

    if (hasClass(element, className)) {
        return true;
    }

    return hasParent(element.parentNode, className)
};


/* Demo Code, can ignore */
const child = document.getElementById('child');
const orphan = document.getElementById('orphan');
const output = document.getElementById('output');

const log = 'child has parent? ${hasParent(child, 'list')}
orphan has parent? ${hasParent(orphan, 'list')}
'

output.innerText = log;
#output {
  margin-top: 50px;
  background: black;
  color: red;
  padding: 20px;
}
<div>
  <ul class="list">
    <li>
      <a id="child" href="#">i have a parent</a> 
    </li>
  </ul>
</div>

<div>
  <ul>
    <li>
      <a id="orphan" href="#">im an orphan</a> 
    </li>
  </ul>
</div>

<div id="output"></div>

Ответ 9

я написал маленький отрывок, чтобы пройти через DOM, чтобы найти первый соответствующий parentNode.

Надеюсь, это когда-нибудь кому-нибудь поможет.

(/¯◡ ‿ ◡) ⊃━ ☆ ゚. * ・。 ゚,

function getFirstParentMatch(element, selector) {
  if (!element) {return element};
  element.matches(selector) || (element = (element.nodeName.toLowerCase() === 'html' ? false : getFirstParent(element.parentNode, selector)));
  return element;    
}

Ответ 10

Поскольку идентификатор должен быть уникальным в контексте документа, вы можете просто использовать вместо него:

return !!document.querySelector('.the-class #the-element');

Если вы хотите включить сам элемент, вы можете использовать:

return !!document.querySelector('.the-class #the-element, #the-element.the-class');