【问题标题】:Passing values to constructor of custom HTMLElement将值传递给自定义 HTMLElement 的构造函数
【发布时间】:2019-08-30 02:23:07
【问题描述】:

我有一个按预期工作的自定义 HTMLElement,但我找不到将参数传递给构造函数的方法;相反,我正在访问传递自定义标记中的值,但随后我必须在 connectedCallback() 中设置值,我对此并不满意。

这是我现在正在做的一个基本版本:

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;
  }
}

我宁愿将 videoId 直接传递给构造函数,就像这样(不起作用):

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() {
  }
}

HTML 页面上的 JS 脚本:

  $(document).ready(function(){
    const tracking_preview = document.createElement('tracking-preview','{{video_id}}');
    tracking_preview.videoId = '{{video_id}}';
    document.body.append(tracking_preview);
  });

有没有办法将值传递给自定义构造函数?文档暗示这是可能的,但对如何做到这一点没有太大帮助。

【问题讨论】:

    标签: javascript html django custom-element


    【解决方案1】:

    Web 组件的构造函数规则非常严格。一条规则是不允许将任何参数传递给构造函数。

    https://w3c.github.io/webcomponents/spec/custom/#custom-element-conformance

    同时使用属性和属性

    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);
    <tracking-preview videoid="10"></tracking-preview>

    当您设置videoid 属性时,将调用attributeChangedCallback 函数并将值传递给您的video 元素。

    在我的超时函数中,我同时读取和写入 videoId 属性,该属性读取和写入 videoid 属性。

    【讨论】:

      【解决方案2】:

      请记住,常规的 HTML 元素都没有带有构造函数参数:不要依赖它们。取而代之的是,依赖于带有 JS 属性支持的属性,并根据 custom elements spec 将它们连接起来。

      因此,就像您必须为Image 编写以下代码一样:

      let img = new Image();
      img.src = "https://example.com/someimage.jpg";
      img.width = ...
      ...
      

      或脚本元素:

      let script = document.createElement("script");
      script.src = ...
      // or script.textContent = ...
      

      您的组件不应该需要构造函数属性。你可以这样使用它:

      let preview = TrackingPreview();
      preview.width = 1920;
      preview.height = 1080;
      

      或 HTML 格式,

      <track-preview width="100" height="200" ...></track-preview>
      

      并让您的自定义元素对设置的这些属性做出反应:

      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;
          }
          // ...
        }
      
        // ...
      }
      

      【讨论】:

        【解决方案3】:

        您可以使用 new 关键字来做到这一点:

        const tacking_preview = new TrackingPreview( id )
        

        【讨论】:

        • 注意不能在自定义元素构造函数中设置属性
        猜你喜欢
        • 2012-12-06
        • 1970-01-01
        • 1970-01-01
        • 2018-05-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-14
        相关资源
        最近更新 更多