ค้นหาเว็บไซต์

javascript - ค้นหาองค์ประกอบบรรพบุรุษที่ใกล้ที่สุดที่มีคลาสเฉพาะ


ฉันจะหาบรรพบุรุษขององค์ประกอบที่อยู่ใกล้ที่สุดในต้นไม้ซึ่งมีคลาสเฉพาะได้อย่างไร โดยใช้ JavaScript ล้วนๆ? ตัวอย่างเช่น ในต้นไม้ดังนี้:

<div class="far ancestor">
    <div class="near ancestor">
        <p>Where am I?</p>
    </div>
</div>

แล้วฉันต้องการ div.near.ancestor หากฉันลองทำสิ่งนี้บน p และค้นหา ancestor

คำตอบ #1

อัปเดต: ตอนนี้รองรับในเบราว์เซอร์หลักส่วนใหญ่แล้ว

document.querySelector("p").closest(".near.ancestor")

โปรดทราบว่าสิ่งนี้สามารถจับคู่ตัวเลือกได้ ไม่ใช่แค่คลาส

https://developer.mozilla.org/th/docs/Web/API/Element.closest

สำหรับเบราว์เซอร์รุ่นเก่าที่ไม่รองรับ closest() แต่มี matches() สามารถสร้างการจับคู่ตัวเลือกที่คล้ายกับการจับคู่คลาสของ @rvighne ได้:

function findAncestor (el, sel) {
    while ((el = el.parentElement) && !((el.matches || el.matchesSelector).call(el,sel)));
    return el;
}

คำตอบ #2

นี่ใช้ได้ผล:

function findAncestor (el, cls) {
    while ((el = el.parentElement) && !el.classList.contains(cls));
    return el;
}

ลูป while จะรอจนกว่า el จะมีคลาสที่ต้องการ และมันจะตั้งค่า el ให้เป็นพาเรนต์ของ el ในทุกการวนรอบ ดังนั้นในที่สุด คุณจะได้บรรพบุรุษที่มีคลาสนั้นหรือ null

นี่คือตัว fiddle ถ้าใครต้องการปรับปรุง มันจะไม่ทำงานบนเบราว์เซอร์เก่า (เช่น IE); ดูตารางความเข้ากันได้นี้สำหรับ classList ที่นี่ใช้ parentElement เพราะ parentNode จะต้องทำงานเพิ่มเติมเพื่อให้แน่ใจว่าโหนดนั้นเป็นองค์ประกอบ

คำตอบ #3

ใช้ element.closest()

https://developer.mozilla.org/en-US/docs/Web/API/Element/closest

ดูตัวอย่าง DOM นี้:

<article>
  <div id="div-01">Here is div-01
    <div id="div-02">Here is div-02
      <div id="div-03">Here is div-03</div>
    </div>
  </div>
</article>

นี่คือวิธีที่คุณจะใช้ element.closest:

var el = document.getElementById('div-03');

var r1 = el.closest("#div-02");  
// returns the element with the id=div-02

var r2 = el.closest("div div");  
// returns the closest ancestor which is a div in div, here is div-03 itself

var r3 = el.closest("article > div");  
// returns the closest ancestor which is a div and has a parent article, here is div-01

var r4 = el.closest(":not(div)");
// returns the closest ancestor which is not a div, here is the outmost article

คำตอบ #4

อิงจากคำตอบของ the8472 และ https://developer.mozilla.org/en-US/docs/Web/API/Element/matches นี่คือวิธีแก้ไขแบบข้ามแพลตฟอร์มในปี 2017:

if (!Element.prototype.matches) {
    Element.prototype.matches =
        Element.prototype.matchesSelector ||
        Element.prototype.mozMatchesSelector ||
        Element.prototype.msMatchesSelector ||
        Element.prototype.oMatchesSelector ||
        Element.prototype.webkitMatchesSelector ||
        function(s) {
            var matches = (this.document || this.ownerDocument).querySelectorAll(s),
                i = matches.length;
            while (--i >= 0 && matches.item(i) !== this) {}
            return i > -1;
        };
}

function findAncestor(el, sel) {
    if (typeof el.closest === 'function') {
        return el.closest(sel) || null;
    }
    while (el) {
        if (el.matches(sel)) {
            return el;
        }
        el = el.parentElement;
    }
    return null;
}

คำตอบ #5

โซลูชันของ @rvighne ใช้งานได้ดี แต่ตามที่ระบุในความคิดเห็น ParentElement และ ClassList มีปัญหาความเข้ากันได้ทั้งคู่ เพื่อให้เข้ากันได้มากขึ้น ฉันได้ใช้:

function findAncestor (el, cls) {
    while ((el = el.parentNode) && el.className.indexOf(cls) < 0);
    return el;
}
  • คุณสมบัติ parentNode แทนที่จะใช้คุณสมบัติ parentElement
  • ใช้วิธี indexOf กับคุณสมบัติ className แทนการใช้วิธี contains กับคุณสมบัติ classList.

แน่นอนว่า indexOf เป็นเพียงการตรวจสอบการมีอยู่ของสตริงนั้น มันไม่ได้สนใจว่าสตริงนั้นจะทั้งหมดหรือไม่ ดังนั้นหากคุณมีองค์ประกอบอื่นที่มีคลาส 'ancestor-type' มันก็ยังคงคืนค่าการพบ 'ancestor' ได้ หากนี่เป็นปัญหาสำหรับคุณ อาจใช้ regexp เพื่อหาการจับคู่ที่ตรงกันเป๊ะ

บทความที่เกี่ยวข้อง