如何访问HTML自定义元素中的内容文本?

时间:2018-12-16 22:17:22

标签: javascript html shadow-dom

在创建带有用户嵌入的JSON字符串的HTML自定义元素时(尽管此处的字符串类型无关紧要)...

<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 :(得分:0)

您应该等待内容出现。

在大多数情况下,只需延迟一下即可解决问题:

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

或者,实际上<slot>可以帮助解决slotchange事件。您可以隐藏渲染或删除不想要的内容。

答案 1 :(得分:0)

为什么不使其更加灵活并同时支持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,也可以传递将返回JSON的URL。

这些属性允许您更改DOM中的单个值。

更改整个innerHTML可能不是正确的选择,但是使用少量DOM可能是正确的选择。您还可以在DOM上更改单个值,或使用类似LitHtml的方法。