自定义元素执行的顺序

时间:2018-06-27 06:24:28

标签: javascript html html5 web-component

我已经使用customElements创建了Web组件。

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

执行顺序为:首先调用<x-select>的构造函数,然后调用<x-option>的构造函数。但是,我希望在<z-option>之前先调用<z-select>的构造函数。我该如何实现?

2 个答案:

答案 0 :(得分:0)

有不同的实现方法。

通过JavaScript

1°创建<x-option>

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>

答案 1 :(得分:0)

Web组件的操作顺序有几个因素。

创建带有内部元素的组件时,将首先调用外部构造函数。然后调用内部构造函数。这很正常。

如果该组件不在真正的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

即使在<x-select>中使用影子DOM时,操作顺序也相同:

// 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的调用。再次,这些是首先需要外部元素,然后是内部元素。元素。