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]
pemburu
sumber
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;
}
Ales
sumber
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

oriadam
sumber
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');
Joon
sumber
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");
david1995
sumber
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);
Matthew James Davis
sumber
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;
}
zb '
sumber
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;
}
Salman von Abbas
sumber
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>

Willem van der Veen
sumber
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');
Chris Ferdinandi
sumber
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;

}

MajidTaheri
sumber
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.

RonnyKnoxville
sumber
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

Pedro Ferreira
sumber
-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.

AL MaMun
sumber