#javascript #html #web-component
#javascript #HTML #веб-компонент
Вопрос:
Я пытаюсь привести пример пользовательских веб-компонентов из MDN. Итак, я закончил с этим кодом
class Info extends HTMLElement
{
constructor()
{
super();
const shadow = this.attachShadow({mode: 'open'});
const wrapper = document.createElement('span');
wrapper.setAttribute('class', 'wrapper');
const icon = document.createElement('span');
icon.setAttribute('class', 'icon');
icon.setAttribute('tabindex', 0);
const info = document.createElement('span');
info.setAttribute('class', 'info');
// Take attribute content and put it inside the info span
const text = this.getAttribute('data-text');
info.textContent = text;
console.log(JSON.stringify(this.attributes['img']));
// Insert icon
const img = document.createElement('img');
img.src = this.hasAttribute('img') ? this.getAttribute('img') : 'img/default.png';
icon.appendChild(img);
// Create some CSS to apply to the shadow dom
const style = document.createElement('style');
style.textContent = `
.wrapper { position: relative; }
img { width: 1.2rem; }
`;
// Attach the created elements to the shadow dom
shadow.appendChild(style);
shadow.appendChild(wrapper);
wrapper.appendChild(icon);
wrapper.appendChild(info);
}
}
customElements.define('a-info', Info);
<html>
<head></head>
<body>
<a-info img="img/alt.png" data-text="Your card."></a-info>
</body>
</html>
Это почти работает. Элемент создается, за исключением this.getAttribute('data-text')
возвратов undefined .
Я запускаю его локально в Firefox.
Не мог бы кто-нибудь объяснить, в чем проблема с этим примером, пожалуйста?
Комментарии:
1. Я провел некоторое расследование, и, похоже
getAttribute()
, возвращает правильное значение при вызове изconnectedCallback()
.
Ответ №1:
Да, на этапе конструктора нет доступного DOM
смотрите: https://andyogo.github.io/custom-element-reactions-diagram /
И не слишком полагайтесь на официальную документацию, она раздута, а иногда и просто неверна:
<script>
class Info extends HTMLElement {
constructor() {
let createElement = (name, className) => {
let el = document.createElement(name);
if (className) el.classList.add(className);
return el;
}
// yes you can add code *before* super()
const style = createElement('style');
style.textContent = `.wrapper {position:relative}img {width: auto}`;
const wrapper = createElement('span', 'wrapper');
const icon = createElement('span', 'icon');
icon.setAttribute('tabindex', 0);
super() // set AND return this scope
.attachShadow({mode: 'open'}) // set AND return this.shadowRoot
.append(style,wrapper);
this.info = createElement('span', 'info');
this.img = createElement('img');
icon.append(this.img);
wrapper.append(icon, this.info);
}
connectedCallback() {
this.info.textContent = this.getAttribute('data-text') || "card?";
this.img.src = this.getAttribute('img') || 'https://via.placeholder.com/42';
}
}
customElements.define('a-info', Info);
</script>
<a-info></a-info>
<a-info img="https://via.placeholder.com/110" data-text="Card #1"></a-info>
<a-info img="https://via.placeholder.com/120" data-text="Card #2"></a-info>
Ответ №2:
Во время constructor
фазы DOM еще нет. connectedCallback
вызывается, когда веб-компонент помещается в DOM, и тогда вы можете получить к нему доступ. Используется connectedCallback
для манипуляций с DOM и прослушивания событий.