Порядок выполнения пользовательских элементов - PullRequest
0 голосов
/ 27 июня 2018

Я создал веб-компоненты, используя customElements.

<x-select>
     <x-option>India</x-option>
     <x-option>Africa</x-option>
</x-select>

Порядок выполнения будет таким: сначала вызывается конструктор <x-select>, а затем вызывается конструктор <x-option>. Но я хочу, чтобы конструктор <z-option> сначала вызывался до <z-select>. Как мне этого добиться?

Ответы [ 2 ]

0 голосов
/ 28 июня 2018

Есть несколько факторов для порядка операций с веб-компонентами.

Когда создается компонент с внутренними элементами, внешний конструктор будет вызываться первым. Тогда внутренние конструкторы называются. Это нормально.

Если компонент НЕ находится в реальном дереве 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. И, опять же, они сначала для внешнего элемента, а затем для внутреннего. элементы.

0 голосов
/ 27 июня 2018

Существуют разные способы достижения этого.

Через Javascript

1 ° Создайте <x-option> s:

xo1 = document.createElement( 'x-option' )

2 ° Создать <x-select>

xs = document.createElement( 'x-select' )

3 ° Добавить <x-option>

xs.appendChild( xo1 )

Через HTML

Отложить инициацию родительского элемента в другом методе пользовательского элемента, а не в его constructor(). Затем вызовите этот метод, чтобы отменить создание дочерних элементов.

<x-select id="xs">
    <x-option>India</x-option>
    <x-option>Africa</x-option>
    <script>xs.init()</script>
</x-select>

<script>
class XSelect extends HTMLElement {
  constructor() {
    super()
    console.log('x-select created')
  }
  init() {
    console.info('x-select init')
  }
}
customElements.define('x-select', XSelect)

class XOption extends HTMLElement {
  constructor() {
    super()
    console.log('x-option created')
  }
}
customElements.define('x-option', XOption)
</script>

<x-select id="xs">
  <x-option id="1">India</x-option>
  <x-option id="2">Africa</x-option>
  <script>xs.init()</script>
</x-select>
...