【发布时间】:2023-03-30 21:53:01
【问题描述】:
我想知道为什么new HTMLElement() 和其他人(例如new HTMLDivElement())会抛出非法构造函数错误。
我想要这样的代码:
// create a square with a given length
class Square extends HTMLDivElement {
constructor(len) {
super();
this.style.width = `${len}px`;
this.style.height = `${len}px`;
this.style.border = '1px solid black';
}
}
const square = new Square(5);
document.body.appendChild(square);
但是,上面的代码不亚于只是一个愿望,因为上面的代码抛出了非法构造函数错误。
我认为有两种解决方法:(1) 使用 $ref (2) 使用自定义元素。请让我展示一下。
(1) 使用 $ref
class Square {
constructor(len) {
const $div = document.createElement('div');
$div.style.width = `${len}px`;
$div.style.height = `${len}px`;
$div.style.border = '1px solid black';
this.$ref = $div;
}
}
const square = new Square(5); // returns Square object
document.body.appendChild(square.$ref);
这样,我可以做一个正方形,但不方便,因为我不能直接访问 div(=$ref)。我需要先通过“方形”对象。 (我想说的是appendChild(square)和appendChild(square.$ref)之间的区别)因为new HTMLDivElement()是不可能的,所以我别无选择,只能使用一个像包装器一样的对象。
(2) 使用(自治)自定义元素——也使用 $ref。
class Square extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
const $div = document.createElement('div');
this.shadowRoot.appendChild($div);
this.shadowRoot.$ref = $div;
}
connectedCallback() {
this.shadowRoot.$ref.style.width = `${this.dataset.len}px`;
this.shadowRoot.$ref.style.height = `${this.dataset.len}px`;
this.shadowRoot.$ref.style.border = '1px solid black';
}
}
customElements.define('custom-square', Square);
const square = document.createElement('custom-square');
square.setAttribute('data-len', 5);
document.body.appendChild(square);
在这种情况下,new Square(5) 因为非法构造函数错误而无法完成,所以我必须使用data-len 自定义属性和connectedCallback() 以便在附加square 时将data-len 应用于$ref.style到 DOM。
当然我可以同时使用这两种方式,但我仍然想知道为什么 new HTMLElement() 被禁止。有什么历史原因吗?
另外,让我想知道的是,即使new HTMLElement() 抛出非法构造函数错误,document.createElement() 如何(在内部)创建一个新的 HTMLElement 实例?根据the first answer of this question,HTMLElement.constructor() 抛出异常,而不是创建对象。那么当我调用document.createElement('div')时HTMLDivElement是如何被实例化并返回给我的呢?
另外,我看到an answer 使用Object.create() 方法创建HTMLElement 的实例。它工作并返回HTMLElement 实例,但似乎HTMLElement 实例无法正常工作。例如,
const test = Object.create(HTMLDivElement.prototype, {});
test.textContent = 'test'; // illegal invocation
由于某种原因,我可能会遇到非法调用错误。这是为什么呢?
【问题讨论】:
-
是的,您可能打算使用
document.createElement而不是扩展内置类。 -
我找到了关于此错误消息的答案stackoverflow.com/q/41521812/14032355
-
使
Square扩展HTMLDivElement,然后是customElements.define('custom-square', Square, {extends: 'div'});。 -
因为 DOM 元素实际上不仅仅是 JS 并且不在同一个“领域”中,因为一个元素需要一个 ownerDocument,因为......可能还有其他好的原因。
标签: javascript dom