Menemukan elemen terdekat tanpa jQuery


90

Saya mencoba menemukan elemen terdekat dengan nama tag tertentu tanpa jquery. Saat saya mengklik a <th>Saya ingin mendapatkan akses ke <tbody>untuk tabel itu. Saran? Saya membaca tentang offset tetapi tidak terlalu memahaminya. Haruskah saya menggunakan:

Asumsikan th sudah disetel ke elemen yang diklik

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

1
Jika Anda menemukan bahwa Anda harus mulai menjelajahi DOM, ini adalah salah satu contoh di mana kbs ekstra yang dikaitkan dengan jquery akan sangat berharga.
Kevin Bowersox


2
Saya pikir ini adalah pertanyaan yang sangat penting dan valid. Tidak ada alasan untuk suara negatif.

el.closest('tbody')untuk browser non-ie. Lihat jawaban yang lebih diuraikan + polyfill di bawah ini.
oriadam

Jawaban:


69

Sedikit (sangat) terlambat ke pesta, tapi tetap saja. Ini harus melakukan trik :

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
Jawaban bagus yang berhasil. MDN juga memiliki polyfill untuk element.closest (). Chrome menyertakan element.matches () dalam rilis saat ini, jadi tidak perlu prefiks. Saya baru saja menambahkan ini ke lib yang saya gunakan di aplikasi yang saya kembangkan, Clibu.
nevf

2
Saya telah mengubah kodenya sehingga ia juga menguji elemen elyang dilakukan jQuery.closest () dan juga Element.closest (). for( var parent = el ; parent !== null && !parent[matchesFn](selector) ; parent = el.parentElement ){ el = parent; } return parent;
nevf

1
Kode ini baik-baik saja, tetapi tidak memiliki titik koma dan juga menentukan parentdalam cakupan global (!)
Steven Lu

1
Mungkin layak disebutkan: developer.mozilla.org/en-US/docs/Web/API/Element/closest metode asli untuk yang terdekat, meskipun sedikit dukungan rendah: Chrome41, FF35, IE-nope, Opera28, Safari9
Michiel D

Hanya catatan tentang ini, Anda mungkin ingin melakukannya el.parentNodeatau ini akan rusak saat melintasi SVG di IE.
smcka

124

Sangat sederhana:

el.closest('tbody')

Didukung di semua browser kecuali IE.
PEMBARUAN : Edge sekarang mendukungnya juga.

Tidak perlu jQuery. Terlebih lagi, mengganti jQuery $(this).closest('tbody')dengan $(this.closest('tbody'))akan meningkatkan kinerja, secara signifikan ketika elemen tidak ditemukan.

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

Perhatikan bahwa tidak ada returnsaat elemen tidak ditemukan, yang secara efektif dikembalikan undefinedsaat elemen terdekat tidak ditemukan.

Untuk lebih jelasnya lihat: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest


4
Mengapa jawaban ini ada di bagian bawah halaman? Harus di atas. Terima kasih banyak
Julien Le Coupanec

terdekat ada di jQuery. Tapi OP mengatakan tidak ada jQuery.
steve moretz

@tokopedia terdekat adalah JavaScript asli sekarang
Louise Eggleton

@LouiseEggleton Ya, oops
steve moretz

Itu disebut jawaban terbaik!
ChosenUser

22

Inilah cara Anda mendapatkan elemen terdekat dengan nama tag tanpa 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
Saya tidak percaya ini akan berhasil. Ini hanya memeriksa pohon DOM. th-> thead-> tabel tidak pernah menganggap saudara kandung
hunterc

2
Anda harus menyatakan kasus spesifik itu dalam pertanyaan Anda.
Joon

2
Lihat. Fungsi ini melintasi parentNodes untuk menemukan induk terdekat (bahkan menurut ekstensi) yang menggunakan tag yang disediakan. Ini tidak akan "turun" dari pohon dokumen, hanya "ke atas". Pengguna rata-rata akan melihat node "terdekat" kemungkinan besar sebagai saudara terdekat. Dia hanya tidak tahu terminologi yang dia butuhkan.

1
Dalam keadilan untuk @Jhawins definisi Anda tentang terdekat adalah istilah jQuery yang paling dekat. Ini bukan pertanyaan jQuery. Saya tidak bisa membuktikan mengapa jQuery memutuskan terdekat berarti leluhur terdekat, tetapi definisi yang lebih masuk akal akan menjadi elemen terdekat apakah itu orang tua, saudara sebelumnya, saudara berikutnya, dll. Apa pun yang ditemukan "paling dekat" dengan elemen target.
ryandlf

1
@ryandlf Tapi bagaimana jika Anda memiliki kedua orang tua dan saudara kandung pada "jarak" yang sama? Definisi jQuery jelas karena ia akan mengembalikan paling banyak satu kecocokan.
mtone

9

Ada fungsi standar untuk melakukan ini: Element.closest . Sebagian besar browser kecuali IE11 mendukungnya ( detail oleh caniuse.com ). Dokumen MDN juga menyertakan polyfill jika Anda harus menargetkan browser lama.

Untuk menemukan orang tbodytua terdekat yang diberikan, thAnda dapat melakukan:

th.closest('tbody');

Jika Anda ingin menulis fungsi sendiri - inilah yang saya buat:

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

Untuk menemukan orang tua terdekat dengan nama tag Anda bisa menggunakannya seperti ini:

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

Solusi ini menggunakan beberapa fitur terbaru dari spesifikasi HTML 5, dan menggunakan ini pada browser yang lebih lama / tidak kompatibel (baca: Internet Explorer) akan membutuhkan polyfill.

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

Itu selalu pergi ke tabel pertama teratas. bukan tabel terdekat .. lihat tautan ini jsfiddle.net/guuy5kof
Balachandran

tangkapan bagus! diperbaiki, lihat di sini jsfiddle.net/c2pqc2x0 tolong beri saya suara seperti bos :)
Matthew James Davis

ya saya sakit ... Apakah Anda memeriksa hasil biola Anda, itu menunjukkan kesalahan ..matches undefined
Balachandran

berfungsi dengan baik untuk saya, di browser mana Anda bekerja? ini tidak didukung di browser lama
Matthew James Davis

hei mari kita jelaskan suara negatif itu apa yang Anda katakan bro
Matthew James Davis

3

Untuk memperluas jawaban @SalmanPK

itu akan memungkinkan untuk menggunakan node sebagai pemilih, berguna ketika Anda bekerja dengan acara seperti gerakan mouse.

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

Inilah fungsi sederhana yang saya gunakan: -

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

Ringkasan:

Untuk menemukan leluhur tertentu kita dapat menggunakan:

Element.closest();

Fungsi ini mengambil string pemilih CSS sebagai argumen. ia kemudian mengembalikan leluhur terdekat dari elemen saat ini (atau elemen itu sendiri) yang cocok dengan pemilih CSS yang diteruskan dalam argumen. Jika tidak ada leluhur, ia akan kembali null.

Contoh:

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

Dapatkan elemen DOM terdekat di atas pohon yang berisi kelas, ID, atribut data, atau tag. Termasuk elemen itu sendiri. Didukung kembali ke 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');

Mengapa tidak menggunakan sakelar untuk firstCharalih - alih semua IFkondisi?
Rafael Herscovici

Mengapa menggunakan forloop yang dikaburkan ?
Rafael Herscovici

1

Temukan Elemen childNodes terdekat.

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

Sini.

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

Hanya menemukan saudara kandung di bawah pohon. Gunakan beforeSibling untuk pergi ke arah lain Atau gunakan variabel untuk melintasi kedua cara dan mengembalikan mana saja yang ditemukan lebih dulu. Anda mendapatkan gambaran umumnya, tetapi jika Anda ingin melintasi parentNodes atau turunan jika saudara kandung tidak cocok, Anda juga dapat menggunakan jQuery. Pada titik itu, itu sangat berharga.


0

Agak terlambat ke pesta, tetapi ketika saya lewat dan hanya menjawab kembali pertanyaan yang sangat mirip, saya mampir di sini solusi saya - kita dapat mengatakan itu adalah closest()pendekatan JQuery , tetapi dalam JavaScript yang bagus.

Itu tidak memerlukan pollyfills dan ini adalah browser yang lebih lama, dan ramah IE (:-)): https://stackoverflow.com/a/48726873/2816279


-4

Saya pikir kode termudah untuk ditangkap dengan jquery terdekat:

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

Terimakasih banyak.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.