为何自定义元素构造函数中设置className未触发浏览器报错?
自定义元素构造器中设置className为何不触发规范错误?
最小复现代码(JS代码第5行)
JavaScript代码
class Bazooka extends HTMLElement { host; constructor() { super(); this.className = "hi"; // 疑问点:参考规范第5条 this.host = this.attachShadow({ mode: "open" }); } connectedCallback() { let foo = document.querySelector(".test"); this.host.appendChild(foo.content); } } customElements.define("bazooka-show", Bazooka);
HTML代码
<!DOCTYPE html> <html lang="en"> <head> <title>Home</title> </head> <body> <main> <bazooka-show></bazooka-show> </main> <template class="test"> <p>A shadow DOM.</p> </template> </body> </html>
问题背景
根据HTML规范第5点要求:
元素不得添加任何属性或子元素
但上述代码在构造器中设置了className属性,浏览器却没有抛出错误,这是为什么?
解答
首先要明确规范里的“添加属性”指的是向元素添加新的HTML属性(Attribute),比如通过setAttribute('new-attr', 'value')这种方式添加自定义或非内置属性。而className是HTMLElement接口自带的DOM属性(Property),它是对元素class属性的反射——修改className本质是修改已有内置属性的取值,而非添加新属性。
其次,浏览器对于自定义元素构造器的规范约束,更多是行为约束而非强制抛出错误:违反规范可能导致元素行为异常,但对于修改内置DOM属性这类操作,浏览器是允许的,因为这属于操作元素本身就具备的特性,不属于“添加新属性”的范畴。
另外,规范的这条约束核心目的是避免构造器中操作元素属性/子元素导致的生命周期问题(比如元素尚未完全初始化就被修改),而修改className这类内置属性不会触发这类风险,因此浏览器不会对此抛出错误。
内容的提问来源于stack exchange,提问作者Arka Pratim Chaudhuri
相关产品推荐
相关产品推荐

