Как проксировать пользовательский элемент (веб-компонент)

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.


person Артур Лаврищев    schedule 08.04.2017    source источник


Ответы (1)


Вы можете проксифицировать класс или экземпляр настраиваемого элемента.

Учитывая следующее определение настраиваемого элемента:

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>

Прокси для класса настраиваемых элементов

Определите ловушку 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>

Получите прокси-сервер экземпляра настраиваемого элемента из прокси-класса

Если вы хотите создать экземпляр настраиваемого элемента и напрямую получить один прокси-объект, вы можете объединить оба решения, описанные выше.

В следующем примере показано, как получить прокси для элемента <a-element>, который будет регистрировать в консоли каждый доступ к свойству. Ловушка construct(), определенная в классе Proxy, возвращает себе прокси для созданного экземпляра Custom Element.

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 )

person Supersharp    schedule 09.04.2017
comment
Мне нужно инкапсулировать логику прокси в суперклассе. Вроде: function P (_class) { return new Proxy (new class extends _class {}, {}) } class A extends P(HTMLElement) {} customElements.define( 'a-element', A ) Но тоже не работает - person Артур Лаврищев; 11.04.2017
comment
@ АртурЛаврищев используйте вместо function P (_class) { return new Proxy (class extends _class {}, {}) } (без new перед class) - person Supersharp; 11.04.2017
comment
@ АртурЛаврищев спасибо за принятый ответ, можете проголосовать, если это помогло :-) - person Supersharp; 14.04.2017
comment
Большое вам спасибо за этот ответ. Это зажгло лампочку в моей голове - существует так много проблем с кодом, с которыми я боролся в течение нескольких месяцев, которые можно было бы просто элегантно решить с помощью этих методов ... - person diopside; 16.07.2018
comment
@diopside Просто любопытно, какие проблемы с кодом вы хотите решить с помощью этих методов прокси? - person trusktr; 30.11.2019
comment
@Supersharp Я полагаю, что этот подход с использованием прокси-конструктора может быть абстрагирован в декоратор (устаревшие декораторы в TypeScript или новые, когда они будут выпущены). Wdyt? - person trusktr; 01.12.2019