jQueryなしで最も近い要素を見つける


90

jqueryなしで特定のタグ名を持つ最も近い要素を見つけようとしています。[]をクリックすると、そのテーブル<th>のにアクセスでき<tbody>ます。提案?オフセットについて読んだのですが、あまり理解していませんでした。私はただ使うべきですか:

thがすでにクリックされたth要素に設定されていると仮定します

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

1
DOMのトラバースを開始する必要があることがわかった場合、これはjqueryに起因する追加のkbが価値がある1つのインスタンスです。
Kevin Bowersox 2013


2
これは非常に重要で有効な質問だと思います。反対票を投じる理由はありません。

el.closest('tbody')非IEブラウザ用。以下のより詳細な回答とポリフィルを参照してください。
oriadam 2016

回答:


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()のポリフィルもあります。Chromeには現在のリリースにelement.matches()が含まれているため、プレフィックスは必要ありません。これを、開発中のアプリClibuで使用しているライブラリに追加しました。
nevf 2015年

2
eljQuery.closest()およびElement.closest()が実行する要素もテストするようにコードを変更しました。for( var parent = el ; parent !== null && !parent[matchesFn](selector) ; parent = el.parentElement ){ el = parent; } return parent;
nevf 2015年

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

124

非常に簡単:

el.closest('tbody')

IEを除くすべてのブラウザでサポートされています。
更新:Edgeはそれもサポートするようになりました。

jQueryは必要ありません。さらに、jQueryをに置き換える$(this).closest('tbody')$(this.closest('tbody'))、要素が見つからない場合にパフォーマンスが大幅に向上します。

IE用のポリフィル:

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
この回答がページの下部にあるのはなぜですか?一番上にある必要があります。
どうも

最も近いのはjQueryですが、OPはjQueryを指定していません。
stevemoretz19年

@stevemoretz。最も近いのは現在ネイティブJavaScriptです
LouiseEggleton19年

@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 2013

2
あなたはあなたの質問でその特定のケースを述べるべきでした。
2013

2
見てください。この関数は、parentNodesをトラバースして、提供されたタグを使用する最も近い親を(拡張子によっても)見つけます。これはドキュメントツリーを「下に」移動するのではなく、「上に」移動するだけです。平均的なユーザーは、「最も近い」ノードを最も近い兄弟として見る可能性が最も高いでしょう。彼は必要な用語を知らないだけです。

1
@Jhawinsに公平を期すために、最も近いという定義は、jQueryが最も近いと呼ぶものです。これはjQueryの質問ではありません。jQueryが最も近いと判断した理由を証明することはできませんが、親、前の兄弟、次の兄弟など、より合理的な定義は最も近い要素です。ターゲット要素に「最も近い」と判断されたものは何でも。
ryandlf 2014

1
@ryandlfしかし、同じ「距離」に親と兄弟の両方がいる場合はどうなるでしょうか。jQueryの定義は、最大で1つの一致を返すという点で明確です。
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を参照)でこれを使用するには、ポリフィルが必要になります。

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上司のように私を賛成してください:)
Matthew James Davis

ya i ill do ...フィドルの結果を確認しましたか?エラーが表示されます..matches undefined
Balachandran

どのブラウザで作業していますか?これは古いブラウザではサポートされていません
Matthew James Davis

ねえ、あなたが何を言っているのか、その反対票をクリアしましょう
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条件の代わりにスイッチを使用してみませんか?
Rafael Herscovici 2017年

なぜ隠されたforループを使用するのですか?
Rafael Herscovici 2017年

1

最も近い要素childNodesを見つけます。

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を使用して反対方向に進むか、変数を使用して両方の方向をトラバースし、最初に見つかった方を返します。一般的な考え方は理解できますが、兄弟が一致しない場合にparentNodeまたは子をトラバースする場合は、jQueryを使用することもできます。その時点で、それは簡単に価値があります。


0

パーティーに少し遅れましたが、通りかかったときに非常によく似た質問に答えたので、ここに解決策を示します。これはJQueryのclosest()アプローチであると言えますが、JavaScriptの古き良き時代です。

それはポリフィルを必要とせず、古いブラウザであり、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>';
}
?>

どうもありがとう。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.