HTML5 自定义元素中的生命周期回调是否可以在注册后定义?
Can life cycle callbacks in an HTML5 custom element be defined after registration?
我最近一直在使用 HTML5 自定义元素,偶然发现了一个令人沮丧的问题。在所有示例中考虑以下 HTML 正文:
<body>
<h2>Foo elements.</h2>
<foo-element>One!</foo-element>
<foo-element>Two!</foo-element>
</body>
并且这个脚本附在页面的头部,用于注册自定义元素:
var HTMLFooElement = document.registerElement('foo-element', {
prototype: Object.create(HTMLDivElement.prototype, {
createdCallback: { value: function() {
console.log('[CALLBACK] created: ', this);
}},
attachedCallback: { value: function() {
console.log('[CALLBACK] attached: ', this);
}}
})
});
该应用程序将在 Chromium 版本 41.0.2272.76 上按预期工作:声明的自定义元素将触发两个回调,向控制台打印 4 行。
[CALLBACK] created: <foo-element>One!</foo-element>
[CALLBACK] attached: <foo-element>One!</foo-element>
[CALLBACK] created: <foo-element>Two!</foo-element>
[CALLBACK] attached: <foo-element>Two!</foo-element>
但现在我有这个用例,我必须将 attachedCallback
的定义推迟到将来的场合:
var HTMLFooElement = document.registerElement('foo-element', {
prototype: Object.create(HTMLDivElement.prototype, {
createdCallback: { value: function() {
console.log('[CALLBACK] created: ', this);
}},
})
});
HTMLFooElement.prototype.attachedCallback = function() {
console.log('[CALLBACK] attached: ', this);
};
事实证明,这个版本不会触发 attachedCallback
并且不会打印 "attached" 行日志 (jsfiddle)。此时该函数肯定会作为成员出现在我所有的自定义元素中,因为所有代码都是在处理 DOM 的 body
部分之前执行的。不管怎样,在加载文档后在 JavaScript 中创建和附加新元素时,结果是相同的。
让我感到困惑的是,自定义标记注册后生命周期回调的后期定义没有被应用。调用registerElement
后如何定义生命周期回调并真正生效?
注册元素的过程好像是在内部复制了每一个生命周期回调,也就是说修改原来的原型是没有效果的。我设法避免在我的项目中重新定义,但对于那些遇到同样问题的人来说,引入代理是解决它的一种方法,不需要重新注册元素。
var protoProxy = {
createdCallback: function(e) {
console.log('[CALLBACK] created: ', e);
},
attachedCallback: function(e) {
console.log('[CALLBACK] placeholding ...');
}
};
var HTMLFooProto = Object.create(HTMLDivElement.prototype, {
createdCallback: { value: function() {
protoProxy.createdCallback(this);
}},
attachedCallback: { value: function() {
protoProxy.attachedCallback(this);
}}
});
var HTMLFooElement = document.registerElement('foo-element', {
prototype: HTMLFooProto
});
protoProxy.attachedCallback = function(e) {
console.log('[CALLBACK] attached: ', e);
};
我最近一直在使用 HTML5 自定义元素,偶然发现了一个令人沮丧的问题。在所有示例中考虑以下 HTML 正文:
<body>
<h2>Foo elements.</h2>
<foo-element>One!</foo-element>
<foo-element>Two!</foo-element>
</body>
并且这个脚本附在页面的头部,用于注册自定义元素:
var HTMLFooElement = document.registerElement('foo-element', {
prototype: Object.create(HTMLDivElement.prototype, {
createdCallback: { value: function() {
console.log('[CALLBACK] created: ', this);
}},
attachedCallback: { value: function() {
console.log('[CALLBACK] attached: ', this);
}}
})
});
该应用程序将在 Chromium 版本 41.0.2272.76 上按预期工作:声明的自定义元素将触发两个回调,向控制台打印 4 行。
[CALLBACK] created: <foo-element>One!</foo-element>
[CALLBACK] attached: <foo-element>One!</foo-element>
[CALLBACK] created: <foo-element>Two!</foo-element>
[CALLBACK] attached: <foo-element>Two!</foo-element>
但现在我有这个用例,我必须将 attachedCallback
的定义推迟到将来的场合:
var HTMLFooElement = document.registerElement('foo-element', {
prototype: Object.create(HTMLDivElement.prototype, {
createdCallback: { value: function() {
console.log('[CALLBACK] created: ', this);
}},
})
});
HTMLFooElement.prototype.attachedCallback = function() {
console.log('[CALLBACK] attached: ', this);
};
事实证明,这个版本不会触发 attachedCallback
并且不会打印 "attached" 行日志 (jsfiddle)。此时该函数肯定会作为成员出现在我所有的自定义元素中,因为所有代码都是在处理 DOM 的 body
部分之前执行的。不管怎样,在加载文档后在 JavaScript 中创建和附加新元素时,结果是相同的。
让我感到困惑的是,自定义标记注册后生命周期回调的后期定义没有被应用。调用registerElement
后如何定义生命周期回调并真正生效?
注册元素的过程好像是在内部复制了每一个生命周期回调,也就是说修改原来的原型是没有效果的。我设法避免在我的项目中重新定义,但对于那些遇到同样问题的人来说,引入代理是解决它的一种方法,不需要重新注册元素。
var protoProxy = {
createdCallback: function(e) {
console.log('[CALLBACK] created: ', e);
},
attachedCallback: function(e) {
console.log('[CALLBACK] placeholding ...');
}
};
var HTMLFooProto = Object.create(HTMLDivElement.prototype, {
createdCallback: { value: function() {
protoProxy.createdCallback(this);
}},
attachedCallback: { value: function() {
protoProxy.attachedCallback(this);
}}
});
var HTMLFooElement = document.registerElement('foo-element', {
prototype: HTMLFooProto
});
protoProxy.attachedCallback = function(e) {
console.log('[CALLBACK] attached: ', e);
};