Χειρισμός DOM σε καθαρή JavaScript. Τεχνικές DOM: Γονείς, παιδιά και γείτονες που εισάγουν περιεχόμενο στο DOM

Συνήθως, οι προγραμματιστές χρησιμοποιούν το jQuery όταν χρειάζεται να κάνουν κάτι με το DOM. Ωστόσο, σχεδόν οποιοσδήποτε χειρισμός DOM μπορεί να γίνει σε καθαρή JavaScript χρησιμοποιώντας το DOM API του.

Ας δούμε αυτό το API με περισσότερες λεπτομέρειες:

Στο τέλος, θα γράψετε τη δική σας απλή βιβλιοθήκη DOM που μπορεί να χρησιμοποιηθεί σε οποιοδήποτε έργο.

Ερωτήματα DOM

Τα ερωτήματα DOM εκτελούνται χρησιμοποιώντας τη μέθοδο .querySelector(), η οποία λαμβάνει ως όρισμα έναν αυθαίρετο επιλογέα CSS.

Const myElement = document.querySelector("#foo > div.bar")

Θα επιστρέψει το πρώτο στοιχείο που ταιριάζει. Μπορείτε να κάνετε το αντίθετο - ελέγξτε αν το στοιχείο ταιριάζει με τον επιλογέα:

MyElement.matches("div.bar") === true

Εάν θέλετε να λάβετε όλα τα στοιχεία που ταιριάζουν με έναν επιλογέα, χρησιμοποιήστε την ακόλουθη κατασκευή:

Const myElements = document.querySelectorAll(".bar")

Εάν γνωρίζετε ποιο γονικό στοιχείο θέλετε να αναφέρετε, μπορείτε απλώς να πραγματοποιήσετε αναζήτηση στα παιδιά του αντί να κάνετε αναζήτηση σε ολόκληρο τον κώδικα:

Const myChildElemet = myElement.querySelector("input") // Αντί για: // document.querySelector("#foo > είσοδος div.bar")

Τίθεται το ερώτημα: γιατί τότε να χρησιμοποιούμε άλλες, λιγότερο βολικές μεθόδους όπως το .getElementsByTagName() ; Υπάρχει ένα μικρό πρόβλημα - η έξοδος του .querySelector() δεν ενημερώνεται και όταν προσθέτουμε ένα νέο στοιχείο (δείτε ), δεν θα αλλάξει.

Const elements1 = document.querySelectorAll("div") const elements2 = document.getElementsByTagName("div") const newElement = document.createElement("div") document.body.appendChild(newElement) elements1.length === elements2.length // ψευδής

Επίσης, η querySelectorAll() συλλέγει τα πάντα σε μια λίστα, γεγονός που την καθιστά όχι πολύ αποτελεσματική.

Πώς να εργαστείτε με λίστες;

Επιπλέον, το .querySelectorAll() έχει δύο μικρές προειδοποιήσεις. Δεν μπορείτε απλώς να καλέσετε μεθόδους στα αποτελέσματα και να περιμένετε να εφαρμοστούν σε καθεμία (όπως μπορεί να έχετε συνηθίσει να κάνετε με το jQuery). Σε κάθε περίπτωση, θα χρειαστεί να επαναλάβετε όλα τα στοιχεία σε έναν βρόχο. Δεύτερον, το επιστρεφόμενο αντικείμενο είναι μια λίστα στοιχείων, όχι ένας πίνακας. Επομένως, οι μέθοδοι πίνακα δεν θα λειτουργήσουν. Φυσικά, υπάρχουν μέθοδοι για λίστες, κάτι σαν .forEach() , αλλά, δυστυχώς, δεν είναι κατάλληλες για όλες τις περιπτώσεις. Επομένως, είναι καλύτερο να μετατρέψετε τη λίστα σε πίνακα:

// Χρήση Array.from() Array.from(myElements).forEach(doSomethingWithEachElement) // Ή πρωτότυπο πίνακα (προ-ES6) Array.prototype.forEach.call(myElements, doSomethingWithEachElement) // Simplercall.(Each). myElements, doSomethingWithEachElement)

Κάθε στοιχείο έχει κάποιες ιδιότητες που παραπέμπουν σε μια «οικογένεια».

MyElement.children myElement.firstElementChild myElement.lastElementChild myElement.previousElementSibling myElement.nextElementSibling

Εφόσον η διεπαφή Element κληρονομείται από τη διεπαφή Node, υπάρχουν επίσης οι ακόλουθες ιδιότητες:

MyElement.childNodes myElement.firstChild myElement.lastChild myElement.previousSibling myElement.nextSibling myElement.parentNode myElement.parentElement

Οι πρώτες ιδιότητες αναφέρονται στο στοιχείο και οι τελευταίες (με εξαίρεση το .parentElement) μπορούν να είναι λίστες στοιχείων οποιουδήποτε τύπου. Αντίστοιχα, μπορείτε να ελέγξετε τον τύπο του στοιχείου:

MyElement.firstChild.nodeType === 3 // αυτό το στοιχείο θα είναι ένας κόμβος κειμένου

Προσθήκη κλάσεων και χαρακτηριστικών

Προσθήκη νέα τάξηπολύ απλό:

MyElement.classList.add("foo") myElement.classList.remove("bar") myElement.classList.toggle("baz")

Η προσθήκη μιας ιδιότητας σε ένα στοιχείο είναι η ίδια όπως για οποιοδήποτε αντικείμενο:

// Λάβετε την τιμή του χαρακτηριστικού const value = myElement.value // Ορίστε το χαρακτηριστικό ως ιδιότητα στοιχείου myElement.value = "foo" // Для установки нескольких свойств используйте.Object.assign() Object.assign(myElement, { value: "foo", id: "bar" }) // Удаление атрибута myElement.value = null !}

Μπορείτε να χρησιμοποιήσετε τις μεθόδους .getAttibute() , .setAttribute() και .removeAttribute(). Θα αλλάξουν αμέσως τα χαρακτηριστικά HTML του στοιχείου (σε αντίθεση με τις ιδιότητες DOM), γεγονός που θα προκαλέσει εκ νέου απόδοση του προγράμματος περιήγησης (μπορείτε να δείτε όλες τις αλλαγές εξετάζοντας το στοιχείο χρησιμοποιώντας τα εργαλεία προγραμματιστή του προγράμματος περιήγησης). Τέτοιες επανασχεδιάσεις όχι μόνο απαιτούν περισσότερους πόρους από τον ορισμό ιδιοτήτων DOM, αλλά μπορούν επίσης να οδηγήσουν σε απροσδόκητα σφάλματα.

Συνήθως, χρησιμοποιούνται για στοιχεία που δεν έχουν αντίστοιχες ιδιότητες DOM, όπως το colspan . Ή εάν η χρήση τους είναι πραγματικά απαραίτητη, για παράδειγμα για ιδιότητες HTML κατά την κληρονομικότητα (βλ.).

Προσθήκη στυλ CSS

Προστίθενται με τον ίδιο τρόπο όπως και άλλες ιδιότητες:

MyElement.style.marginLeft = "2em"

Ορισμένες συγκεκριμένες ιδιότητες μπορούν να ρυθμιστούν χρησιμοποιώντας το .style, αλλά αν θέλετε να λάβετε τις τιμές μετά από κάποιους υπολογισμούς, τότε είναι καλύτερο να χρησιμοποιήσετε το window.getComputedStyle() . Αυτή η μέθοδος λαμβάνει ένα στοιχείο και επιστρέφει μια CSSStyleDeclaration που περιέχει τα στυλ τόσο του ίδιου του στοιχείου όσο και του γονέα του:

Window.getComputedStyle(myElement).getPropertyValue("margin-left")

Αλλαγή του DOM

Μπορείτε να μετακινήσετε στοιχεία:

// Προσθήκη στοιχείου1 ως τελευταίου θυγατρικού στοιχείου2 στοιχείου1.appendChild(element2) // Εισαγωγή στοιχείου2 ως θυγατρικού στοιχείου1 πριν από το στοιχείο3 στοιχείο1.insertBefore(element2, element3)

Εάν δεν θέλετε να το μετακινήσετε, αλλά πρέπει να εισαγάγετε ένα αντίγραφο, χρησιμοποιήστε:

// Δημιουργία κλώνου const myElementClone = myElement.cloneNode() myParentElement.appendChild(myElementClone)

Η μέθοδος .cloneNode() λαμβάνει μια δυαδική τιμή ως όρισμα και εάν είναι αληθής, κλωνοποιούνται επίσης θυγατρικά στοιχεία.

Φυσικά μπορείτε να δημιουργήσετε νέα στοιχεία:

Const myNewElement = document.createElement("div") const myNewTextNode = document.createTextNode("κάποιο κείμενο")

Και μετά τοποθετήστε τα όπως φαίνεται παραπάνω. Δεν μπορείτε να διαγράψετε ένα στοιχείο απευθείας, αλλά μπορείτε να το κάνετε μέσω του γονικού στοιχείου:

MyParentElement.removeChild(myElement)

Μπορείτε επίσης να επικοινωνήσετε έμμεσα:

MyElement.parentNode.removeChild(myElement)

Μέθοδοι για στοιχεία

Κάθε στοιχείο έχει ιδιότητες όπως .innerHTML και .textContent , περιέχουν κώδικα HTML και, κατά συνέπεια, το ίδιο το κείμενο. Το ακόλουθο παράδειγμα αλλάζει το περιεχόμενο ενός στοιχείου:

// Αλλαγή του HTML myElement.innerHTML = ` Νέο περιεχόμενο ( el.addEventListener("αλλαγή", συνάρτηση (γεγονός) ( console.log(event.target.value) )) ))

Αποτροπή προεπιλεγμένων ενεργειών

Για να το κάνετε αυτό, χρησιμοποιήστε τη μέθοδο .preventDefault(), η οποία αποκλείει τυπικές ενέργειες. Για παράδειγμα, θα αποκλείσει την υποβολή φόρμας εάν η εξουσιοδότηση από την πλευρά του πελάτη δεν ήταν επιτυχής:

MyForm.addEventListener("submit", function (event) ( const name = this.querySelector("#name") if (name.value === "Donald Duck") { alert("You gotta be kidding!") event.preventDefault() } }) !}

Η μέθοδος .stopPropagation() θα σας βοηθήσει εάν έχετε εκχωρήσει ένα συγκεκριμένο πρόγραμμα χειρισμού συμβάντων σε ένα θυγατρικό στοιχείο και ένα δεύτερο πρόγραμμα χειρισμού συμβάντων στον γονέα για το ίδιο συμβάν.

Όπως αναφέρθηκε προηγουμένως, η μέθοδος .addEventListener() λαμβάνει ένα προαιρετικό τρίτο όρισμα με τη μορφή ενός αντικειμένου διαμόρφωσης. Αυτό το αντικείμενο πρέπει να περιέχει οποιαδήποτε από τις ακόλουθες δυαδικές ιδιότητες (όλα ορίζονται σε false από προεπιλογή):

  • λήψη: το συμβάν θα προσαρτηθεί σε αυτό το στοιχείο πριν από οποιοδήποτε άλλο στοιχείο παρακάτω στο DOM.
  • Μία φορά: ένα συμβάν μπορεί να ανατεθεί μόνο μία φορά.
  • παθητικό: το event.preventDefault() θα αγνοηθεί (εξαίρεση κατά το σφάλμα).

Η πιο συνηθισμένη ιδιότητα είναι .capture και είναι τόσο συνηθισμένη που υπάρχει μια συντόμευση για αυτήν: αντί να τη μεταβιβάσετε σε ένα αντικείμενο διαμόρφωσης, απλώς περάστε την τιμή της εδώ:

MyElement.addEventListener (τύπος, ακροατής, true)

Τα προγράμματα χειρισμού καταργούνται χρησιμοποιώντας τη μέθοδο .removeEventListener(), η οποία παίρνει δύο ορίσματα: τον τύπο συμβάντος και μια αναφορά στο πρόγραμμα χειρισμού προς κατάργηση. Για παράδειγμα, η ιδιότητα Once μπορεί να υλοποιηθεί ως εξής:

MyElement.addEventListener("αλλαγή", λειτουργία ακρόασης (συμβάν) ( console.log(event.type + " ενεργοποιήθηκε στο " + this) this.removeEventListener("αλλαγή", ακροατής) ))

Κληρονομία

Ας υποθέσουμε ότι έχετε ένα στοιχείο και θέλετε να προσθέσετε ένα πρόγραμμα χειρισμού συμβάντων για όλα τα παιδιά του. Στη συνέχεια, θα πρέπει να πραγματοποιήσετε βρόχο μέσω αυτών χρησιμοποιώντας τη μέθοδο myForm.querySelectorAll("input") όπως φαίνεται παραπάνω. Ωστόσο, μπορείτε απλώς να προσθέσετε στοιχεία στη φόρμα και να ελέγξετε το περιεχόμενό τους χρησιμοποιώντας το event.target .

MyForm.addEventListener("αλλαγή", συνάρτηση (γεγονός) ( const target = event.target if (target.matches("input")) ( console.log(target.value) )))

Και ένα άλλο πλεονέκτημα αυτής της μεθόδου είναι ότι ο χειριστής θα συνδεθεί αυτόματα σε νέα θυγατρικά στοιχεία.

Κινουμένων σχεδίων

Ο ευκολότερος τρόπος για να προσθέσετε κινούμενα σχέδια είναι η χρήση CSS με την ιδιότητα μετάβασης. Αλλά για μεγαλύτερη ευελιξία (για παράδειγμα, για παιχνίδια), η JavaScript ταιριάζει καλύτερα.

Η κλήση της μεθόδου window.setTimeout() μέχρι να τελειώσει η κινούμενη εικόνα δεν είναι καλή ιδέα, καθώς η εφαρμογή σας μπορεί να παγώσει, ειδικά σε κινητές συσκευές. Είναι καλύτερα να χρησιμοποιήσετε το window.requestAnimationFrame() για να αποθηκεύσετε όλες τις αλλαγές μέχρι την επόμενη επανασχεδίαση. Παίρνει μια συνάρτηση ως όρισμα, η οποία με τη σειρά της λαμβάνει μια χρονική σήμανση:

Const start = window.performance.now() const duration = 2000 window.requestAnimationFrame(function fadeIn (now)) ( const progress = now - start myElement.style.opacity = πρόοδος / διάρκεια if (progress< duration) { window.requestAnimationFrame(fadeIn) } }

Με αυτόν τον τρόπο επιτυγχάνεται πολύ ομαλή κινούμενη εικόνα. Στο άρθρο του, ο Mark Brown συζητά αυτό το θέμα.

Γράφοντας τη δική μας βιβλιοθήκη

Το γεγονός ότι στο DOM πρέπει να επαναλαμβάνετε στοιχεία συνεχώς για να εκτελέσετε οποιεσδήποτε λειτουργίες σε στοιχεία μπορεί να φαίνεται αρκετά κουραστικό σε σύγκριση με τη σύνταξη $(".foo").css((color: "κόκκινο")) του jQuery. Αλλά γιατί να μην γράψετε μερικές από τις δικές σας μεθόδους για να κάνετε αυτή την εργασία ευκολότερη;

Const $ = συνάρτηση $ (επιλογέας, πλαίσιο = έγγραφο) ( στοιχεία const = Array.from(context.querySelectorAll(selector)) επιστροφή ( στοιχεία, html (newHtml) ( this.elements.forEach(element => ( element.innerHTML = newHtml )) return this ), css (newCss) ( this.elements.forEach(element => ( Object.assign(element.style, newCss) )) return this ), on (event, handler, options) ( this.elements .forEach(στοιχείο => ( element.addEventListener(συμβάν, χειριστής, επιλογές) )) επιστρέψτε αυτό ) )

Ψευδοκώδικας

$(".rightArrow").click(function() ( rightArrowParents = this.dom(); //.dom(); είναι η ψευδοσυνάρτηση ... θα πρέπει να εμφανίζει ολόκληρη την ειδοποίηση(rightArrowParents); ));

Το μήνυμα συναγερμού θα είναι:

body div.lol a.rightArrow

Πώς μπορώ να το αποκτήσω χρησιμοποιώντας javascript/jquery;

Χρησιμοποιώντας το jQuery όπως αυτό (ακολουθούμενη από μια λύση που δεν χρησιμοποιεί jQuery εκτός από το συμβάν, πολύ λιγότερες κλήσεις συναρτήσεων, αν αυτό είναι σημαντικό):

Παράδειγμα σε πραγματικό χρόνο:

$(".rightArrow").click(function() ( var rightArrowParents = ; $(this).parents().addBack().not("html").each(function() ( var entry = this.tagName .toLowerCase(); if (this.className) (καταχώρηση += "." + this.className.replace(/ /g, "."); ) rightArrowParents.push(entry); )); alert(rightArrowParents.join (" ")); επιστροφή ψευδής;)); Κάντε κλικ ΕΔΩ

(Στα ζωντανά παραδείγματα, ενημέρωσα το χαρακτηριστικό class στο div ώστε να είναι lol multi για να δείξω ότι χειρίζομαι πολλές κλάσεις.)

Εδώ είναι μια λύση για την ακριβή αντιστοίχιση στοιχείων.

Είναι σημαντικό να κατανοήσουμε ότι ο επιλογέας (δεν είναι πραγματικό) που δείχνουν τα εργαλεία chrome δεν προσδιορίζουν μοναδικά το στοιχείο στο DOM. ( για παράδειγμα, δεν θα κάνει διάκριση μεταξύ μιας λίστας διαδοχικών στοιχείων διαστήματος. Δεν υπάρχουν πληροφορίες τοποθέτησης/ευρετηρίου)

$.fn.fullSelector = συνάρτηση () ( var path = this.parents().addBack(); var quickCss = path.get().map(function (item) ( var self = $(item), id = item .id ? "#" + item.id: "", clss = item.classList.length ? item.classList.toString().split(" ").map(function (c) ( return "." + c; )).join("") : "", name = item.nodeName.toLowerCase(), index = self.siblings(name).length ? ":nth-child(" + (self.index() + 1) + ")" : ""; if (όνομα === "html" || όνομα === "σώμα") ( όνομα επιστροφής; ) όνομα επιστροφής + ευρετήριο + id + clss; )).join(" > ") ; επιστροφή quickCss; );

Και μπορείτε να το χρησιμοποιήσετε ως εξής:

Console.log($("some-selector").fullSelector());

Μετακίνησα ένα κομμάτι από τον T.J. Crowder έως μικροσκοπικό Πρόσθετο jQuery. Χρησιμοποίησα την έκδοση jQuery, ακόμα κι αν έχει δίκιο ότι είναι εντελώς περιττή, αλλά τη χρησιμοποιώ μόνο για σκοπούς εντοπισμού σφαλμάτων, οπότε δεν με νοιάζει.

Χρήση:

Ένθετο άνοιγμα Απλό άνοιγμα Προ

// αποτέλεσμα (πίνακας): ["body", "div.sampleClass"] $("span").getDomPath(false) // αποτέλεσμα (string): body > div.sampleClass $("span").getDomPath( ) // αποτέλεσμα (πίνακας): ["body", "div#test"] $("pre").getDomPath(false) // αποτέλεσμα (string): body > div#test $("pre").getDomPath ()

Var obj = $("#show-editor-button"), διαδρομή = ""; while (typeof obj.prop("tagName") != "undefined")( if (obj.attr("class"))( path = "."+obj.attr("class").replace(/\s /g , ".") + διαδρομή; ) if (obj.attr("id"))( path = "#"+obj.attr("id") + διαδρομή; ) path = " " +obj.prop( "tagName").toLowerCase() + διαδρομή; obj = obj.parent(); ) console.log(path);

Γεια σας αυτή η συνάρτηση επιλύει το σφάλμα που σχετίζεται με το τρέχον στοιχείο που δεν εμφανίζεται στη διαδρομή

Ελέγξτε το τώρα

$j(".wrapper").click(function(event) ( selectedElement=$j(event.target); var rightArrowParents = ; $j(event.target).parents().not("html,body") .each(function() ( var entry = this.tagName.toLowerCase(); if (this.className) ( entry += "." + this.className.replace(/ /g, "."); )άλλο εάν (this.id)( entry += "#" + this.id; ) entry=replaceAll(entry,.","."); rightArrowParents.push(entry); )); rightArrowParents.reverse(); // if(event.target.nodeName.toLowerCase()=="a" || event.target.nodeName.toLowerCase()=="h1")( var entry = event.target.nodeName.toLowerCase(); if (συμβάν .target.className) ( καταχώριση += "." + event.target.className.replace(/ /g, "."); )άλλο if(event.target.id)( καταχώρηση += "#" + συμβάν. target.id; ) rightArrowParents.push(entry); // )

Όπου $j = Μεταβλητή jQuery

λύστε επίσης το πρόβλημα με το .. στο όνομα της τάξης

εδώ είναι η λειτουργία αντικατάστασης:

Συνάρτηση escapeRegExp(str) ( return str.replace(/([.*+?^=!:$()()|\[\]\/\\])/g, "\\$1"); ) συνάρτηση replaceAll(str, find, replace) ( return str.replace(new RegExp(escapeRegExp(find), "g"), αντικατάσταση); )

Ακολουθεί μια εγγενής έκδοση JS που επιστρέφει τη διαδρομή jQuery. Προσθέτω επίσης αναγνωριστικά για τα στοιχεία εάν υπάρχουν. Αυτό θα σας δώσει την επιλογή να ακολουθήσετε τη συντομότερη διαδρομή εάν δείτε το αναγνωριστικό στον πίνακα.

Var path = getDomPath(στοιχείο); console.log(path.join(" > "));

Body > section:eq(0) > div:eq(3) > section#content > section#firehose > div#firehoselist > article#firehose-46813651 > header > h2 > span#title-46813651

Εδώ είναι η λειτουργία.

Συνάρτηση getDomPath(el) ( var stack = ; while (el.parentNode != null) ( console.log(el.nodeName); var sibCount = 0; var sibIndex = 0; for (var i = 0; i< el.parentNode.childNodes.length; i++) { var sib = el.parentNode.childNodes[i]; if (sib.nodeName == el.nodeName) { if (sib === el) { sibIndex = sibCount; } sibCount++; } } if (el.hasAttribute("id") && el.id != "") { stack.unshift(el.nodeName.toLowerCase() + "#" + el.id); } else if (sibCount >1) ( stack.unshift(el.nodeName.toLowerCase() + ":eq(" + sibIndex + ")"); ) else ( stack.unshift(el.nodeName.toLowerCase()); ) el = el.parentNode ; ) return stack.slice(1); // αφαιρεί το στοιχείο html)

Πολύπλοκες και βαριές εφαρμογές web έχουν γίνει κοινές αυτές τις μέρες. Οι βιβλιοθήκες πολλαπλών προγραμμάτων περιήγησης και οι εύχρηστες βιβλιοθήκες όπως το jQuery με την πλούσια λειτουργικότητά τους μπορούν να βοηθήσουν σημαντικά στον χειρισμό του DOM εν κινήσει. Επομένως, δεν προκαλεί έκπληξη το γεγονός ότι πολλοί προγραμματιστές χρησιμοποιούν τέτοιες βιβλιοθήκες πιο συχνά από το να εργάζονται με το εγγενές DOM API, με το οποίο υπήρχαν πολλά προβλήματα. Ενώ οι διαφορές στο πρόγραμμα περιήγησης εξακολουθούν να αποτελούν πρόβλημα, το DOM είναι σε καλύτερη κατάσταση τώρα από ό,τι ήταν πριν από 5-6 χρόνια, όταν το jQuery κέρδιζε δημοτικότητα.

Σε αυτό το άρθρο, θα δείξω τις δυνατότητες χειρισμού HTML του DOM, εστιάζοντας στις σχέσεις γονέα, παιδιού και γείτονα. Εν κατακλείδι, θα δώσω πληροφορίες σχετικά με την υποστήριξη του προγράμματος περιήγησης για αυτές τις δυνατότητες, αλλά να έχετε κατά νου ότι μια βιβλιοθήκη όπως το jQuery εξακολουθεί να είναι μια καλή επιλογή λόγω της παρουσίας σφαλμάτων και ασυνεπειών στην υλοποίηση της εγγενούς λειτουργικότητας.

Καταμέτρηση παιδικών κόμβων

Για επίδειξη θα χρησιμοποιήσω τα παρακάτω Σήμανση HTML, θα το αλλάξουμε πολλές φορές σε όλο το άρθρο:

  • Παράδειγμα ένα
  • Παράδειγμα δύο
  • Παράδειγμα τρία
  • Παράδειγμα τέσσερα
  • Παράδειγμα πέντε
  • Παράδειγμα έκτο

Var myList = document.getElementById("myList"); console.log(myList.children.length); // 6 console.log(myList.childElementCount); // 6

Όπως μπορείτε να δείτε, τα αποτελέσματα είναι τα ίδια, αν και οι τεχνικές που χρησιμοποιούνται είναι διαφορετικές. Στην πρώτη περίπτωση χρησιμοποιώ την ιδιοκτησία των παιδιών. Αυτή είναι μια ιδιότητα μόνο για ανάγνωση, επιστρέφει μια συλλογή στοιχεία HTML, που βρίσκεται μέσα στο ζητούμενο στοιχείο. Για να μετρήσω τον αριθμό τους, χρησιμοποιώ την ιδιότητα length αυτής της συλλογής.

Στο δεύτερο παράδειγμα, χρησιμοποιώ τη μέθοδο childElementCount, η οποία νομίζω ότι είναι πιο τακτοποιημένος και δυνητικά πιο διατηρήσιμος τρόπος (συζητήστε το περισσότερο αργότερα, δεν νομίζω ότι θα δυσκολευτείτε να καταλάβετε τι κάνει).

Θα μπορούσα να δοκιμάσω να χρησιμοποιήσω το childNodes.length (αντί για το child.length), αλλά κοιτάξτε το αποτέλεσμα:

Var myList = document.getElementById("myList"); console.log(myList.childNodes.length); // 13

Επιστρέφει 13 επειδή το childNodes είναι μια συλλογή από όλους τους κόμβους, συμπεριλαμβανομένων των διαστημάτων - έχετε αυτό υπόψη εάν ενδιαφέρεστε για τη διαφορά μεταξύ θυγατρικών κόμβων και κόμβων θυγατρικών στοιχείων.

Έλεγχος ύπαρξης θυγατρικών κόμβων

Για να ελέγξω εάν ένα στοιχείο έχει θυγατρικούς κόμβους, μπορώ να χρησιμοποιήσω τη μέθοδο hasChildNodes(). Η μέθοδος επιστρέφει μια Boolean τιμή που υποδεικνύει την παρουσία ή την απουσία τους:

Var myList = document.getElementById("myList"); console.log(myList.hasChildNodes()); // αληθές

Γνωρίζω ότι η λίστα μου έχει θυγατρικούς κόμβους, αλλά μπορώ να αλλάξω το HTML έτσι ώστε να μην υπάρχουν. Η σήμανση τώρα μοιάζει με αυτό:

Και εδώ είναι το αποτέλεσμα της εκ νέου εκτέλεσης της hasChildNodes():

Console.log(myList.hasChildNodes()); // αληθές

Η μέθοδος εξακολουθεί να επιστρέφει true. Αν και η λίστα δεν περιέχει στοιχεία, περιέχει ένα κενό, το οποίο είναι έγκυρος τύπος κόμβου. Αυτή η μέθοδοςλαμβάνει υπόψη όλους τους κόμβους, όχι μόνο τους κόμβους στοιχείων. Για να επιστρέψει η hasChildNodes() false, πρέπει να αλλάξουμε ξανά τη σήμανση:

Και τώρα το αναμενόμενο αποτέλεσμα εμφανίζεται στην κονσόλα:

Console.log(myList.hasChildNodes()); // ψευδής

Φυσικά, αν ξέρω ότι μπορεί να συναντήσω κενό διάστημα, θα ελέγξω πρώτα την ύπαρξη θυγατρικών κόμβων και, στη συνέχεια, θα χρησιμοποιήσω την ιδιότητα nodeType για να προσδιορίσω εάν υπάρχουν κόμβοι στοιχείων μεταξύ τους.

Προσθήκη και αφαίρεση παιδικών στοιχείων

Υπάρχουν τεχνικές που μπορείτε να χρησιμοποιήσετε για να προσθέσετε και να αφαιρέσετε στοιχεία από το DOM. Το πιο διάσημο από αυτά βασίζεται σε έναν συνδυασμό των μεθόδων createElement() και appendChild().

Var myEl = document.createElement("div"); document.body.appendChild(myEl);

Σε αυτήν την περίπτωση, δημιουργώ χρησιμοποιώντας τη μέθοδο createElement() και μετά την προσθέτω στο σώμα . Είναι πολύ απλό και μάλλον έχετε χρησιμοποιήσει αυτή την τεχνική στο παρελθόν.

Αντί όμως να εισάγουμε συγκεκριμένα στοιχείο που δημιουργείται, μπορώ επίσης να χρησιμοποιήσω το appendChild() και απλώς να μετακινήσω το υπάρχον στοιχείο. Ας υποθέσουμε ότι έχουμε την ακόλουθη σήμανση:

  • Παράδειγμα ένα
  • Παράδειγμα δύο
  • Παράδειγμα τρία
  • Παράδειγμα τέσσερα
  • Παράδειγμα πέντε
  • Παράδειγμα έκτο

Παράδειγμα κειμένου

Μπορώ να αλλάξω τη θέση της λίστας με τον ακόλουθο κωδικό:

Var myList = document.getElementById("myList"), container = document.getElementById("c"); container.appendChild(myList);

Το τελικό DOM θα μοιάζει με αυτό:

Παράδειγμα κειμένου

  • Παράδειγμα ένα
  • Παράδειγμα δύο
  • Παράδειγμα τρία
  • Παράδειγμα τέσσερα
  • Παράδειγμα πέντε
  • Παράδειγμα έκτο

Παρατηρήστε ότι ολόκληρη η λίστα έχει αφαιρεθεί από τη θέση της (πάνω από την παράγραφο) και στη συνέχεια έχει εισαχθεί μετά από αυτήν πριν από το σώμα κλεισίματος . Ενώ η μέθοδος appendChild() χρησιμοποιείται συνήθως για την προσθήκη στοιχείων που δημιουργούνται με την createElement() , μπορεί επίσης να χρησιμοποιηθεί για τη μετακίνηση υπαρχόντων στοιχείων.

Μπορώ επίσης να αφαιρέσω εντελώς ένα θυγατρικό στοιχείο από το DOM χρησιμοποιώντας removeChild() . Δείτε πώς μπορείτε να διαγράψετε τη λίστα μας από το προηγούμενο παράδειγμα:

Var myList = document.getElementById("myList"), container = document.getElementById("c"); container.removeChild(myList);

Το στοιχείο έχει πλέον αφαιρεθεί. Η μέθοδος removeChild() επιστρέφει το αφαιρεμένο στοιχείο ώστε να μπορώ να το αποθηκεύσω σε περίπτωση που το χρειαστώ αργότερα.

Var myOldChild = document.body.removeChild(myList); document.body.appendChild(myOldChild);

Υπάρχει επίσης μια μέθοδος ChildNode.remove() που προστέθηκε σχετικά πρόσφατα στην προδιαγραφή:

Var myList = document.getElementById("myList"); myList.remove();

Αυτή η μέθοδος δεν επιστρέφει το απομακρυσμένο αντικείμενο και δεν λειτουργεί σε IE (μόνο Edge). Και οι δύο μέθοδοι αφαιρούν τους κόμβους κειμένου με τον ίδιο τρόπο όπως οι κόμβοι στοιχείων.

Αντικατάσταση παιδικών στοιχείων

Μπορώ να αντικαταστήσω ένα υπάρχον θυγατρικό στοιχείο με ένα νέο, είτε αυτό το νέο στοιχείο υπάρχει είτε το δημιούργησα από την αρχή. Εδώ είναι η σήμανση:

Παράδειγμα κειμένου

Var myPar = document.getElementById("par"), myDiv = document.createElement("div"); myDiv.className = "παράδειγμα"; myDiv.appendChild(document.createTextNode("Κείμενο νέου στοιχείου")); document.body.replaceChild(myDiv, myPar);

Κείμενο νέου στοιχείου

Όπως μπορείτε να δείτε, η μέθοδος replaceChild() παίρνει δύο ορίσματα: το νέο στοιχείο και το παλιό στοιχείο που αντικαθιστά.

Μπορώ επίσης να χρησιμοποιήσω αυτήν τη μέθοδο για να μετακινήσω ένα υπάρχον στοιχείο. Ρίξτε μια ματιά στον ακόλουθο HTML:

Παράδειγμα κειμένου 1

Παράδειγμα κειμένου 2

Παράδειγμα κειμένου 3

Μπορώ να αντικαταστήσω την τρίτη παράγραφο με την πρώτη παράγραφο χρησιμοποιώντας τον ακόλουθο κώδικα:

Var myPar1 = document.getElementById("par1"), myPar3 = document.getElementById("par3"); document.body.replaceChild(myPar1, myPar3);

Τώρα το DOM που δημιουργήθηκε μοιάζει με αυτό:

Παράδειγμα κειμένου 2

Παράδειγμα κειμένου 1

Επιλογή συγκεκριμένων παιδιών

Υπάρχουν αρκετές διαφορετικοί τρόποιεπιλέγοντας ένα συγκεκριμένο στοιχείο. Όπως φαίνεται νωρίτερα, μπορώ να ξεκινήσω χρησιμοποιώντας τη συλλογή παιδιών ή την ιδιότητα childNodes. Ας δούμε όμως και άλλες επιλογές:

Οι ιδιότητες firstElementChild και lastElementChild κάνουν ακριβώς αυτό που υποδεικνύουν τα ονόματά τους: επιλέξτε το πρώτο και το τελευταίο θυγατρικό στοιχείο. Ας επιστρέψουμε στη σήμανση:

  • Παράδειγμα ένα
  • Παράδειγμα δύο
  • Παράδειγμα τρία
  • Παράδειγμα τέσσερα
  • Παράδειγμα πέντε
  • Παράδειγμα έκτο

Μπορώ να επιλέξω το πρώτο και το τελευταίο στοιχείο χρησιμοποιώντας αυτές τις ιδιότητες:

Var myList = document.getElementById("myList"); console.log(myList.firstElementChild.innerHTML); // "Παράδειγμα ένα" console.log(myList.lastElementChild.innerHTML); // "Παράδειγμα έξι"

Μπορώ επίσης να χρησιμοποιήσω τις ιδιότητες previousElementSibling και nextElementSibling εάν θέλω να επιλέξω θυγατρικά στοιχεία εκτός από το πρώτο ή το τελευταίο. Αυτό γίνεται συνδυάζοντας τις ιδιότητες firstElementChild και lastElementChild:

Var myList = document.getElementById("myList"); console.log(myList.firstElementChild.nextElementSibling.innerHTML); // "Παράδειγμα δύο" console.log(myList.lastElementChild.previousElementSibling.innerHTML); // "Παράδειγμα πέντε"

Υπάρχουν επίσης παρόμοιες ιδιότητες firstChild , lastChild , previousSibling και nextSibling , αλλά λαμβάνουν υπόψη όλους τους τύπους κόμβων, όχι μόνο στοιχεία. Γενικά, οι ιδιότητες που λαμβάνουν υπόψη μόνο τους κόμβους στοιχείων είναι πιο χρήσιμες από αυτές που επιλέγουν όλους τους κόμβους.

Εισαγωγή περιεχομένου στο DOM

Έχω ήδη εξετάσει τρόπους εισαγωγής στοιχείων στο DOM. Ας προχωρήσουμε στο παρόμοιο θέμακαι ρίξτε μια ματιά στις νέες επιλογές για την εισαγωγή περιεχομένου.

Πρώτον, υπάρχει μια απλή μέθοδος insertBefore(), όπως η replaceChild(), παίρνει δύο ορίσματα και λειτουργεί τόσο με νέα στοιχεία όσο και με υπάρχοντα. Εδώ είναι η σήμανση:

  • Παράδειγμα ένα
  • Παράδειγμα δύο
  • Παράδειγμα τρία
  • Παράδειγμα τέσσερα
  • Παράδειγμα πέντε
  • Παράδειγμα έκτο

Παράδειγμα Παράγραφος

Προσέξτε την παράγραφο που πρόκειται να αφαιρέσω πρώτα και στη συνέχεια να την εισαγάγετε πριν από τη λίστα, όλα με μια κίνηση:

Var myList = document.getElementById("myList"), container = document.getElementBy("c"), myPar = document.getElementById("par"); container.insertBefore(myPar, myList);

Στο HTML που προκύπτει, η παράγραφος θα εμφανιστεί πριν από τη λίστα και αυτός είναι ένας άλλος τρόπος για να αναδιπλώσετε το στοιχείο.

Παράδειγμα Παράγραφος

  • Παράδειγμα ένα
  • Παράδειγμα δύο
  • Παράδειγμα τρία
  • Παράδειγμα τέσσερα
  • Παράδειγμα πέντε
  • Παράδειγμα έκτο

Όπως και η replaceChild(), η insertBefore() παίρνει δύο ορίσματα: το στοιχείο που πρέπει να προστεθεί και το στοιχείο πριν από το οποίο θέλουμε να το εισαγάγουμε.

Αυτή η μέθοδος είναι απλή. Ας δοκιμάσουμε τώρα μια πιο ισχυρή μέθοδο εισαγωγής: τη μέθοδο insertAdjacentHTML().