在 Web 组件的构造函数中,您可以做什么和不可以做什么有一组规则。它们在下面。
但是想想这个:
可以通过以下三种方式之一创建组件:
- 初始页面的一部分/使用innerHTML:当浏览器加载页面或使用
innerHTML 时,您可以将属性和子项添加到组件作为页面加载的一部分或innerHTML 的一部分。
parent.innerHTML = '<super-hero name="Thor"><super-weapon value="Mjolnir"></super-weapon></super-hero>'.
- 您可以调用
document.createELement 来创建元素。在创建元素之前,您不能添加属性或子元素。
let superHero = document.createElement('super-hero');
let superWeapon = document.createElement('super-weapon');
superHero.setAttribute('name', 'Thor');
superWeapon.setAttribute('value', 'Mjolnir');
superHero.appendChild(superWeapon);
parent.appendChild(superHero)
- 您可以使用
new 实例化一个对象。就像document.createElement 一样,您必须等到元素创建后才能添加属性和子元素。
let superHero = new SuperHero();
let superWeapon = new SuperWeapon();
superHero.setAttribute('name', 'Thor');
superWeapon.setAttribute('value', 'Mjolnir');
superHero.appendChild(superWeapon);
parent.appendChild(superHero)
一旦组件被创建,它就会被添加到 DOM 中,这时你的组件的 connectedCallback 就会被调用。
所有这三种方式都归结为使用new 进行实例化。 document.createElement 调用 CustomElementRegistry.get 以获取该元素的构造函数,然后使用 new 创建对象。
innerHTML 解析 HTML,然后调用 document.createElement 或使用 new 创建对象。
但是,这样做时,调用元素的构造函数时没有属性或子元素。实际上,调用connectedCallback 时可能没有任何子项或属性。这是在规范中添加observedAttributes 和attributeChangedCallback 的原因之一。
规范中缺少的一件事是知道有人在组件添加到 DOM 之前或之后添加或更改了子项。但是,如果你真的想知道孩子什么时候发生变化,你可以使用MutationObserver。
这就是构造函数中不存在子元素或属性的原因。它们还没有被添加。
Now on to the rules:
在编写自定义元素构造函数时,作者受以下一致性要求的约束:
-
对 super() 的无参数调用必须是构造函数主体中的第一条语句,以便在运行任何进一步的代码之前建立正确的原型链和此值。
-
return 语句不得出现在构造函数主体内的任何位置,除非它是简单的提前返回(return 或 return this)。
-
构造函数不得使用 document.write() 或 document.open() 方法。
-
不得检查元素的属性和子元素,因为在非升级的情况下不会出现任何内容,并且依赖升级会降低元素的可用性。
-
元素不得获得任何属性或子元素,因为这违背了使用 createElement 或 createElementNS 方法的消费者的期望。
-
一般来说,工作应尽可能推迟到 connectedCallback ——尤其是涉及获取资源或渲染的工作。但是请注意,connectedCallback 可以多次调用,因此任何真正一次性的初始化工作都需要一个守卫来防止它运行两次。
-
一般来说,构造函数应该用于设置初始状态和默认值,并设置事件侦听器和可能的影子根。
在元素创建过程中会直接或间接检查其中一些要求,如果不遵循这些要求,将导致解析器或 DOM API 无法实例化自定义元素。