如何指定 运行 嵌套 Web 组件构造函数的顺序?
How can I specify the sequence of running nested web components constructors?
我创建了两个网络组件并将其中一个嵌套到另一个中。
他们都有它的constructor
。我遇到的问题是,我无法控制 运行 constructor
的顺序。
有什么办法可以解决这个问题吗?
这是我的代码:
子网络组件:
(function () {
const template = document.createElement('template');
template.innerHTML = `<div>WC1</div>`;
class WC1Component extends HTMLElement {
constructor() {
super();
console.log('WC1: constructor()');
var me = this;
me._shadowRoot = this.attachShadow({ 'mode': 'open' });
me._shadowRoot.appendChild(template.content.cloneNode(true));
}
connectedCallback() {
console.log('WC1: connectedCallback');
}
test() {
console.log('test:wc1');
}
}
window.customElements.define('wc-one', WC1Component);
}());
父网络组件:
(function () {
const template = document.createElement('template');
template.innerHTML = `
<wc-one id="wc1"></wc-one>
<div>WC2</div>
`;
class WC2Component extends HTMLElement {
constructor() {
super();
console.log('WC2: constructor()');
var me = this;
me._shadowRoot = this.attachShadow({ 'mode': 'open' });
me._shadowRoot.appendChild(template.content.cloneNode(true));
me._wc1 = me._shadowRoot.querySelector('#wc1');
}
connectedCallback() {
console.log('WC2: connectedCallback');
this._wc1.test(); // <-- Error: test is undefined!
}
}
window.customElements.define('wc-two', WC2Component);
}());
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Test Web Component</title>
</head>
<body>
<script src="wc1.js"></script>
<script src="wc2.js"></script>
<wc-two></wc-two>
<script>
</script>
</body>
</html>
结果:
WC2: constructor()
WC2: connectedCallback
Uncaught TypeError: this._wc1.test is not a function
WC1: constructor()
WC1: connectedCallback
您可以使用:
setTimeout(() => {
this._wc1.test();
});
在 connectedCallback
实际上,您确实可以控制构造函数的 运行 序列。
由于 <wc-one>
是由 <wc-two>
创建的,因此 WC2 构造函数将始终在 WC1 之前被调用。
错误是因为当您尝试调用它时,内部组件 (WC1) 尚未添加到 DOM。
您可以监听 DOMContentLoaded
事件以确保元素正常,或者监听 window
上的 load
事件,或者实现 window.onload
处理程序。 @elanz-nasiri 也在工作。
DOMContentLoaded
将首先被解雇。
有替代解决方案,但更难实施。
window.customElements.define('wc-one', class extends HTMLElement {
constructor() {
super()
this.attachShadow({ 'mode': 'open' }).innerHTML = `<div>WC1</div>`
}
test(source) {
console.log('test:wc1', source)
}
} )
window.customElements.define('wc-two', class extends HTMLElement {
constructor() {
super()
this._shadowRoot = this.attachShadow({ 'mode': 'open' })
this._shadowRoot.innerHTML = `<wc-one id="wc1"></wc-one><div>WC2</div>`
this._wc1 = this._shadowRoot.querySelector('#wc1');
}
connectedCallback() {
setTimeout( ()=>this._wc1.test('setTimout') )
document.addEventListener( 'DOMContentLoaded', ()=>this._wc1.test('DOMContentLoaded') )
window.onload = ()=>this._wc1.test('window.onload')
window.addEventListener( 'load', ()=>this._wc1.test('load') )
}
} )
<wc-two></wc-two>
如果您想控制何时调用构造函数,则需要调用它。不要让 HTML 解析器为你做这件事。允许 HTML 解析器执行此操作的问题在于您不知道 组件何时 升级。
const template = document.createElement('template');
template.innerHTML = `<div>WC1</div>`;
class WC1Component extends HTMLElement {
constructor() {
super();
console.log('WC1: constructor()');
this.attachShadow({ 'mode': 'open' });
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
connectedCallback() {
console.log('WC1: connectedCallback');
}
test() {
console.log('test:wc1');
}
}
window.customElements.define('wc-one', WC1Component);
//<wc-one id="wc1"></wc-one>
//<div>WC2</div>
class WC2Component extends HTMLElement {
constructor() {
super();
console.log('WC2: constructor()');
let wc1 = document.createElement('wc-one');
wc1.id = 'wc1';
this.attachShadow({ 'mode': 'open' });
this._wc1 = wc1;
this.shadowRoot.appendChild(wc1);
let div = document.createElement('div');
div.textContent = 'WC2';
this.shadowRoot.appendChild(div);
}
connectedCallback() {
console.log('WC2: connectedCallback');
this._wc1.test();
}
}
window.customElements.define('wc-two', WC2Component);
<wc-two></wc-two>
我所做的只是通过调用 document.createElement('wc-one')
使 wc-one
的构造函数执行,然后将其添加到组件中。这会强制该对象在我尝试使用其 test
函数之前存在。
此外,您不需要保存 this.attachShadow({ 'mode': 'open' });
的 return 值,因为它已经作为 this.shadowRoot
.
可用
您也不需要将 this
保存为 me
。
我创建了两个网络组件并将其中一个嵌套到另一个中。
他们都有它的constructor
。我遇到的问题是,我无法控制 运行 constructor
的顺序。
有什么办法可以解决这个问题吗?
这是我的代码:
子网络组件:
(function () {
const template = document.createElement('template');
template.innerHTML = `<div>WC1</div>`;
class WC1Component extends HTMLElement {
constructor() {
super();
console.log('WC1: constructor()');
var me = this;
me._shadowRoot = this.attachShadow({ 'mode': 'open' });
me._shadowRoot.appendChild(template.content.cloneNode(true));
}
connectedCallback() {
console.log('WC1: connectedCallback');
}
test() {
console.log('test:wc1');
}
}
window.customElements.define('wc-one', WC1Component);
}());
父网络组件:
(function () {
const template = document.createElement('template');
template.innerHTML = `
<wc-one id="wc1"></wc-one>
<div>WC2</div>
`;
class WC2Component extends HTMLElement {
constructor() {
super();
console.log('WC2: constructor()');
var me = this;
me._shadowRoot = this.attachShadow({ 'mode': 'open' });
me._shadowRoot.appendChild(template.content.cloneNode(true));
me._wc1 = me._shadowRoot.querySelector('#wc1');
}
connectedCallback() {
console.log('WC2: connectedCallback');
this._wc1.test(); // <-- Error: test is undefined!
}
}
window.customElements.define('wc-two', WC2Component);
}());
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Test Web Component</title>
</head>
<body>
<script src="wc1.js"></script>
<script src="wc2.js"></script>
<wc-two></wc-two>
<script>
</script>
</body>
</html>
结果:
WC2: constructor()
WC2: connectedCallback
Uncaught TypeError: this._wc1.test is not a function
WC1: constructor()
WC1: connectedCallback
您可以使用:
setTimeout(() => {
this._wc1.test();
});
在 connectedCallback
实际上,您确实可以控制构造函数的 运行 序列。
由于 <wc-one>
是由 <wc-two>
创建的,因此 WC2 构造函数将始终在 WC1 之前被调用。
错误是因为当您尝试调用它时,内部组件 (WC1) 尚未添加到 DOM。
您可以监听 DOMContentLoaded
事件以确保元素正常,或者监听 window
上的 load
事件,或者实现 window.onload
处理程序。 @elanz-nasiri 也在工作。
DOMContentLoaded
将首先被解雇。
有替代解决方案,但更难实施。
window.customElements.define('wc-one', class extends HTMLElement {
constructor() {
super()
this.attachShadow({ 'mode': 'open' }).innerHTML = `<div>WC1</div>`
}
test(source) {
console.log('test:wc1', source)
}
} )
window.customElements.define('wc-two', class extends HTMLElement {
constructor() {
super()
this._shadowRoot = this.attachShadow({ 'mode': 'open' })
this._shadowRoot.innerHTML = `<wc-one id="wc1"></wc-one><div>WC2</div>`
this._wc1 = this._shadowRoot.querySelector('#wc1');
}
connectedCallback() {
setTimeout( ()=>this._wc1.test('setTimout') )
document.addEventListener( 'DOMContentLoaded', ()=>this._wc1.test('DOMContentLoaded') )
window.onload = ()=>this._wc1.test('window.onload')
window.addEventListener( 'load', ()=>this._wc1.test('load') )
}
} )
<wc-two></wc-two>
如果您想控制何时调用构造函数,则需要调用它。不要让 HTML 解析器为你做这件事。允许 HTML 解析器执行此操作的问题在于您不知道 组件何时 升级。
const template = document.createElement('template');
template.innerHTML = `<div>WC1</div>`;
class WC1Component extends HTMLElement {
constructor() {
super();
console.log('WC1: constructor()');
this.attachShadow({ 'mode': 'open' });
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
connectedCallback() {
console.log('WC1: connectedCallback');
}
test() {
console.log('test:wc1');
}
}
window.customElements.define('wc-one', WC1Component);
//<wc-one id="wc1"></wc-one>
//<div>WC2</div>
class WC2Component extends HTMLElement {
constructor() {
super();
console.log('WC2: constructor()');
let wc1 = document.createElement('wc-one');
wc1.id = 'wc1';
this.attachShadow({ 'mode': 'open' });
this._wc1 = wc1;
this.shadowRoot.appendChild(wc1);
let div = document.createElement('div');
div.textContent = 'WC2';
this.shadowRoot.appendChild(div);
}
connectedCallback() {
console.log('WC2: connectedCallback');
this._wc1.test();
}
}
window.customElements.define('wc-two', WC2Component);
<wc-two></wc-two>
我所做的只是通过调用 document.createElement('wc-one')
使 wc-one
的构造函数执行,然后将其添加到组件中。这会强制该对象在我尝试使用其 test
函数之前存在。
此外,您不需要保存 this.attachShadow({ 'mode': 'open' });
的 return 值,因为它已经作为 this.shadowRoot
.
您也不需要将 this
保存为 me
。