4
votes

Passer des valeurs au constructeur de HTMLElement personnalisé

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.


0 commentaires

3 Réponses :


0
votes

Vous pouvez le faire avec le nouveau mot-clé:

const tacking_preview = new TrackingPreview( id )


1 commentaires

notez que vous ne pouvez pas définir d'attributs dans le constructeur d'élément personnalisé



3
votes

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 .


0 commentaires

1
votes

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 = ...
...


0 commentaires