document.registerElement - Why do we need to specify both 'prototype' and 'extends'?

时间:2016-04-12 00:44:44

标签: javascript html5 web-component custom-element

Consider I want to extend the native button element, and create my own super-button element. As I know, it must follow the following pattern:

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

It looks strange to me - doesn't the prototype and extends parameters say the same thing? If I explicitly say that my super-button use the HTMLButtonElement prototype, why do I also need to specify that it extends the button element? isn't it redundant? For me it looks like exactly the same information.

3 个答案:

答案 0 :(得分:5)

来自Custom Elements specification

  

通常,扩展元素的名称不能简单地通过查看它扩展的元素接口来确定,因为许多元素共享相同的接口(例如q和blockquote都共享HTMLQuoteElement)。

换句话说,虽然<button>元素可能是多余的,但一般来说它并不冗余,并且规范需要支持一般情况。

我认为<button>并不是多余的,因为没有什么能阻止你这样做:

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

答案 1 :(得分:1)

澄清Paulpro的答案:extends创建is=语法。如果qblockquote共享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并自行实现所有锚接口。
  • 使用不同的非标准界面创建锚点。

答案 2 :(得分:1)

实际上,它允许您区分Custom Tags声明与Type Extensions声明(由Bergi的第二条评论建议),因为它们共享相同的方法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>

注意:如果唯一的原因是因为你不能总是从其原型链中推断<element>,那么就会提出一个可选参数来消除这种罕见情况的歧义。在这里,他们选择了一种常见的合成方法,乍一看你是对的!