【问题标题】:Check if class exists somewhere in parent检查类是否存在于父级的某处
【发布时间】:2013-05-27 15:59:45
【问题描述】:

我想检查一个类是否存在于某个元素的某个父元素中的某个位置。

我不想使用任何库,只是普通的 JS。

在下面的示例中,如果所讨论的元素位于以“the-class”作为类名的元素的子元素中的某个位置,则它应该返回 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>

...但这会返回错误:

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

【问题讨论】:

  • 使用 jquery 这将是最接近的('.theclass').length
  • 您是否有任何代码可以显示您尝试过的内容,以便我们查看您可能需要帮助的地方?
  • 那么,您想查看是否有任何祖先或祖先的兄弟姐妹具有给定的类名?

标签: javascript dom


【解决方案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);
}

Demonstration(打开控制台查看true

【讨论】:

  • 如果 som 父级没有类,则会失败
  • 无法拆分未定义
  • 我用这段代码来处理没有类的元素:var hasSomeParentTheClass = function(element, classname) { if (element.className &amp;&amp; element.className.split(' ').indexOf(classname) &gt;= 0) return true; return element.parentNode &amp;&amp; hasSomeParentTheClass(element.parentNode, classname); }
  • 使用parentElement 代替parentNode 可以避免这个问题。
  • @lexa IE9 不知道什么是 classList。
【解决方案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】:

    我相信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;
    

    【讨论】:

    • 我遇到了同样的问题,我想出了这个解决方案,所以我想我会把它贴在这里给其他面临这个问题的人。
    • 为什么$更有效?
    • @SuperUberDuper 我并不是说 jQuery 比单一用途的香草代码更有效,如果这就是你要问的。我认为,我的意思是,与 OP 的 jq 行相比,使用带有 parents 的选择器可能会减少一个循环。措辞不好,嗯?
    • 这是一个很好的方法。我只建议运行 .hasOwnProperty() 检查。
    【解决方案4】:

    因为 ID 在文档上下文中必须是唯一的,所以您可以改用:

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

    如果你想包含元素本身,你可以使用:

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

    【讨论】:

      【解决方案5】:

      我的 Vanilla JS 示例,它使用了 jQuery 中的 parents() 的香草等价物

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

      所以你的选择器就是.className

      只需检查父级是否 > 0

      【讨论】:

        【解决方案6】:

        Denys Séguret 发布的功能我没问题,它看起来很优雅,我喜欢它。 我只是稍微调整了该函数,因为如果参数中指定的类不存在于整个 DOM 中,则当递归到达文档对象时它会失败,因为我们控制元素是否具有父节点是真的(在最后一行,当文档是元素时父节点为空)但是在我们执行上一行之前,当元素是文档时,document.classNameundefined 并且它失败了,所以必须将控件移动到顶部。

        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);
        }
        

        【讨论】:

        • 不需要单独的条件,您可以通过显式检查空值来确保获得布尔值:element.parentNode != null &amp;&amp; hasSomeParentTheClass(..)
        【解决方案7】:

        您可以使用somecontains 来实现结果:

        function hasParentWithMatchingSelector (target, selector) {
          return [...document.querySelectorAll(selector)].some(el =>
            el !== target && el.contains(target)
          )
        }
        
        // usage
        hasParentWithMatchingSelector(myElement, '.some-class-name');
        

        【讨论】:

        • 这真的很聪明.. 只需要修复因为el.contains(el) returns true。所以我们应该重写为:el !== target &amp;&amp; el.contains(target)
        【解决方案8】:

        您可以使用Elementclosest() 方法遍历元素的父元素(朝向文档根目录),直到找到与提供的选择器字符串匹配的节点。将返回自身或匹配的祖先。如果不存在这样的元素,则返回 null。

        您可以将返回值转换为布尔值

        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>

        【讨论】:

        • 这是更现代的答案。但是,它不支持称为 Internet Explorer 的古老浏览器,并且需要 polyfill。 (MDN Reference)
        • 这是您想要的答案,除非您仍然需要支持 MSIE 11 或更低版本。
        【解决方案9】:

        对于一些喜欢现代/polyfill 浏览器的这种风格的人来说,这是另一种选择。

        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>

        【讨论】:

          【解决方案10】:

          尝试 closest() 函数 - 对于集合中的每个元素,通过测试元素本身并向上遍历其在 DOM 树中的祖先来获取与选择器匹配的第一个元素。请参阅此处的Official Docs

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-11-09
            • 2016-12-24
            • 2014-07-20
            • 1970-01-01
            • 2015-10-17
            • 1970-01-01
            • 2021-03-28
            • 1970-01-01
            相关资源
            最近更新 更多