Les éléments personnalisés vous permettent de créer vos propres balises HTML. Cette liste de contrôle couvre les meilleures pratiques pour vous aider à créer des éléments de haute qualité.
Les éléments personnalisés vous permettent d'étendre le code HTML et de définir vos propres balises. Il s'agit d'un
incroyablement puissante, mais elles sont aussi de bas niveau, ce qui signifie qu'il ne s'agit pas
toujours déterminer la meilleure façon
de mettre en œuvre votre propre élément.
Pour vous aider à créer la meilleure expérience possible, nous avons mis au point cette
liste de contrôle. Il décrit toutes les choses
qui, selon nous, sont nécessaires pour être
est un élément personnalisé
qui se comporte bien.
Checklist
Shadow DOM
Créez une racine fantôme pour encapsuler les styles. |
Why? |
L'encapsulation des styles dans la racine fantôme de votre élément garantit qu'il fonctionnera
quel que soit l'endroit où elles sont utilisées. C'est particulièrement important si un développeur
souhaite placer votre élément à l’intérieur de la racine de l’ombre d’un autre élément. Ce
s'applique même aux éléments simples
comme une case à cocher ou une case d'option. Il peut s'agir
le seul contenu à l'intérieur de votre racine fantôme sera les styles
eux-mêmes.
|
Exemple |
Le
<howto-checkbox> .
|
Créez la racine fantôme dans le constructeur.
|
Why? |
On parle de constructeur lorsque vous avez une connaissance exclusive de votre élément.
C'est le moment idéal pour définir les détails de l'implémentation que vous ne souhaitez pas que d'autres
avec d'autres éléments. Cette opération est effectuée dans un rappel ultérieur, par exemple
connectedCallback , signifie que vous devez vous protéger
situations où votre élément est détaché, puis réassocié au document.
|
Exemple |
Le
<howto-checkbox> .
|
Placez tous les enfants créés par l'élément dans sa racine fantôme.
|
Why? |
Les enfants créés par votre élément font partie de son implémentation et doivent être
privé. Sans la protection d'une racine fantôme, le code JavaScript externe peut
interférer par inadvertance avec ces enfants.
|
Exemple |
Le
<howto-tabs> .
|
Utiliser <slot> pour projeter les enfants du Light DOM dans votre Shadow DOM
|
Why? |
Autorisez les utilisateurs de votre composant à spécifier du contenu dans votre composant, car les éléments enfants HTML rendent votre composant plus composable. Lorsqu'un navigateur n'accepte pas les éléments personnalisés, le contenu imbriqué reste disponible, visible et accessible.
|
Exemple |
Le
<howto-tabs> .
|
Définissez un style d'affichage :host (par exemple, block ,
inline-block , flex ), sauf si vous préférez la valeur par défaut
inline
|
Why? |
Les éléments personnalisés étant display: inline par défaut, vous devez définir leur
width ou height n'auront aucun effet. Souvent
surprend les développeurs et peut causer des problèmes liés à
la mise en page. À moins que vous ne préfériez un écran inline , vous
doit toujours définir une valeur display par défaut.
|
Exemple |
Le
<howto-checkbox> .
|
Ajoutez un style d'affichage :host qui respecte l'attribut masqué.
|
Why? |
Un élément personnalisé avec un style display par défaut (par exemple,
:host { display: block } , remplacera la valeur de précision inférieure
intégré
<ph type="x-smartling-placeholder"></ph>
hidden .
Vous serez peut-être surpris si vous pensez définir les hidden
sur votre élément pour l'afficher display: none . De plus,
à un style display par défaut, ajoutez la prise en charge de hidden
avec :host([hidden]) { display: none } .
|
Exemple |
Le
<howto-checkbox> .
|
Attributs et propriétés
Ne remplacez pas les attributs globaux définis par l'auteur.
|
Why? |
Les attributs globaux sont ceux qui sont présents dans tous les éléments HTML. Un peu
par exemple tabindex et role . Un élément personnalisé
nous vous conseillons de définir son tabindex initial sur 0 pour que ce soit le cas
sélectionnables. Mais vous devez toujours vérifier
d'abord si le développeur qui utilise
votre élément l'a défini sur une autre valeur. Si, par exemple, il a défini
tabindex à -1, cela indique qu'ils ne souhaitent pas que la
pour qu'il soit interactif.
|
Exemple |
Le
<howto-checkbox> . Pour en savoir plus, consultez
Ne remplacez pas l'auteur de la page.
|
Toujours accepter les données primitives (chaînes, nombres, valeurs booléennes) en tant qu'attributs
ou propriétés.
|
Why? |
Les éléments personnalisés, comme leurs homologues intégrés, doivent être configurables.
La configuration peut être transmise de manière déclarative, via des attributs ou de manière impérative
via des propriétés JavaScript. Idéalement, chaque attribut
doit également être lié à
une propriété correspondante.
|
Exemple |
Le
<howto-checkbox> .
|
Efforcez-vous de synchroniser les attributs et les propriétés des données primitifs,
à l'attribut, et inversement.
|
Why? |
Vous ne savez jamais comment un utilisateur interagira avec votre élément. Il pourrait
définir une propriété en JavaScript, puis s'attendre à lire cette valeur
à l'aide d'une API comme getAttribute() . Si chaque attribut a une valeur
la propriété correspondante, et que ces deux éléments reflètent,
pour que les utilisateurs
travaillent avec votre élément. Autrement dit, appeler
setAttribute('foo', value) doit également définir une valeur
foo , et inversement. Il existe, bien sûr, des exceptions
cette règle. Vous ne devez pas refléter les propriétés de fréquence élevée, comme
currentTime dans un lecteur vidéo. Faites appel à votre bon sens. Si
semble qu'un utilisateur interagira avec une propriété ou un attribut ;
qu'il n'est pas gênant de la
réfléchir, alors faites-le.
|
Exemple |
Le
<howto-checkbox> . Pour en savoir plus, consultez
Évitez les problèmes de réentrée.
|
Essayez de n'accepter que les données enrichies (objets, tableaux) en tant que propriétés.
|
Why? |
De manière générale, il n'existe aucun exemple d'élément HTML intégré qui
acceptent des données enrichies (tableaux et objets JavaScript simples) via leur
. Les données enrichies sont acceptées
par le biais d'appels de méthode ou
propriétés. L'acceptation des données enrichies en tant que source de données
: la sérialisation d'un objet volumineux en chaîne peut s'avérer coûteuse.
toutes les références d'objets seront perdues
lors de ce processus de concaténation. Pour
exemple, si vous chaînez un objet qui fait référence à un autre objet,
ou un nœud DOM, ces références seront perdues.
|
Ne pas refléter les propriétés des données enrichies dans les attributs.
|
Why? |
La réplication des propriétés de données enrichies dans des attributs est inutilement coûteuse.
nécessitant la sérialisation et la désérialisation
des mêmes objets JavaScript. À moins que
vous avez un cas d'utilisation qui ne peut être résolu qu'avec cette fonctionnalité,
de l'éviter.
|
Pensez à vérifier les propriétés qui ont pu être définies avant l'élément
mises à niveau.
|
Why? |
Un développeur qui utilise votre élément peut tenter d'en définir une propriété.
avant le chargement de sa définition. Cela est particulièrement vrai si
le développeur utilise un framework qui gère le chargement des composants, leur estampe
à la page et lier leurs propriétés à un modèle.
|
Exemple |
Le
<howto-checkbox> . Pour en savoir plus, consultez
Rendre les propriétés différées.
|
N'appliquez pas vous-même les cours.
|
Why? |
Les éléments qui doivent exprimer leur état doivent le faire à l'aide d'attributs. La
L'attribut class est généralement considéré comme appartenant au
développeur utilisant votre élément. Si vous l'écrivez vous-même, vous risquez
piétiner les classes de développeurs.
|
Événements
Distribuer des événements en réponse à l'activité des composants internes
|
Why? |
Le composant peut avoir des propriétés qui changent en réponse à une activité qui
seul votre composant est informé, par exemple, si un minuteur ou une animation
ou le chargement d'une ressource est terminé. Il est utile d'envoyer des événements
en réponse à ces modifications pour avertir l'hôte que l'état du composant est
différentes.
|
Ne envoyez pas d'événements en réponse à la définition d'une propriété au niveau de l'hôte (vers le bas
flux de données).
|
Why? |
Il n'est plus nécessaire d'envoyer un événement en réponse à un paramètre d'hôte.
(l'hôte connaît l'état actuel car il vient de le définir). Événements de distribution
En réponse à un paramètre d'hôte, une propriété peut provoquer des boucles infinies avec les données
des systèmes de liaison.
|
Exemple |
Le
<howto-checkbox> .
|
Vidéo explicative
Ne pas remplacer l'auteur de la page
Il est possible qu'un développeur utilisant votre élément veuille remplacer certaines
son état initial. Par exemple, si vous modifiez son role
ARIA ou sa mise au point avec
tabindex
Vérifiez si ces attributs et d'autres attributs globaux ont été définis.
avant d'appliquer vos propres valeurs.
connectedCallback() {
if (!this.hasAttribute('role'))
this.setAttribute('role', 'checkbox');
if (!this.hasAttribute('tabindex'))
this.setAttribute('tabindex', 0);
Rendre les propriétés inactives
Un développeur peut tenter de définir une propriété sur votre élément avant ses
a été chargée. Cela est particulièrement vrai si le développeur utilise
qui gère le chargement des composants, les insère dans la page et
de lier leurs propriétés à un modèle.
Dans l'exemple suivant, Angular lie de manière déclarative les
isChecked
à la propriété checked
de la case à cocher. Si la définition de
Howto-box a été chargé en différé. Il est possible qu'Angular tente de définir
la propriété cochée avant la mise à jour de l'élément.
<howto-checkbox [checked]="defaults.isChecked"></howto-checkbox>
Un élément personnalisé doit gérer ce scénario en vérifiant si des propriétés ont des
déjà défini sur son instance. <howto-checkbox>
illustre ce modèle à l'aide d'une méthode appelée _upgradeProperty()
.
connectedCallback() {
...
this._upgradeProperty('checked');
}
_upgradeProperty(prop) {
if (this.hasOwnProperty(prop)) {
let value = this[prop];
delete this[prop];
this[prop] = value;
}
}
_upgradeProperty()
capture la valeur de l'instance non mise à niveau et supprime
la propriété afin qu'elle n'occulte pas le setter de la propriété de l'élément personnalisé.
Ainsi, lorsque le chargement de la définition de l'élément est terminé, il peut immédiatement
reflètent l'état correct.
Éviter les problèmes de réentrée
Il est tentant d'utiliser attributeChangedCallback()
pour refléter l'état dans une
sous-jacente. Exemple:
// When the [checked] attribute changes, set the checked property to match.
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'checked')
this.checked = newValue;
}
Mais cela peut créer une boucle infinie si le setter de la propriété reflète également
l'attribut.
set checked(value) {
const isChecked = Boolean(value);
if (isChecked)
// OOPS! This will cause an infinite loop because it triggers the
// attributeChangedCallback() which then sets this property again.
this.setAttribute('checked', '');
else
this.removeAttribute('checked');
}
Une alternative consiste à autoriser le setter de propriété à refléter l'attribut, et
pour que le getter détermine sa valeur en fonction de l'attribut.
set checked(value) {
const isChecked = Boolean(value);
if (isChecked)
this.setAttribute('checked', '');
else
this.removeAttribute('checked');
}
get checked() {
return this.hasAttribute('checked');
}
Dans cet exemple, l'ajout ou la suppression de l'attribut définit également la propriété.
Enfin, attributeChangedCallback()
peut être utilisé pour gérer les effets secondaires.
comme l'application d'états ARIA.
attributeChangedCallback(name, oldValue, newValue) {
const hasValue = newValue !== null;
switch (name) {
case 'checked':
// Note the attributeChangedCallback is only handling the *side effects*
// of setting the attribute.
this.setAttribute('aria-checked', hasValue);
break;
...
}
}