【问题标题】:Finding closest element without jQuery在没有 jQuery 的情况下查找最近的元素
【发布时间】:2020-03-05 11:28:28
【问题描述】:

我正在尝试在没有 jquery 的情况下找到具有特定标记名称的最接近的元素。当我单击<th> 时,我想访问该表的<tbody>。建议?我阅读了有关偏移量的信息,但并没有真正理解太多。我应该使用:

假设 th 已经被设置为 clicked th 元素

th.offsetParent.getElementsByTagName('tbody')[0]

【问题讨论】:

  • 如果你发现你必须开始遍历 DOM,这是一个值得归因于 jquery 的额外 kbs 的实例。
  • 我认为这是一个非常重要且有效的问题。没有理由投反对票。
  • el.closest('tbody') 用于非 ie 浏览器。在下面查看更详细的答案 + polyfill。

标签: javascript


【解决方案1】:

很简单:

el.closest('tbody')

在除 IE 之外的所有浏览器上均受支持。
更新:Edge 现在也支持它。

不需要 jQuery。 此外,将 jQuery 的 $(this).closest('tbody') 替换为 $(this.closest('tbody')) 会提高性能,尤其是在找不到元素时。

IE 的 Polyfill:

if (!Element.prototype.matches) Element.prototype.matches = Element.prototype.msMatchesSelector;
if (!Element.prototype.closest) Element.prototype.closest = function (selector) {
    var el = this;
    while (el) {
        if (el.matches(selector)) {
            return el;
        }
        el = el.parentElement;
    }
};

请注意,当找不到元素时没有return,当找不到最近的元素时有效地返回undefined

更多详情见: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest

【讨论】:

  • 为什么这个答案在页面底部?应该在顶部。非常感谢
  • 最接近的是 jQuery。但是 OP 说没有 jQuery。
  • @stevemoretz。现在最接近的是原生 JavaScript
  • @LouiseEggleton 是的,哎呀
  • 这就是最好的答案!
【解决方案2】:

晚会有点(非常)迟到,但尽管如此。这应该是trick:

function closest(el, selector) {
    var matchesFn;

    // find vendor prefix
    ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
        if (typeof document.body[fn] == 'function') {
            matchesFn = fn;
            return true;
        }
        return false;
    })

    var parent;

    // traverse parents
    while (el) {
        parent = el.parentElement;
        if (parent && parent[matchesFn](selector)) {
            return parent;
        }
        el = parent;
    }

    return null;
}

【讨论】:

  • 很好的答案,很不错。 MDN 还有一个用于 element.closest() 的 polyfill。 Chrome 在当前版本中包含 element.matches(),因此不需要前缀。我刚刚将它添加到我正在开发的应用程序 Clibu 中使用的库中。
  • 我已经更改了代码,以便它还测试元素 el jQuery.closest() 和 Element.closest() 所做的。 for( var parent = el ; parent !== null && !parent[matchesFn](selector) ; parent = el.parentElement ){ el = parent; } return parent;
  • 这段代码很好,但它缺少一个分号并且还在全局范围内定义了parent (!)
  • 可能值得一提:developer.mozilla.org/en-US/docs/Web/API/Element/closest 最接近的本机方法,虽然支持率很低:Chrome41、FF35、IE-nope、Opera28、Safari9
  • 请注意,您可能需要 el.parentNode 否则在 IE 中遍历 SVG 时会中断。
【解决方案3】:

以下是在不使用 jQuery 的情况下通过标签名称获取最接近元素的方法:

function getClosest(el, tag) {
  // this is necessary since nodeName is always in upper case
  tag = tag.toUpperCase();
  do {
    if (el.nodeName === tag) {
      // tag name is found! let's return it. :)
      return el;
    }
  } while (el = el.parentNode);

  // not found :(
  return null;
}

getClosest(th, 'tbody');

【讨论】:

  • 我不相信这会奏效。它只检查 DOM 树。 th->thead->table 从不考虑兄弟姐妹
  • 您应该在问题中说明具体情况。
  • 看。此函数遍历 parentNodes 以找到使用提供的标签的最近的父节点(甚至通过扩展)。这不会“向下”文档树,只会“向上”。普通用户将最有可能将“最近”节点视为最接近的兄弟节点。他只是不知道他需要的术语。
  • 公平地说,@Jhawins 您对最接近的定义是 jQuery 术语最接近的。这不是一个 jQuery 问题。我无法证明为什么 jQuery 决定最接近意味着最接近的祖先,但更合理的定义将是最接近的元素,无论它是父元素、前一个兄弟姐妹、下一个兄弟姐妹等。无论发现什么“最接近”目标元素。
  • @ryandlf 但是如果你的父母和兄弟姐妹在相同的“距离”上呢? jQuery 的定义很明确,它最多返回一个匹配项。
【解决方案4】:

有一个标准化的函数可以做到这一点:Element.closest。 除了 IE11 之外的大多数浏览器都支持它 (details by caniuse.com)。 MDN docs 还包含一个 polyfill,以防您必须针对旧版浏览器。

要找到给定th 的最接近的tbody 父母,您可以这样做:

th.closest('tbody');

如果您想自己编写函数 - 这是我想出的:

function findClosestParent (startElement, fn) {
  var parent = startElement.parentElement;
  if (!parent) return undefined;
  return fn(parent) ? parent : findClosestParent(parent, fn);
}

要通过标签名称找到最近的父级,您可以像这样使用它:

findClosestParent(x, element => return element.tagName === "SECTION");

【讨论】:

    【解决方案5】:
    function closest(el, sel) {
        if (el != null)
            return el.matches(sel) ? el 
                : (el.querySelector(sel) 
                    || closest(el.parentNode, sel));
    }
    

    这个解决方案使用了 HTML 5 规范的一些更新的特性,并且在旧的/不兼容的浏览器(阅读:Internet Explorer)上使用它需要一个 polyfill。

    Element.prototype.matches = (Element.prototype.matches || Element.prototype.mozMatchesSelector 
        || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector 
        || Element.prototype.webkitMatchesSelector || Element.prototype.webkitMatchesSelector);
    

    【讨论】:

    • 它总是排在第一位。不是最近的表.. 看到这个链接jsfiddle.net/guuy5kof
    • 不错的收获!已修复,请参阅此处jsfiddle.net/c2pqc2x0 请像老板一样为我投票 :)
    • 你我会做的......你检查过你的小提琴结果吗,它显示错误..matches undefined
    • 非常适合我,您使用的是哪种浏览器?旧浏览器不支持此功能
    • 嘿,让我们澄清一下,你说什么,兄弟
    【解决方案6】:

    扩展@SalmanPK 答案

    它将允许使用节点作为选择器,在处理鼠标悬停等事件时很有用。

    function closest(el, selector) {
        if (typeof selector === 'string') {
            matches = el.webkitMatchesSelector ? 'webkitMatchesSelector' : (el.msMatchesSelector ? 'msMatchesSelector' : 'matches');
            while (el.parentElement) {
                if (el[matches](selector)) {
                    return el
                };
                el = el.parentElement;
            }
        } else {
            while (el.parentElement) {
                if (el === selector) {
                    return el
                };
                el = el.parentElement;
            }
        }
    
        return null;
    }
    

    【讨论】:

      【解决方案7】:

      这是我正在使用的简单函数:-

      function closest(el, selector) {
          var matches = el.webkitMatchesSelector ? 'webkitMatchesSelector' : (el.msMatchesSelector ? 'msMatchesSelector' : 'matches');
      
          while (el.parentElement) {
              if (el[matches](selector)) return el;
      
              el = el.parentElement;
          }
      
          return null;
      }
      

      【讨论】:

        【解决方案8】:

        总结:

        为了找到我们可以使用的特定祖先:

        Element.closest();

        此函数将 CSS 选择器字符串作为参数。然后它返回与在参数中传递的 CSS 选择器匹配的当前元素(或元素本身)最近的祖先。如果没有祖先,它将返回null

        示例:

        const child = document.querySelector('.child');
        // select the child
        
        console.dir(child.closest('.parent').className);
        // check if there is any ancestor called parent
        <div class="parent">
          <div></div>
          <div>
            <div></div>
            <div class="child"></div>
          </div>
        </div>

        【讨论】:

          【解决方案9】:

          从包含类、ID、数据属性或标签的树中获取最近的 DOM 元素。包括元素本身。支持回 IE6。

          var getClosest = function (elem, selector) {
          
              var firstChar = selector.charAt(0);
          
              // Get closest match
              for ( ; elem && elem !== document; elem = elem.parentNode ) {
          
                  // If selector is a class
                  if ( firstChar === '.' ) {
                      if ( elem.classList.contains( selector.substr(1) ) ) {
                          return elem;
                      }
                  }
          
                  // If selector is an ID
                  if ( firstChar === '#' ) {
                      if ( elem.id === selector.substr(1) ) {
                          return elem;
                      }
                  } 
          
                  // If selector is a data attribute
                  if ( firstChar === '[' ) {
                      if ( elem.hasAttribute( selector.substr(1, selector.length - 2) ) ) {
                          return elem;
                      }
                  }
          
                  // If selector is a tag
                  if ( elem.tagName.toLowerCase() === selector ) {
                      return elem;
                  }
          
              }
          
              return false;
          
          };
          
          var elem = document.querySelector('#some-element');
          var closest = getClosest(elem, '.some-class');
          var closestLink = getClosest(elem, 'a');
          var closestExcludingElement = getClosest(elem.parentNode, '.some-class');
          

          【讨论】:

          • 为什么不对firstChar 使用开关而不是所有IF 条件?
          • 为什么要使用模糊的for 循环?
          【解决方案10】:

          查找最近的元素子节点。

          closest:function(el, selector,userMatchFn) {
          var matchesFn;
          
          // find vendor prefix
          ['matches','webkitMatchesSelector','mozMatchesSelector','msMatchesSelector','oMatchesSelector'].some(function(fn) {
              if (typeof document.body[fn] == 'function') {
                  matchesFn = fn;
                  return true;
              }
              return false;
          });
          function findInChilds(el){
              if(!el) return false;
              if(el && el[matchesFn] && el[matchesFn](selector)
          
              && userMatchFn(el) ) return [el];
              var resultAsArr=[];
              if(el.childNodes && el.childNodes.length){
                  for(var i=0;i< el.childNodes.length;i++)
                  {
                       var child=el.childNodes[i];
                       var resultForChild=findInChilds(child);
                      if(resultForChild instanceof Array){
                          for(var j=0;j<resultForChild.length;j++)
                          {
                              resultAsArr.push(resultForChild[j]);
                          }
                      } 
                  }
          
              }
              return resultAsArr.length?resultAsArr: false;
          }
          
          var parent;
          if(!userMatchFn || arguments.length==2) userMatchFn=function(){return true;}
          while (el) {
              parent = el.parentElement;
              result=findInChilds(parent);
              if (result)     return result;
          
              el = parent;
          }
          
          return null;
          

          }

          【讨论】:

            【解决方案11】:

            这里。

            function findNearest(el, tag) {
                while( el && el.tagName && el.tagName !== tag.toUpperCase()) {
                    el = el.nextSibling;     
                } return el;
            } 
            

            仅在树的下方找到兄弟姐妹。使用previousSibling 走另一条路 或者使用变量来遍历两种方式并返回首先找到的那个。 你得到了一般的想法,但是如果你想遍历 parentNodes 或如果兄弟不匹配的孩子,你也可以使用 jQuery。在这一点上,它很容易值得。

            【讨论】:

            • 稍微修改了您的建议以支持深度子遍历:function findNearest(el, tag) { while( el &amp;&amp; el.tagName &amp;&amp; el.tagName !== tag.toUpperCase()) { el = findNearest(el.firstElementChild, tag) || el.nextElementSibling; } return el; }
            【解决方案12】:

            聚会有点晚了,但是当我路过并回答了一个非常相似的问题时,我把我的解决方案放在这里——我们可以说这是 JQuery closest() 方法,但在普通的 JavaScript 中。

            它不需要任何 pollyfills 并且它是较旧的浏览器,并且 IE (:-) ) 友好: https://stackoverflow.com/a/48726873/2816279

            【讨论】:

              【解决方案13】:

              我认为最容易用 jquery 捕获的代码最接近:

              <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
              <script>
                  $(document).ready(function () {
                      $(".add").on("click", function () {
                          var v = $(this).closest(".division").find("input[name='roll']").val();
                          alert(v);
                      });
                  });
              </script>
              <?php
              
              for ($i = 1; $i <= 5; $i++) {
                  echo'<div class = "division">'
                      . '<form method="POST" action="">'
                      . '<p><input type="number" name="roll" placeholder="Enter Roll"></p>'
                      . '<p><input type="button" class="add" name = "submit" value = "Click"></p>'
                      . '</form></div>';
              }
              ?>
              

              非常感谢。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2019-10-27
                • 2011-10-24
                • 1970-01-01
                • 1970-01-01
                • 2018-12-20
                • 2023-03-12
                • 1970-01-01
                相关资源
                最近更新 更多