В чем смысл синтаксиса "есть" при расширении элементов в веб-компонентах?

В веб-компонентах для регистрации элемента, который вы просто вводите:

var XFoo = document.registerElement('x-foo', {
  prototype: Object.create(HTMLElement.prototype)
});

Чтобы создать элемент, вы можете сделать одно из следующих:

<x-foo></x-foo>

var xFoo = new XFoo();
document.body.appendChild(xFoo);

var xFoo = document.createElement( 'x-foo')
document.body.appendChild(xFoo);

Это все прекрасно и денди. Проблемы возникают, когда вы говорите о расширении существующих элементов.

var XFooButton = document.registerElement('x-foo-button', {
  prototype: Object.create(HTMLButtonElement.prototype),
  extends: 'button'
});

Вопрос 1: Почему дублирование? Здесь 'button' должно быть достаточно (тем более, что достаточно легко проработать прототип элемента с помощью Object.getPrototypeOf(document.createElement(tag));

Вопрос 2: как эта информация используется внутри страны? Что произойдет, если вы, например, имеете prototype: Object.create(HTMLFormElement.prototype и extends: 'button' (где то, что после extends не соответствует прототипу)

Чтобы создать один, вы можете сделать одно из следующих действий:

<button is="x-foo-button"></button>

var xFooButton = new XFooButton();
document.body.appendChild(xFoo);

var xFooButton = document.createElement('button', 'x-foo-button');
document.body.appendChild(xFooButton);

Вопрос 3: поскольку ясно, что x-foo-button extends button, почему мы должны указать их оба при использовании document.createElement()? Я подозреваю, что поскольку document.createElement() просто создает тег с синтаксисом <button is="x-foo-button"></button>, что приводит меня к следующему вопросу:

Вопрос 4: Какая точка синтаксиса is? Какова фактическая разница между этим:

var XFooButton = document.registerElement('x-foo-button', {
  prototype: Object.create(HTMLButtonElement.prototype),
  extends: 'button'
});

И это:

var XFooButton = document.registerElement('x-foo-button', {
  prototype: Object.create(HTMLButtonElement.prototype),
});

За исключением 1) Первый синтаксис понадобится <button is="x-foo-button"></button> для создания экземпляра в документе 2). Второй синтаксис может использоваться для любого элемента, а не только для расширения пользовательских?

Ответы

Ответ 1

Ответ 1 Очевидное дублирование состоит в том, что ваш пример очень прост. В реальной виртуальной жизни вы предоставили бы другой прототип registerElement.

Пример с пользовательской кнопкой, которая будет отображать всплывающее окно при нажатии:

//Custom method
function callback ()
{
    console.log( this + " {created}" )
    this.onclick = function ( event )
    {
        alert( this.id + " " + this.value )
    } 
}

//Type Extension
var newProto = Object.create( HTMLButtonElement.prototype )
newProto.createdCallback = callback
var XFooButtonExt = document.registerElement( 'x-foo-button', {
    prototype: newProto,
    extends: 'button'
} )

newProto отличается от HTMLButtonElement prototype.

Со следующим кодом HTML:

<button is="x-foo-button" id="Hello" value="World"> Hello </button>

Щелчок по нему отобразит "Hello World" во всплывающем окне.


Ответ 2 extends: 'button' - это семантическая индикация, указывающая браузеру, что новый прототип реализует интерфейс HTMLButtonElement. Поэтому проще начать с объекта, который наследуется от HTMLButtonElement. Вместо этого вы можете начать с прототипа HTMLFormElement, но вам придется переопределить все свойства и методы интерфейса HTMLButtonElement.

Если нет, поведение элемента будет неправильным. В приведенном выше примере, если вы замените строку на:

var newProto = Object.create( HTMLFormElement.prototype )

... щелчок на нем завершится неудачно, потому что свойство value не реализовано в элементе <form>.

Свойство id всегда корректно, потому что оно обеспечивается интерфейсом HTMLElement, реализованным каждым элементом (включая <form>).

Обратите внимание, что вы можете добавить отсутствующие свойства и связать их с их атрибутом в методе attributeChangedCallback.


Ответ 3 Ты прав. Это поддерживает обратную совместимость со старыми браузерами, которые игнорируют второй аргумент, все еще способный создать нормальный элемент (стандартный <button> в вашем примере).


Ответ 4 В парадигме Custom Elements есть две разные концепции:

  • Расширения типов (настраиваемые встроенные элементы), если вы хотите расширить стандартный элемент HTML.
  • Пользовательский тег (автономные пользовательские элементы), если вы хотите определить пользовательские элементы с новыми именами.

Оба определены с помощью того же метода registerElement. Опция extends/is позволяет выбрать один из них.

Синтаксис is работает только с расширениями типов и поэтому всегда связан с опцией extends.

С помощью Type Extensions вы сохраняете всю семантику расширяемого элемента: стили CSS, встроенное поведение (интерфейсы), возможности доступа. Обратная совместимость - еще одно преимущество этого синтаксиса.

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

Обновить: следующий пример (для Chrome и Opera) иллюстрирует разницу между расширением типа и пользовательским тегом.

//Method
function callback() {
  this.textContent = this //Get the HTML semantics
  this.onclick = function(event) {
    try {
      var output = this.id + " "
      output += this.name        //works only with <button is=...>
    } 
    catch (e) {
      output += "a generic element"
    }
    alert(output)
  }
}

//Type Extension
var newProto = Object.create(HTMLButtonElement.prototype)
newProto.createdCallback = callback

var XFooButtonExt = document.registerElement('x-foo-button', {
  prototype: newProto,
  extends: 'button'
})

//Custom Tag
var newProto2 = Object.create(HTMLButtonElement.prototype)
newProto2.createdCallback = callback

var XFooButtonCust = document.registerElement('x-foo-button-2', {
  prototype: newProto2,
})
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <title>Custom Elements</title>
</head>

<body>
  <h3>Type Extension</h3>
  <button is="x-foo-button" id="I'm" name="a button">Type Extension</button>
  <h3>Custom Tag</h3>
  <x-foo-button-2 id="I'm" name="a button">Custom Tag</x-foo-button-2>
</body>

</html>