Большинство людей не знают о правилах конструктора веб-компонентов:
Вот официальные документы:
https://w3c.github.io/webcomponents/spec/custom/#custom-element-conformance
Резюме:
Ваш код конструктора:
- должен иметь беспараметрический вызов super () в качестве первого оператора в конструкторе.
- не должен иметьоператор возврата в любом месте конструктора.
- не должен вызывать document.write () или document.open ().
- не должен проверять атрибуты элемента.
- не должен изменять или добавлятьлюбые атрибуты или дочерние элементы.
В общем случае конструктор следует использовать для установки начального состояния и значений по умолчанию, а также для настройки прослушивателей событий и, возможно, теневого корня.
InВ общем, я согласен с @TJ Crowder, но я бы сделал одну незначительную модификацию объекта Bar
:
class Bar extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
}
static get observedAttributes() {
// Indicate that we want to be notified
// when the `val` attribute is changed
return ['val'];
}
connectedCallback() {
// Render the initial value
// when this element is placed into the DOM
render(this.getAttribute('val'));
}
attributeChangedCallback(attrName, oldVal, newVal) {
if (oldVal != newVal) {
// If the value for the `val` attribute has changed
// then re-render this element
render(newVal);
}
}
render(val = 'no value') {
this.shadowRoot.innerHTML = `
<div class='bar'>
<span>${val}</span>
</div>
`;
}
}
customElements.define('x-bar', Bar);
При этом использовались стандарты attributeChangedCallback
и observedAttributes
.Хотя переопределение функциональности setAttribute
работает, оно не является будущим.Если в будущем API-интерфейс для setAttribute
изменится, вам нужно будет не забыть исправить свой компонент.И выполнение этого со многими компонентами увеличивает долги разработчиков.
class Bar extends HTMLElement {
constructor() {
super();
this.attachShadow({mode: 'open'});
// Render the blank DOM
this.shadowRoot.innerHTML = '<div class="bar"><span>no value</span><div>';
this._span = this.shadowRoot.querySelector('span');
}
static get observedAttributes() {
// Indicate that we want to be notified
// when the `val` attribute is changed
return ['val'];
}
attributeChangedCallback(attrName, oldVal, newVal) {
if (oldVal != newVal) {
// If the value for the `val` attribute has changed
// then insert the value into the `<span>`
this._span.textContent = newVal || 'no value';
// OR: this._span.innerHTML = newVal || 'no value';
// But make sure someone has not tried to hit you
// with a script attack.
}
}
get val() {
return this._span.textContent;
}
set val(newVal) {
if (newVal == null || newVal === false || newVal === '') {
this.removeAttribute('val');
}
else {
this.setAttribute('val', newVal);
}
}
}
customElements.define('x-bar', Bar);
Этот второй метод не выполняет рендеринг всего DOM, он просто вставляет измененное значение атрибута в тег <span>
.
Он также предоставляет свойстватак что вы можете установить значение через атрибут, а также через JavaScript:
var el = document.querySelector('x-bar');
if (el) {
el.val = "A New String";
setTimeout(()=>el.val = '';,2000);
}