document.registerElement - 为什么我们需要同时指定 'prototype' 和 'extends'?
document.registerElement - Why do we need to specify both 'prototype' and 'extends'?
假设我想扩展本机 button
元素,并创建我自己的 super-button
元素。据我所知,它必须遵循以下模式:
var SuperButton = document.registerElement('super-button', {
prototype: Object.create(HTMLButtonElement.prototype),
extends: 'button'
});
我觉得很奇怪 - prototype
和 extends
参数不是说同样的事情吗?如果我明确地说我的 super-button
使用 HTMLButtonElement
原型,为什么我还需要指定它扩展按钮元素?这不是多余的吗?对我来说,它看起来像是完全相同的信息。
来自Custom Elements specification:
In general, the name of the element being extended cannot be determined simply by looking at what element interface it extends, as many elements share the same interface (such as q and blockquote both sharing HTMLQuoteElement).
换句话说,虽然它对于 <button>
个元素可能是冗余的,但它通常不是冗余的,规范需要支持一般情况。
不过,我认为它对 <button>
来说甚至都不是多余的,因为没有什么可以阻止你这样做:
var SuperButton = document.registerElement('super-button', {
prototype: Object.create(HTMLButtonElement.prototype),
extends: 'a'
});
为了澄清 Paulpro 的回答:extends
创建了 is=
语法。如果q
和blockquote
都共享HTMLQuoteElement
,而你扩展q
,那么你可以写<q is="super-button">
但不能写<blockquote is="super-button">
.
关于用另一个元素的 prototype
扩展 a
link 意味着什么,这将创建一个没有适当功能和属性的 link,这不好:
参见: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
并自己实现所有锚点接口。
- 使用不同的非标准界面创建锚点。
实际上,它允许您区分 Custom Tags declaration versus Type Extensions 声明(正如 Bergi 的第二条评论所建议的),因为它们共享相同的方法 document.registerElement()
.
类型扩展:使用extends
document.registerElement( "button-v2", {
prototype: Object.create( HTMLButtonElement.prototype ),
extends: 'button'
} )
<button-v2>
将继续充当 <button>
(ie 保持其语义)。
自定义标签:不要使用 extends
document.registerElement( "not-button", {
prototype: Object.create( HTMLButtonElement.prototype )
} )
<not-button>
继承自 HTMLButtonElement
接口但失去了语义(ie 不会充当 <button>
)
注意:如果唯一的原因真的是因为你不能总是从它的原型链中推断出一个 <element>
,那么就会提出一个可选参数来消除这种罕见情况的歧义。在这里,他们选择了一种常见的 synthetic 方法,乍一看会令人困惑,你是对的!
假设我想扩展本机 button
元素,并创建我自己的 super-button
元素。据我所知,它必须遵循以下模式:
var SuperButton = document.registerElement('super-button', {
prototype: Object.create(HTMLButtonElement.prototype),
extends: 'button'
});
我觉得很奇怪 - prototype
和 extends
参数不是说同样的事情吗?如果我明确地说我的 super-button
使用 HTMLButtonElement
原型,为什么我还需要指定它扩展按钮元素?这不是多余的吗?对我来说,它看起来像是完全相同的信息。
来自Custom Elements specification:
In general, the name of the element being extended cannot be determined simply by looking at what element interface it extends, as many elements share the same interface (such as q and blockquote both sharing HTMLQuoteElement).
换句话说,虽然它对于 <button>
个元素可能是冗余的,但它通常不是冗余的,规范需要支持一般情况。
不过,我认为它对 <button>
来说甚至都不是多余的,因为没有什么可以阻止你这样做:
var SuperButton = document.registerElement('super-button', {
prototype: Object.create(HTMLButtonElement.prototype),
extends: 'a'
});
为了澄清 Paulpro 的回答:extends
创建了 is=
语法。如果q
和blockquote
都共享HTMLQuoteElement
,而你扩展q
,那么你可以写<q is="super-button">
但不能写<blockquote is="super-button">
.
关于用另一个元素的 prototype
扩展 a
link 意味着什么,这将创建一个没有适当功能和属性的 link,这不好:
参见: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
并自己实现所有锚点接口。 - 使用不同的非标准界面创建锚点。
实际上,它允许您区分 Custom Tags declaration versus Type Extensions 声明(正如 Bergi 的第二条评论所建议的),因为它们共享相同的方法 document.registerElement()
.
类型扩展:使用extends
document.registerElement( "button-v2", {
prototype: Object.create( HTMLButtonElement.prototype ),
extends: 'button'
} )
<button-v2>
将继续充当 <button>
(ie 保持其语义)。
自定义标签:不要使用 extends
document.registerElement( "not-button", {
prototype: Object.create( HTMLButtonElement.prototype )
} )
<not-button>
继承自 HTMLButtonElement
接口但失去了语义(ie 不会充当 <button>
)
注意:如果唯一的原因真的是因为你不能总是从它的原型链中推断出一个 <element>
,那么就会提出一个可选参数来消除这种罕见情况的歧义。在这里,他们选择了一种常见的 synthetic 方法,乍一看会令人困惑,你是对的!