Есть несколько факторов для порядка операций с веб-компонентами.
Когда создается компонент с внутренними элементами, внешний конструктор будет вызываться первым. Тогда внутренние конструкторы называются. Это нормально.
Если компонент НЕ находится в реальном дереве DOM, больше ничего не произойдет. Никакой другой код не вызывается.
Как только компонент помещен в DOM, вызывается connectedCallback
. Начиная с внешнего компонента, а затем с внутренних компонентов.
Вот пример, не использующий теневой DOM:
// Class for `<x-select>`
class XSelect extends HTMLElement {
constructor() {
super();
console.log('x-select constructor');
}
connectedCallback() {
console.log('x-select connectedCallback');
}
}
// Define our web component
customElements.define('x-select', XSelect);
// Class for `<x-option>`
class XOption extends HTMLElement {
constructor() {
super();
console.log('x-option constructor');
}
connectedCallback() {
console.log('x-option connectedCallback');
}
}
// Define our web component
customElements.define('x-option', XOption);
<x-select>
<x-option>India</x-option>
<x-option>Africa</x-option>
</x-select>
Вывод на консоль:
x-select constructor
x-select connectedCallback
x-option constructor
x-option connectedCallback
x-option constructor
x-option connectedCallback
Даже при использовании теневого DOM в <x-select>
порядок операций такой же:
// Class for `<x-select>`
class XSelect extends HTMLElement {
constructor() {
super();
var sd = this.attachShadow({mode:'open'});
sd.innerHTML = '<slot></slot>';
console.log('x-select constructor');
}
connectedCallback() {
console.log('x-select connectedCallback');
}
}
// Define our web component
customElements.define('x-select', XSelect);
// Class for `<x-option>`
class XOption extends HTMLElement {
constructor() {
super();
console.log('x-option constructor');
}
connectedCallback() {
console.log('x-option connectedCallback');
}
}
// Define our web component
customElements.define('x-option', XOption);
<x-select>
<x-option>India</x-option>
<x-option>Africa</x-option>
</x-select>
Если мы создадим компоненты в JavaScript, мы сможем контролировать порядок построения. В моем примере ниже я создаю их в том же порядке, но вы можете смешать их, если хотите.
// Class for `<x-select>`
class XSelect extends HTMLElement {
constructor() {
super();
//var sd = this.attachShadow({mode:'open'});
//sd.innerHTML = '<slot></slot>';
console.log('x-select constructor');
}
connectedCallback() {
console.log('x-select connectedCallback');
}
}
// Define our web component
customElements.define('x-select', XSelect);
// Class for `<x-option>`
class XOption extends HTMLElement {
constructor() {
super();
console.log('x-option constructor');
}
connectedCallback() {
console.log(`x-option[${this.textContent}] connectedCallback`);
}
}
// Define our web component
customElements.define('x-option', XOption);
console.log('creating x-select');
var xs = document.createElement('x-select');
console.log('creating x-option 1');
var xo1 = document.createElement('x-option');
console.log('setting text of x-option 1');
xo1.textContent = 'India';
console.log('creating x-option 2');
var xo2 = document.createElement('x-option');
console.log('setting text of x-option 2');
xo2.textContent = 'Africa';
console.log('Adding x-option 1 to x-select');
xs.appendChild(xo1);
console.log('Adding x-option 2 to x-select');
xs.appendChild(xo2);
console.log('Adding x-select to container');
var c = document.getElementById('container');
c.appendChild(xs)
<div id="container"></div>
Конструкторы вызываются, когда я вызываю document.createElement
, но связанный обратный вызов не сработает, пока элементы не будут помещены в DOM.
Вывод на консоль вышеприведенного кода:
creating x-select
x-select constructor
creating x-option 1
x-option constructor
setting text of x-option 1
creating x-option 2
x-option constructor
setting text of x-option 2
Adding x-option 1 to x-select
Adding x-option 2 to x-select
Adding x-select to container
x-select connectedCallback
x-option[India] connectedCallback
x-option[Africa] connectedCallback
Последний пример - создание DIV, затем установите для innerHTML
следующее:
<x-select>
<x-option>India</x-option>
<x-option>Africa</x-option>
</x-select>
// Class for `<x-select>`
class XSelect extends HTMLElement {
constructor() {
super();
//var sd = this.attachShadow({mode:'open'});
//sd.innerHTML = '<slot></slot>';
console.log('x-select constructor');
}
connectedCallback() {
console.log('x-select connectedCallback');
}
}
// Define our web component
customElements.define('x-select', XSelect);
// Class for `<x-option>`
class XOption extends HTMLElement {
constructor() {
super();
console.log('x-option constructor');
}
connectedCallback() {
console.log(`x-option[${this.textContent}] connectedCallback`);
}
}
// Define our web component
customElements.define('x-option', XOption);
console.log('creating div');
var d = document.createElement('div');
console.log('setting innerHTML of div');
d.innerHTML = `<x-select>
<x-option>India</x-option>
<x-option>Africa</x-option>
</x-select>`;
console.log('Adding div to container');
var c = document.getElementById('container');
c.appendChild(d)
<div id="container"></div>
Теперь это вызывает только конструкторы внешнего элемента, а затем внутренние элементы. Только после ввода <div>
в DOM вызываются вызовы на connectedCallback
. И, опять же, они сначала для внешнего элемента, а затем для внутреннего. элементы.