to
Κάθε στοιχείο μπορεί να έχει μόνο μία ρίζα σκιάς. Μερικά στοιχεία, συμπεριλαμβανομένων και
έχουν ήδη μια ενσωματωμένη ρίζα σκιάς που δεν είναι προσβάσιμη μέσω του Scripting. Μπορείτε να τα επιθεωρήσετε με τα εργαλεία προγραμματιστή σας, επιτρέποντας το Εμφάνιση σκιώδους πράκτορα χρήστη Dom Ρύθμιση, η οποία είναι “απενεργοποιημένη” από προεπιλογή.

Δημιουργία ρίζας σκιάς
Πριν αξιοποιήσετε τα οφέλη της σκιάς Dom, πρέπει πρώτα να δημιουργήσετε ένα σκιά ρίζα σε ένα στοιχείο. Αυτό μπορεί να παρουσιαστεί επιφανειακά ή δηλωτικά.
Επιτακτική εμφάνιση
Για να δημιουργήσετε μια ρίζα σκιάς χρησιμοποιώντας το JavaScript, χρησιμοποιήστε attachShadow({ mode })
σε ένα στοιχείο. Ο mode
μπορεί να είναι open
(επιτρέποντας την πρόσβαση μέσω element.shadowRoot
) ή closed
(κρύβοντας τη ρίζα της σκιάς από εξωτερικά σενάρια).
const host = document.createElement('div');
const shadow = host.attachShadow({ mode: 'open' });
shadow.innerHTML = 'Hello from the Shadow DOM!
';
document.body.appendChild(host);
Σε αυτό το παράδειγμα, έχουμε δημιουργήσει ένα open
ρίζα σκιάς. Αυτό σημαίνει ότι το περιεχόμενο του στοιχείου είναι προσβάσιμο από το εξωτερικό και μπορούμε να το ζητήσουμε όπως κάθε άλλος κόμβος DOM:
host.shadowRoot.querySelector('p'); // selects the paragraph element
Εάν θέλουμε να αποτρέψουμε εξ ολοκλήρου τα εξωτερικά σενάρια πρόσβασης στην εσωτερική μας δομή, μπορούμε να ρυθμίσουμε τη λειτουργία closed
αντί. Αυτό προκαλεί τα στοιχεία shadowRoot
ιδιοκτησία για επιστροφή null
. Μπορούμε ακόμα να το αποκτήσουμε πρόσβαση από το δικό μας shadow
Αναφορά στο πεδίο εφαρμογής όπου το δημιουργήσαμε.
shadow.querySelector('p');
Αυτό είναι ένα κρίσιμο χαρακτηριστικό ασφάλειας. Με ένα closed
ρίζα σκιάς, μπορούμε να είμαστε σίγουροι ότι οι κακόβουλοι ηθοποιοί δεν μπορούν να εξαγάγουν ιδιωτικά δεδομένα χρήστη από τα εξαρτήματά μας. Για παράδειγμα, εξετάστε ένα widget που δείχνει τραπεζικές πληροφορίες. Ίσως περιέχει τον αριθμό λογαριασμού του χρήστη. Με ένα open
Η σκιά ρίζα, κάθε σενάριο στη σελίδα μπορεί να τρυπήσει στο στοιχείο μας και να αναλύσει το περιεχόμενό της. Σε closed
Λειτουργία, μόνο ο χρήστης μπορεί να εκτελέσει αυτό το είδος δράσης με χειροκίνητη αντιγραφή ή με επιθεώρηση του στοιχείου.
Προτείνω ένα κλειστή πρώτη προσέγγιση Όταν εργάζεστε με το Shadow Dom. Κάντε μια συνήθεια να χρησιμοποιείτε closed
Λειτουργία εκτός εάν είστε εντοπισμός σφαλμάτων, ή μόνο όταν είναι απολύτως απαραίτητο για να περάσετε γύρω από έναν περιορισμό πραγματικού κόσμου που δεν μπορεί να αποφευχθεί. Εάν ακολουθήσετε αυτήν την προσέγγιση, θα διαπιστώσετε ότι οι περιπτώσεις όπου open
Η λειτουργία απαιτείται στην πραγματικότητα λίγα και πολύ μακριά.
Δηλωτική παράσταση
Δεν χρειάζεται να χρησιμοποιήσουμε το JavaScript για να επωφεληθούμε από το Shadow Dom. Η εγγραφή μιας ρίζας σκιάς μπορεί να γίνει δηλωτικά. Φωλιάζοντας α με ένα
shadowrootmode
Το χαρακτηριστικό μέσα σε οποιοδήποτε υποστηριζόμενο στοιχείο θα προκαλέσει την αυτόματη αναβάθμιση αυτού του στοιχείου με ρίζα σκιάς. Η τοποθέτηση μιας ρίζας σκιάς με αυτόν τον τρόπο μπορεί να γίνει ακόμη και με απενεργοποιημένη javascript.
Declarative Shadow DOM content
Και πάλι, αυτό μπορεί να είναι είτε open
ή closed
. Εξετάστε τις επιπτώσεις ασφαλείας πριν χρησιμοποιήσετε open
Λειτουργία, αλλά σημειώστε ότι δεν μπορείτε να έχετε πρόσβαση στο closed
Περιεχόμενο λειτουργίας μέσω οποιωνδήποτε σεναρίων εκτός εάν χρησιμοποιηθεί αυτή η μέθοδος με ένα εγγεγραμμένος Προσαρμοσμένο στοιχείο, σε αυτήν την περίπτωση, μπορείτε να χρησιμοποιήσετε ElementInternals
Για να αποκτήσετε πρόσβαση στην αυτόματα συνδεδεμένη ρίζα σκιάς:
class MyWidget extends HTMLElement {
#internals;
#shadowRoot;
constructor() {
super();
this.#internals = this.attachInternals();
this.#shadowRoot = this.#internals.shadowRoot;
}
connectedCallback() {
const p = this.#shadowRoot.querySelector('p')
console.log(p.textContent); // this works
}
};
customElements.define('my-widget', MyWidget);
export { MyWidget };
Διαμόρφωση σκιάς DOM
Υπάρχουν τρεις άλλες επιλογές εκτός από τρόπος που μπορούμε να περάσουμε Element.attachShadow()
.
Επιλογή 1: clonable:true
Μέχρι πρόσφατα, εάν ένα τυποποιημένο στοιχείο είχε μια ρίζα σκιάς και προσπαθήσατε να το κλωνοποιήσετε χρησιμοποιώντας Node.cloneNode(true)
ή document.importNode(node,true)
θα έχετε μόνο ένα ρηχό αντίγραφο του στοιχείου υποδοχής χωρίς το περιεχόμενο ρίζας σκιάς. Τα παραδείγματα που απλά εξετάσαμε θα επέστρεφαν πραγματικά ένα άδειο
But for a declarative Shadow DOM, this means that each element needs its own template, and they cannot be reused. With this newly-added feature, we can selectively clone components when it’s desirable:
Επιλογή 2: serializable:true
Η ενεργοποίηση αυτής της επιλογής σάς επιτρέπει να αποθηκεύσετε μια αναπαράσταση συμβολοσειρών του περιεχομένου μέσα στη ρίζα της σκιάς ενός στοιχείου. Κλήση Element.getHTML()
Σε ένα στοιχείο υποδοχής θα επιστρέψει ένα αντίγραφο προτύπου της τρέχουσας κατάστασης της σκιάς Dom, συμπεριλαμβανομένων όλων των ένθετων περιπτώσεων του shadowrootserializable
. Αυτό μπορεί να χρησιμοποιηθεί για την έγχυση ενός αντιγράφου της ρίζας της σκιάς σας σε έναν άλλο κεντρικό υπολογιστή ή το cache για μεταγενέστερη χρήση.
Στο Chrome, αυτό στην πραγματικότητα Λειτουργεί με μια κλειστή ρίζα σκιάςοπότε προσέξτε να διαρρέουν τυχαία δεδομένα χρήστη με αυτήν τη λειτουργία. Μια ασφαλέστερη εναλλακτική λύση θα ήταν να χρησιμοποιήσετε ένα closed
περιτύλιγμα για να προστατεύσει τα εσωτερικά περιεχόμενα από εξωτερικές επιρροές, διατηρώντας παράλληλα τα πράγματα open
εσωτερικώς:
`); this.ClonEcontent (); } clonEcontent () {const insed = this#shadow.querySelector ('ενσωματωμένο στοιχείο'); const snapshot = imed.gethtml ({serializableshadowroots: true}); const temp = document.createElement ('div'); temp.sethtmlunsafe (`
Ανακοίνωση setHTMLUnsafe()
. Αυτό συμβαίνει επειδή το περιεχόμενο περιέχει στοιχεία. Αυτή η μέθοδος πρέπει να καλείται κατά την ένεση έμπιστος Περιεχόμενο αυτού του είδους. Εισαγωγή του προτύπου χρησιμοποιώντας
innerHTML
δεν θα ενεργοποιήσει την αυτόματη αρχικοποίηση σε μια ρίζα σκιάς.
Επιλογή 3: delegatesFocus:true
Αυτή η επιλογή κάνει ουσιαστικά το στοιχείο υποδοχής μας να λειτουργεί ως για το εσωτερικό περιεχόμενό του. Όταν είναι ενεργοποιημένη, κάνοντας κλικ οπουδήποτε στον κεντρικό υπολογιστή ή την κλήση
.focus()
Σε αυτό θα μετακινήσει το δρομέα στο πρώτο εστιασμένο στοιχείο στη ρίζα της σκιάς. Αυτό θα εφαρμόσει επίσης το :focus
ψευδο-κατηγορία στον κεντρικό υπολογιστή, ο οποίος είναι ιδιαίτερα χρήσιμος κατά τη δημιουργία στοιχείων που προορίζονται να συμμετάσχουν σε μορφές.
Αυτό το παράδειγμα δείχνει μόνο την αντιπροσωπεία εστίασης. Ένα από τα περίεργα της εγκλεισμού είναι ότι οι υποβολές μορφής δεν είναι αυτόματα συνδεδεμένες. Αυτό σημαίνει ότι η τιμή μιας εισόδου δεν θα είναι στην υποβολή έντυπου από προεπιλογή. Επικύρωση της φόρμας και τα κράτη δεν κοινοποιούνται από τη σκιά DOM. Υπάρχουν παρόμοια προβλήματα συνδεσιμότητας με την προσβασιμότητα, όπου το όριο της ρίζας σκιών μπορεί να παρεμβαίνει στην ARIA. Αυτές είναι όλες οι σκέψεις ειδικά για τα έντυπα με τα οποία μπορούμε να αντιμετωπίσουμε ElementInternals
το οποίο είναι ένα θέμα για ένα άλλο άρθρο και είναι να αναρωτηθεί αν μπορείτε να βασιστείτε σε μια ελαφριά μορφή DOM.
Περιεχόμενο με σχισμές
Μέχρι στιγμής, εξετάσαμε μόνο τα πλήρως ενθυλακωμένα εξαρτήματα. Χρησιμοποιείται μια βασική λειτουργία Dom Doma κουλοχέρηδες Για να εισάγετε επιλεκτικά περιεχόμενο στην εσωτερική δομή του στοιχείου. Κάθε ρίζα σκιάς μπορεί να έχει ένα αθέτηση (ανώνυμος)
; Όλοι οι άλλοι πρέπει να είναι ονομάστηκε. Η ονομασία μιας υποδοχής μας επιτρέπει να παρέχουμε περιεχόμενο για να γεμίσουμε συγκεκριμένα τμήματα του στοιχείου μας καθώς και περιεχομένου για την κάλυψη για να γεμίσουμε τυχόν υποδοχές που παραλείπονται από τον χρήστη:
Fallback Title
A placeholder description.
A Slotted Title
An example of using slots to fill parts of a component.
Foo
Bar
Baz
Οι προεπιλεγμένες υποδοχές υποστηρίζουν επίσης το περιεχόμενο του Fallback, αλλά οι αδέσποτοι κόμβοι κειμένου θα τους γεμίσουν. Ως αποτέλεσμα, αυτό λειτουργεί μόνο εάν καταρρεύσετε όλα τα κενά στο σήμα του στοιχείου υποδοχής:
Fallback Content
Εκπέμπουν στοιχεία υποδοχής slotchange
γεγονότα όταν τους assignedNodes()
προστίθενται ή αφαιρούνται. Αυτά τα γεγονότα δεν περιέχουν αναφορά στην υποδοχή ή στους κόμβους, οπότε θα χρειαστεί να μεταβιβάσετε αυτά στο χειριστή συμβάντων σας:
class SlottedWidget extends HTMLElement {
#internals;
#shadow;
constructor() {
super();
this.#internals = this.attachInternals();
this.#shadow = this.#internals.shadowRoot;
this.configureSlots();
}
configureSlots() {
const slots = this.#shadow.querySelectorAll('slot');
console.log({ slots });
slots.forEach(slot => {
slot.addEventListener('slotchange', () => {
console.log({
changedSlot: slot.name || 'default',
assignedNodes: slot.assignedNodes()
});
});
});
}
}
customElements.define('slotted-widget', SlottedWidget);
Πολλαπλά στοιχεία μπορούν να αντιστοιχιστούν σε μια ενιαία υποδοχή, είτε δηλωτικά με το slot
Χαρακτηριστικό ή μέσω δέσμης ενεργειών:
const widget = document.querySelector('slotted-widget');
const added = document.createElement('p');
added.textContent="A secondary paragraph added using a named slot.";
added.slot="description";
widget.append(added);
Παρατηρήστε ότι η παράγραφος σε αυτό το παράδειγμα επισυνάπτεται στο πλήθος στοιχείο. Το περιεχόμενο με σχισμές ανήκει πραγματικά στο "φως" DOM, όχι στο σκιώδες dom. Σε αντίθεση με τα παραδείγματα που καλύψαμε μέχρι στιγμής, αυτά τα στοιχεία μπορούν να ερωτηθούν απευθείας από το document
αντικείμενο:
const widgetTitle = document.querySelector('my-widget (slot=title)');
widgetTitle.textContent="A Different Title";
Εάν θέλετε να έχετε πρόσβαση σε αυτά τα στοιχεία εσωτερικά από τον ορισμό της τάξης σας, χρησιμοποιήστε this.children
ή this.querySelector
. Μόνο το
Τα ίδια τα στοιχεία μπορούν να ερωτηθούν μέσω της σκιάς Dom, όχι του περιεχομένου τους.
Από το μυστήριο έως την κυριαρχία
Τώρα ξέρετε Γιατί θα θέλατε να χρησιμοποιήσετε το Shadow Dom, όταν Θα πρέπει να το ενσωματώσετε στη δουλειά σας και πως Μπορείτε να το χρησιμοποιήσετε τώρα.
Αλλά το ταξίδι του ιστού σας δεν μπορεί να τελειώσει εδώ. Έχουμε καλύψει μόνο τη σήμανση και τη δέσμη ενεργειών σε αυτό το άρθρο. Δεν έχουμε καν αγγίξει μια άλλη σημαντική πτυχή των στοιχείων του ιστού: Ενθυλάκωση στυλ. Αυτό θα είναι το θέμα μας σε ένα άλλο άρθρο.

(GG, YK)