是否可以在不使用类的情况下创建Web组件?

问题描述 投票:0回答:1

如果 JavaScript 中的所有内容都来自原型,我想有某种方法可以在不使用类的情况下创建 Web 组件。我从来没有找到任何关于它的文章,我不知道这是因为这是一个不好的做法还是因为它不可能。

javascript web-component
1个回答
0
投票

是的,无需使用

class
语法即可完成。诀窍是使用
Reflect.construct
来代替对
super
的调用。这是一个小示例片段,包含一个工厂 (
createCustomElementFactory
),用于创建使用
customElements.define
注册自定义元素所需的“类”。

要使用代码,请分叉此 Stackblitz 项目

const myCustomElementCreator = createCustomElementFactory();
const connectedCallback = function() {
  const isCustom = this.getAttribute(`is`);

  if (!isCustom) {
    this.style.display = `block`;
    this.style.padding = `2px 5px`;
    this.style.border = `1px solid #999`;
  }

  this.insertAdjacentHTML(`afterbegin`, `<div>I am <i>&lt;${
    this.tagName.toLowerCase()}${
      isCustom ? ` is="${isCustom}"` : ``}></i></div>`);

  console.log(`We just connected the ${
    isCustom ? `custom` : `autonomous`} element '${
      this.tagName.toLowerCase()}${isCustom ? `[is="${isCustom}"]` : ``}'`);
};
const myBrandNewElemClass = myCustomElementCreator({ connectedCallback } );
const myBrandNewParagraphClass = myCustomElementCreator({
  connectedCallback,
  forElem: HTMLParagraphElement }); 

// register 2 elements
customElements.define( "my-brand-new-element", myBrandNewElemClass );

customElements.define( 
  "my-brand-new-paragraph", 
  myBrandNewParagraphClass,
  { extends: `p` } );

document.body.insertAdjacentHTML(
  `beforeend`, 
  `<my-brand-new-element>Hello world!</my-brand-new-element>`
);
document.body.insertAdjacentHTML(
  `beforeend`, 
  `<p is="my-brand-new-paragraph">Hello paragraph!</p>`
);

function createCustomElementFactory() {
  const paramsPlaceholder = ({
    get all() {
      return {
        connectedCallback, 
        disconnectedCallback, 
        adoptedCallback, 
        attributeChangedCallback,
        observedAttributes, 
        forElem } = {}
    }
  });

  function CustomElementConstructorFactory(params = paramsPlaceholder.all) {
    const elemProto = params.forElem?.prototype instanceof HTMLElement 
      ? params.forElem : HTMLElement;
      
    function CustomElementConstructor() {
      if (elemProto !== HTMLElement) {
        self = Reflect.construct( params.forElem, [], CustomElementConstructor );
        return self;
      }

      return Reflect.construct( HTMLElement, [], CustomElementConstructor );
    }

    CustomElementConstructor.prototype = elemProto.prototype;
    CustomElementConstructor.observedAttributes = params.observedAttributes;

    Object.entries( params ).forEach( ([name, cb]) => { 
      if (cb && cb instanceof Function) { 
        CustomElementConstructor.prototype[name] = cb; } 
      } );

    return CustomElementConstructor;
  }

  return (params = paramsPlaceholder.all) => CustomElementConstructorFactory(params);
  }

© www.soinside.com 2019 - 2024. All rights reserved.