document.registerElement — Почему нам нужно указывать как «прототип», так и «расширение»?

Представьте, что я хочу расширить собственный элемент button и создать свой собственный элемент super-button. Насколько я знаю, он должен следовать следующему шаблону:

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

Мне это кажется странным - разве параметры prototype и extends не говорят об одном и том же? Если я прямо говорю, что мой super-button использует прототип HTMLButtonElement, зачем мне также указывать, что он расширяет элемент кнопки? это не лишнее? Для меня это выглядит как точно такая же информация.


person gipouf    schedule 12.04.2016    source источник
comment
Нет, может быть несколько тегов с одним и тем же прототипом.   -  person Bergi    schedule 12.04.2016
comment
так что часть «расширения» больше касается наследования стиля и внешнего вида элемента?   -  person gipouf    schedule 12.04.2016
comment
Нет, extends касается наследования встроенного поведения (например, того, как он действует в форме) элемента. Вы захотите прочитать о различии между пользовательскими элементами и расширениями типов.   -  person Bergi    schedule 12.04.2016
comment
@Bergi Я не думаю, что несколько пользовательских тегов могут использовать один и тот же прототип (registerElement этого не примет)   -  person Supersharp    schedule 12.05.2016
comment
@Supersharp: я не знаю (не пробовал), но я имел в виду, что вы не можете вывести имя тега из прототипа (цепочки). Если я создам прототип своего пользовательского тега с Object.create(HTMLQuoteElement.prototype), что, по вашему мнению, он расширит?   -  person Bergi    schedule 12.05.2016


Ответы (3)


Из спецификации пользовательских элементов:

Как правило, имя расширяемого элемента нельзя определить, просто взглянув на интерфейс элемента, который он расширяет, поскольку многие элементы используют один и тот же интерфейс (например, q и blockquote используют один и тот же HTMLQuoteElement).

Другими словами, хотя это может быть избыточным для элементов <button>, в целом это не является избыточным, и спецификация должна поддерживать общий случай.

Я бы сказал, что это даже не избыточно для <button>, поскольку ничто не мешает вам сделать:

var SuperButton = document.registerElement('super-button', {
  prototype: Object.create(HTMLButtonElement.prototype),
  extends: 'a'
});
person Paul    schedule 12.04.2016
comment
Хорошо, насколько я понимаю, часть «расширения» касается наследования стиля и внутреннего DOM элемента, а «прототип» — функциональности. Я прав? В противном случае я не понимаю, что значит расширять прототип кнопки и одновременно быть элементом «а». Это довольно запутанно :-). - person gipouf; 12.04.2016
comment
@gipouf вы можете прочитать этот пост для получения дополнительной информации: stackoverflow.com/questions/34055503/ - person Supersharp; 12.05.2016

Чтобы уточнить ответ Paulpro: extends создает синтаксис is=. Если q и blockquote совместно используют HTMLQuoteElement, и вы расширяете q, то вы можете написать <q is="super-button">, но не можете написать <blockquote is="super-button">.

Что касается того, что означает расширение ссылки a с помощью prototype другого элемента, это создаст ссылку, которая не имеет соответствующих функций и свойств, что плохо:

См.: https://jsfiddle.net/3g0pus8r/.

<a is="anchor-one" href="google.com">1st link</a>
<a is="anchor-two" href="google.com">2nd link</a>

var proto1 = Object.create(HTMLAnchorElement.prototype, {
  createdCallback: {
    value: function() { 
    console.log("1st:");
    console.log(HTMLAnchorElement.prototype.isPrototypeOf(this));
    console.log(this.hostname);
    console.log(this.toString());
    }
  }
});

var proto2 = Object.create(HTMLButtonElement.prototype, {
  createdCallback: {
    value: function() {        
    console.log("\n2nd:");
    console.log(HTMLAnchorElement.prototype.isPrototypeOf(this));
    console.log(this.hostname);
    console.log(this.toString());
    }
  }
});

document.registerElement("anchor-one",{prototype:proto1, extends: "a"});
document.registerElement("anchor-two",{prototype:proto2, extends: "a"});

Результат:

1st:
true
fiddle.jshell.net
https://fiddle.jshell.net/_display/google.com

2st:
false
undefined
[object HTMLButtonElement]

Тем не менее, вы можете по-прежнему хотеть:

  • Расширение MyOtherAnchor, которое, в свою очередь, расширяет HTMLAnchorElement;
  • Расширьте HTMLElement и реализуйте весь интерфейс привязки самостоятельно.
  • Создайте якорь с другим, нестандартным интерфейсом.
person MarcG    schedule 21.04.2016

На самом деле, это позволяет вам различать Custom Объявление тегов по сравнению с < em>Type Extensions (как предложено вторым комментарием Берги), так как оба используют один и тот же метод document.registerElement().

Расширения типов: используйте extends

document.registerElement( "button-v2",  { 
    prototype: Object.create( HTMLButtonElement.prototype ),
    extends: 'button'
} )

<button-v2> продолжит действовать как <button> (т.е. сохранит свою семантику).

Пользовательские теги: не используйте extends

document.registerElement( "not-button",  { 
    prototype: Object.create( HTMLButtonElement.prototype )
} )

<not-button> наследуется от интерфейса HTMLButtonElement, но теряет свою семантику (т.е. не будет действовать как <button>)


NB: Если бы единственная причина заключалась в том, что вы не всегда можете вывести <element> из цепочки прототипов, был бы предложен необязательный параметр для устранения неоднозначности в таких редких случаях. Здесь они выбрали общий, синтетический метод, который на первый взгляд сбивает с толку, вы правы!

person Supersharp    schedule 12.05.2016