在没有jQuery的情况下找到最接近的元素


89

我试图找到没有jquery的具有特定标记名称的最接近的元素。当我点击时,<th>我想访问<tbody>该表的。有什么建议吗?我读过有关偏移量的信息,但并不太了解。我应该只使用:

假设已经设置了单击元素

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

1
如果您发现必须开始遍历DOM,则这是一个实例,其中应归因于jquery的额外kbs值得。
凯文·鲍尔索克斯


2
我认为这是一个非常重要和有效的问题。没有理由投票。

el.closest('tbody')对于非IE浏览器。请参阅下面的详细说明的答案+ polyfill。
oriadam '16

Answers:


69

晚会很少(很晚),但是。这应该做的伎俩

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

2
好的答案,请客。MDN还为element.closest()提供了一个polyfill。Chrome在当前版本中包括element.matches(),因此不需要前缀。我刚刚将其添加到正在开发的应用程序Clibu中使用的库中。
nevf

2
我更改了代码,以便它也可以测试eljQuery.closest()和Element.closest()的元素。for( var parent = el ; parent !== null && !parent[matchesFn](selector) ; parent = el.parentElement ){ el = parent; } return parent;
nevf

1
这段代码很好,但是缺少分号,并且也在parent全局范围内定义(!)
Steven Lu

1
可能值得一提:developer.mozilla.org/en-US/docs/Web/API/Element/closest最接近的本机方法,尽管支持程度很低:Chrome41,FF35,IE-nope,Opera28,Safari9
Michiel D

对此,您可能需要这样做,el.parentNode否则在IE中遍历SVG时可能会中断。
smcka,2016年

123

很简单的:

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


4
为什么此答案在页面底部?应该在顶部。非常感谢
Julien Le Coupanec

最接近的是jQuery.OP却没有jQuery。
史蒂夫·莫雷兹

@stevemoretz。现在最接近的是本机JavaScript
Louise Eggleton

@LouiseEggleton是的,糟糕
史蒂夫·莫雷兹

这就是最好的答案!
ChosenUser

22

在不使用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');

2
我认为这不会奏效。它仅检查DOM树。th-> thead-> table从不考虑兄弟姐妹
hunterc

2
您应该在问题中说明具体情况。
2013年

2
看。此函数遍历parentNode来查找使用所提供标签的最接近的父级(甚至通过扩展名)。这不会使文档树“下降”,而只会“上升”。普通用户最有可能将“最近”节点视为最接近的同级节点。他只是不知道他需要的术语。

1
为了公平起见,@ Jhawins定义的最接近的是jQuery术语最接近的。这不是jQuery问题。我无法证明为什么jQuery确定最接近意味着最接近祖先,但是更合理的定义是最接近元素,无论是父元素,上一个兄弟姐妹,下一个兄弟姐妹等。无论找到的与目标元素“最接近”的元素。
ryandlf

1
@ryandlf但是,如果您的父母和兄弟姐妹都在相同的“距离”下怎么办?jQuery的定义很明确,因为它最多将返回一个匹配项。
mtone 2014年

9

有一个标准化的函数可以执行此操作:Element.closest。除IE11之外,大多数浏览器都支持它(caniuse.com进行了详细介绍)。的MDN文档还包括如果你有目标旧版浏览器的一个填充工具。

要找到tbody给定的最接近的父级,th您可以执行以下操作:

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

6
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
Balachandran

好抓住!固定,请参见jsfiddle.net/c2pqc2x0,请像老板一样我:)
马修·詹姆斯·戴维斯

是的,我病了...您检查了小提琴的结果吗,它显示错误..matches未定义
Balachandran

对我来说很棒,您正在使用哪个浏览器?较旧的浏览器不支持此功能
Matthew James Davis

嘿,让我们澄清一下,你怎么说兄弟
马修·詹姆斯·戴维斯

3

扩展@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;
}

2

这是我正在使用的简单功能:-

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

2

概要:

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

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>


1

在包含类,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循环?
拉斐尔·赫斯科维奇

1

查找最近的Elements子节点。

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;

}


0

这里。

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

只在树下找到兄弟姐妹。使用previousSibling进行其他选择,或使用变量遍历两种方法并返回最先找到的那个。您已基本了解,但是如果您要遍历parentNodes或子级不匹配的子级,则可以使用jQuery。在这一点上,它很值得。


0

派对晚了一点,但是当我路过并回答一个非常相似的问题时,我在这里提出了解决方案-我们可以说这是JQuery closest()方法,但是使用JavaScript很简单。

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


-4

我认为最容易用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>';
}
?>

非常感谢。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.