如何代理自定义元素(Web 组件)

How to Proxy Custom Element (Web Component)

class A extends HTMLElement {
  constructor() {
    super()
    return new Proxy(this, {})
  }
}

window.customElements.define('a-element', A)
<a-element></a-element>

如何代理自定义元素?

当我尝试时:

Uncaught InvalidStateError: custom element constructors must call super() first and must not return a different object.

您可以代理自定义元素的 class 实例

给定以下自定义元素定义:

class A extends HTMLElement {
  constructor() {
    super()
  }
  connectedCallback() {
    this.innerHTML = 'Hello'    
  }
}
customElements.define( 'a-element', A )

自定义元素实例的代理

从实例引用创建代理(此处:ae):

<a-element id="ae"></a-element>
<script>
  var b1 = new Proxy( ae, {
    get ( target, value ) { return target[value] }       
  } )
  console.log( b1.innerHTML ) // => "Hello"
</script>

自定义元素的代理 class

定义 construct 陷阱以捕获 new 运算符:

<script>
  var B = new Proxy( A, {
    construct() { return new A }
  } )
  var b2 = new B
  document.body.appendChild( b2 )
  console.log( b2.innerHTML ) // => "Hello"
</script>

从 class 代理

获取自定义元素实例代理

如果想实例化一个Custom Element,直接获取一个Proxy对象,可以结合以上两种方案。

以下示例显示如何为元素 <a-element> 获取代理,该代理将在每次 属性 访问时登录控制台。在 class 代理中定义的 construct() 陷阱 returns 本身就是实例化自定义元素的代理。

class A extends HTMLElement {
  constructor() {
    super()
  }
  connectedCallback() {
    this.innerHTML = 'Hello'    
  }
}
customElements.define( 'a-element', A )  

var P = new Proxy( A, {
  construct () { 
    return new Proxy ( new A, {
      get ( target, value ) { 
        if ( value == 'element' ) 
          return target
        console.info( `proxy: property ${value} for <${target.localName}> is "${target[value]}"` )
        return target[value]
      }       
    } )
  }
} )
var p = new P
document.body.appendChild( p.element )
console.log( p.innerHTML )