Пользовательские элементы с прокси имеет, получить и установить - PullRequest
0 голосов
/ 07 июня 2019

Моя цель - создать класс ObservableElement, расширяющий HTMLElement, чтобы его можно было использовать для определения пользовательских элементов, например:

customElements.define('an-observable-elem', class extends ObservableElement {
  construct() {
    super()
    ...
  }
  ...
})

Особенность любого элемента, основанного на ObservableElement, заключается в том, что он должен иметь определенные особенности поведения по отношению к свойствам.

Во-первых, 'whatever' in myElem должно всегда быть верным. Другими словами, для экземпляра has я бы хотел ловушку для прокси, которая всегда всегда возвращает true.

Во-вторых, установка и получение любого реквизита должны работать. Но всякий раз, когда устанавливается опора, которая явно не определена в элементе или в цепочке прототипов, я хочу создать пользовательское событие с именем set${propname} и detail: theValue.

Кажется, должен быть способ использования es6-прокси. Наивно я впервые попробовал:

class ObservableElement extends HTMLElement {
  constructor () {
    super()
    const vals = {}
    return Proxy(this, {
      has: _ => true,
      get: name => {
        if (name in this) return this[name]
        if (name in vals) return vals[name]
        return null
      },
      set: (name, value) => {
        if (name in this) {
          this[name] = value
          return
        }
        if (vals[name] === value) return
        vals[name] = value
        this.dispatchEvent(new CustomEvent(`set${name}`, {detail: value}))
      }
    })
  }
}

Но, конечно, это не сработало. Возвращение прокси из конструктора не изменило значение this в конструкторах расширенных классов. Я возился со всевозможными комбинациями проксирования construct в классе, Object.setPrototypeOf(...) и т. Д. Безрезультатно.

Я был бы очень признателен, если бы любой, кто понимает, как эти вещи могут сочетаться друг с другом для достижения того, чего я хочу, объяснил бы мне это. Спасибо!

1 Ответ

0 голосов
/ 16 июня 2019

То, что вы пытаетесь сделать, не поддерживается спецификацией веб-компонентов W3C.

В соответствии с п. 2.4 спецификации веб-компонентов W3C, шаг 10.6.2 :

Если observedAttributesIterable не равно undefined, тогда установите observedAttributes в результате преобразования observedAttributesIterable в sequence<DOMString>. Отбросьте все исключения из преобразования.

Это происходит во время выполнения customElements.define(), что означает, что вам нужно определить итерацию для каждой мыслимой строки, когда класс определен, чтобы перехватывать все изменения атрибутов.

Если компонент не находит измененное свойство в этой последовательности, он не вызывает attributeChangedCallback().

Точно так же невозможно вернуть прокси из constructor из-за ограничения в §2.2 :

Оператор return не должен появляться где-либо внутри тела конструктора, если только он не является простым ранним возвратом (return или return this).

...