Как получить доступ к тексту содержимого в пользовательском элементе HTML? - PullRequest
0 голосов
/ 17 декабря 2018

При создании пользовательского HTML-элемента со встроенной пользователем строкой JSON (хотя тип строки здесь не имеет значения) ...

<my-elem>
  { "some":"content" }
</my-elem>

Я бы хотел JSON.parse вот так...

class MyElement extends HTMLElement {
    constructor() {
        super();
        this.root = this.attachShadow({ mode:'open' });
        this.root.appendChild(template.content.cloneNode(true));
    }
    connectedCallback() {
        JSON.parse(this.innerHTML);
    }
}
customElements.define('my-elem', MyElement);

const template = document.createElement('template');
template.innerHTML =  `irrelevant`;

... и получить идеальный результат с Firefox v.63.

Но при работе с Chrome v.71 я получаю

Uncaught SyntaxError: Unexpected end of JSON input

из-за this.innerHTML, возвращающего пустую строку.

Я также пытался использовать другие методы DOM для доступа к текстовому контенту, но все они тоже не сработали.

Теперь я довольно невежественен, какчтобы заставить это работать с Chrome.

Кстати: использование <slot> не поможет, так как я не хочу отображать текстовый контент ... только доступ к нему для анализа.

Решено :

  • Поместите определение шаблона перед определением класса.
  • Убедитесь, что скрипт, определяющий пользовательский элемент, вставлен за всеми экземплярами пользовательских элементов в документе HTML,

Ответы [ 2 ]

0 голосов
/ 17 декабря 2018

Почему бы не сделать его более гибким и поддерживать как атрибут src, так и свойство data?

class MyElement extends HTMLElement {
  static get observedAttributes() {
    return ['src'];
  }

  constructor() {
    super();
    this.attachShadow({ mode:'open' });
    this._data = {
      name: '',
      address: ''
    };
  }

  attributeChangedCallback(attrName, oldVal, newVal) {
    if (oldVal !== newVal) {
      const el = this;
      fetch(newVal).then(resp => resp.json()).then(
        data => {
          el._data = data;
          el.render();
        }
      );
    }
  }

  render() {
    this.shadowRoot.innerHTML = `
    <div>
      <div>${this._data.name}</div>
      <div>${this._data.address}</div>
    </div>`;
  }

  set address(val) {
    this._data.address = val;
    this.render();
  }
  
  set name(val) {
    this._data.name = val;
    this.render();
  }
}

customElements.define('my-elem', MyElement);


setTimeout(() => {
  let el = document.querySelector('my-elem');
  el.name = 'The Joker';
  el.address = 'Gothem';

  setTimeout(() => {
    el.setAttribute('src', 'data:application/json,%7B%22name%22:%22Thanos%22,%22address%22:%22Titan%22%7D')
  }, 1500);
}, 1500);
<my-elem src="data:application/json,%7B%22name%22:%22Darth%20Vader%22,%22address%22:%22Death%20Star%22%7D"></my-elem>

Преимущество использования атрибута src заключается в том, что вы можете передать JSON или URL-адрес, который вернет JSON.

Свойства позволяют вам изменять отдельные значения в вашей DOM.

Изменение всего innerHTML может быть неправильным, но при небольшом количестве DOM это может быть.Вы также можете изменить отдельные значения в DOM или использовать что-то вроде LitHtml.

0 голосов
/ 17 декабря 2018

Вам следует подождать, пока контент не появится.

В большинстве случаев простая задержка может решить проблему:

connectedCallback() {
    setTimeout( () => JSON.parse(this.innerHTML) )
}

Альтернативно, на самом деле <slot> может помочь с slotchange событие.Вы можете скрыть рендеринг или удалить контент, если он вам не нужен.

...