【问题标题】:Is it possible to keep the inner html of a custom element?是否可以保留自定义元素的内部 html?
【发布时间】:2018-02-12 01:43:24
【问题描述】:

使用自定义元素,我想为自定义元素内的元素设置样式,但是当我定义元素时,除了 shadow dom 之外的所有内容都消失了。

如何将内容从元素移动到 shadow dom?我已经在阴影中有一个包装元素 (<div class="wrapper">),但正在尝试使用

wrapper.innerHTML = this.innerHTML;

没用。

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);

【问题讨论】:

  • 欢迎来到 SO。请包括所有相关的代码行及其输出,并解释预期结果与您得到的结果。
  • @marekful 谢谢!我已经添加了 HTML 和 JS。

标签: javascript html web-component native-web-component


【解决方案1】:

如果您想从自定义元素外部控制 CSS,则只需使用 &lt;slot&gt;&lt;slot&gt; 将子元素嵌入到槽中,但将 CSS 控制权留给元素外部。

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>

如果你想从元素内部控制 CSS,那么你需要迁移子元素。但这不能在构造函数中完成。 This section of the spec 解释了构造函数的限制。

你需要移动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>

我建议避免使用innerHTML,因为这会清除任何可能已经存在的事件处理程序等。它实际上可能会更慢,具体取决于直接子代的数量。它还可能弄乱任何可能是自定义元素的子元素。

【讨论】:

  • 谢谢!这很有帮助!
【解决方案2】:

你应该稍后再做,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);

【讨论】:

  • 如果组件是通过 JavaScript 创建的,window.onload 可能已经触发。
猜你喜欢
  • 2020-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-08
  • 1970-01-01
  • 2011-12-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多