最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Is it possible to keep the inner html of a custom element? - Stack Overflow

programmeradmin0浏览0评论

Using Custom Elements, I would like to style the elements inside the custom element, but when I define the element, everything besides the shadow dom disappears.

How do I move the content from the element to the shadow dom? I already have a wrapper element (<div class="wrapper">) inside the shadow, but trying to use

wrapper.innerHTML = this.innerHTML;

doesn't work.

HTML

<site-card>
  <section title>
    ...
  </section>
  <section body>
    ...
  </section>
  <section actions>
    <button class="modern small">Action</button>
    <button class="modern small">Action 2</button>
  </section>
</site-card>

JS

"use strict";
class cardElement extends HTMLElement {
    constructor() {
        super();
        var shadow = this.attachShadow({mode: 'open'});
        var wrapper = document.createElement('div');
        wrapper.setAttribute('class','wrapper');
        wrapper.innerHTML = this.innerHTML;
        var style = document.createElement('style');
        style.textContent = ... /* CSS removed to shorten. */
        shadow.appendChild(style);
        shadow.appendChild(wrapper);
    };
};
customElements.define('site-card', cardElement);

Using Custom Elements, I would like to style the elements inside the custom element, but when I define the element, everything besides the shadow dom disappears.

How do I move the content from the element to the shadow dom? I already have a wrapper element (<div class="wrapper">) inside the shadow, but trying to use

wrapper.innerHTML = this.innerHTML;

doesn't work.

HTML

<site-card>
  <section title>
    ...
  </section>
  <section body>
    ...
  </section>
  <section actions>
    <button class="modern small">Action</button>
    <button class="modern small">Action 2</button>
  </section>
</site-card>

JS

"use strict";
class cardElement extends HTMLElement {
    constructor() {
        super();
        var shadow = this.attachShadow({mode: 'open'});
        var wrapper = document.createElement('div');
        wrapper.setAttribute('class','wrapper');
        wrapper.innerHTML = this.innerHTML;
        var style = document.createElement('style');
        style.textContent = ... /* CSS removed to shorten. */
        shadow.appendChild(style);
        shadow.appendChild(wrapper);
    };
};
customElements.define('site-card', cardElement);
Share edited Mar 29, 2019 at 6:39 Christopher Bradshaw 2,7835 gold badges27 silver badges41 bronze badges asked Feb 12, 2018 at 1:43 James MJames M 5611 gold badge5 silver badges7 bronze badges 2
  • Wele to SO. Please include all relevant lines of code, its output and explain the expected result versus what you get. – marekful Commented Feb 12, 2018 at 1:54
  • @marekful Thanks! I have added the HTML and JS. – James M Commented Feb 13, 2018 at 2:46
Add a ment  | 

2 Answers 2

Reset to default 5

If you want to control the CSS from outside of the custom element then just use <slot>. <slot> embeds the children into the slot but leaves CSS control to outside the element.

class cardElement extends HTMLElement {
  constructor() {
    super();
    var shadow = this.attachShadow({mode: 'open'});
    var wrapper = document.createElement('slot');
    var style = document.createElement('style');
    style.textContent = `
    [title] {
      background-color: #060;
      color: #FFF;
    }
    [body] {
      background-color: #600;
      color: #FFF;
    }
    [actions] {
      background-color: #006;
      color: #FFF;
    }
    `;
    shadow.appendChild(style);
    shadow.appendChild(wrapper);
  };
};
customElements.define('site-card', cardElement);
[title] {
  background-color: #0F0;
  color: #000;
}
[body] {
  background-color: #F00;
  color: #000;
}
[actions] {
  background-color: #00F;
  color: #000;
}
<site-card>
  <section title>
    This is the title
  </section>
  <section body>
    This is the body
  </section>
  <section actions>
    <button class="modern small">Action</button>
    <button class="modern small">Action 2</button>
  </section>
</site-card>

If you want to control the CSS from inside the element then you need to migrate the children. But this can not be done in the constructor. This section of the spec explains the limitations on the constructor.

You need to move the children in the connectedCallback

class cardElement extends HTMLElement {
  constructor() {
    super();
    var shadow = this.attachShadow({mode: 'open'});
    this._wrapper = document.createElement('div');
    var style = document.createElement('style');
    style.textContent = `
    [title] {
      background-color: #060;
      color: #FFF;
    }
    [body] {
      background-color: #600;
      color: #FFF;
    }
    [actions] {
      background-color: #006;
      color: #FFF;
    }
    `;
    shadow.appendChild(style);
    shadow.appendChild(this._wrapper);
  };
  
  connectedCallback() {
    while(this.firstElementChild) {
      this._wrapper.appendChild(this.firstElementChild);
    }
  }
};
customElements.define('site-card', cardElement);
[title] {
  background-color: #0F0;
  color: #000;
}
[body] {
  background-color: #F00;
  color: #000;
}
[actions] {
  background-color: #00F;
  color: #000;
}
<site-card>
  <section title>
    This is the title
  </section>
  <section body>
    This is the body
  </section>
  <section actions>
    <button class="modern small">Action</button>
    <button class="modern small">Action 2</button>
  </section>
</site-card>

I would suggest avoiding using innerHTML since that will wipe out any event handlers, etc. that might already exist. It may actually be slower depending on the number of direct children. It could also mess up any children that may be custom elements.

You should do it a bit later, in window.onload:

class cardElement extends HTMLElement {
    constructor() {
        super();
        var shadow = this.attachShadow({ mode: 'open' });
        var wrapper = document.createElement('div');
        wrapper.setAttribute('class', 'wrapper');
        window.onload = () => {
            wrapper.innerHTML = this.innerHTML;
        };
        var style = document.createElement('style');
        style.textContent = ... /* CSS removed to shorten. */
        shadow.appendChild(style);
        shadow.appendChild(wrapper);
    }
};
customElements.define('site-card', cardElement);
发布评论

评论列表(0)

  1. 暂无评论