J'ai un HTMLElement personnalisé qui fonctionne comme prévu, mais je ne trouve pas de moyen de transmettre des arguments au constructeur; à la place, j'accède en passant les valeurs dans ma balise personnalisée, mais je dois ensuite définir les valeurs dans connectedCallback ()
, ce dont je ne suis pas satisfait.
Voici une version de base de ce qui Je fais maintenant:
$(document).ready(function(){ const tracking_preview = document.createElement('tracking-preview','{{video_id}}'); tracking_preview.videoId = '{{video_id}}'; document.body.append(tracking_preview); });
Je préfère passer le videoId directement au constructeur, quelque chose comme ça (qui ne fonctionne PAS):
JS:
class TrackingPreview extends HTMLElement { constructor(videoId) { super(); const video = document.createElement('video'); video.setAttribute('id', videoId); video.setAttribute('controls', ''); video.setAttribute('width', '1920'); video.setAttribute('height', '1080'); shadow.appendChild(video); } connectedCallback() { } }
Script JS sur une page HTML:
class TrackingPreview extends HTMLElement { constructor() { super(); const video = document.createElement('video'); video.setAttribute('controls', ''); video.setAttribute('width', '1920'); video.setAttribute('height', '1080'); shadow.appendChild(video); this.video = video; } connectedCallback() { const videoId = this.getAttribute('video-id'); this.video.id = videoId; } }
Existe-t-il un moyen de transmettre des valeurs à un constructeur personnalisé? Les documents impliquent que c'est possible mais ne sont pas très utiles pour savoir comment procéder.
3 Réponses :
Vous pouvez le faire avec le nouveau
mot-clé:
const tacking_preview = new TrackingPreview( id )
notez que vous ne pouvez pas définir d'attributs dans le constructeur d'élément personnalisé
Les règles d'un constructeur pour un composant Web sont assez strictes. Une règle est que vous n'êtes pas autorisé à transmettre des arguments au constructeur.
https://w3c.github.io/webcomponents/spec/custom/#custom-element-conformance
Utilisez plutôt à la fois une propriété et un attribut
<tracking-preview videoid="10"></tracking-preview>
class TrackingPreview extends HTMLElement { static get observedAttributes() { return ['videoid']; } constructor() { super(); const video = document.createElement('video'); video.setAttribute('controls', ''); video.width = 192; video.height = 108; this.video = video; this.attachShadow({mode: 'open'}).appendChild(video); } attributeChangedCallback(attrName, oldVal, newVal) { if (oldVal !== newVal) { // Since we only watch videoid there is no need to check attrName this.video.setAttribute('id', newVal); } } get videoId() { return this.video.getAttribute('id'); } set videoId(val) { if (val == null) { // check for null and undefined this.removeAttribute('videoid'); } else { this.setAttribute('videoid', val); } } } customElements.define('tracking-preview', TrackingPreview); setTimeout(function() { let el = document.querySelector('tracking-preview'); if (el) { console.log(el.videoId); el.videoId = 99; console.log(el.videoId); } }, 500);
Lorsque vous attribuez videoid
est défini, la fonction attributeChangedCallback
est appelée et vous transmettez la valeur à votre élément video
.
Dans ma fonction timeout, je lis et j'écris à la fois la propriété videoId
qui lit et écrit l'attribut videoid
.
Souvenez-vous qu'aucun des éléments HTML normaux n'est livré avec des arguments de constructeur: ne vous fiez pas à eux. Au lieu de cela, comptez sur les attributs, avec le support de propriété JS, et connectez-les conformément au spécification des éléments personnalisés .
Donc, de la même manière que vous auriez le code suivant pour une Image
:
class TrackingPreview extends HTMLElement { static get observedAttributes() { return [`width`, `height`]; } constructor() { super(); const shadow = this.attachShadow({mode: 'open'}); const video = this.video = document.createElement('video'); video.setAttribute(`controls`, `controls`); video.setAttribute(`width`, this.getAttribute(`width`) || 1920); video.setAttribute(`height`, this.getAttribute(`height`) || 1080); shadow.appendChild(video); } get width() { return this.video.width; } set width(val) { this.setAttribute(`width`, val); } get height() { return this.video.height; } set height(val) { this.setAttribuite(`height`, val); } attributeChangedCallback(name, oldValue, newValue) { if (name === `width`) { this.video.width = newValue; } if (name === `height`) { this.video.height = newValue; } // ... } // ... }
ou un élément de script:
<track-preview width="100" height="200" ...></track-preview>
votre composant ne devrait pas avoir besoin de propriétés de constructeur. Vous l'utiliseriez comme ceci:
let preview = TrackingPreview(); preview.width = 1920; preview.height = 1080;
ou sous forme HTML,
let script = document.createElement("script"); script.src = ... // or script.textContent = ...
Et faites réagir votre élément personnalisé ces propriétés sont définies:
let img = new Image(); img.src = "https://example.com/someimage.jpg"; img.width = ... ...