如何将 Web 组件分离到单个文件并加载它们?

IT技术 javascript html templates web-component separation-of-concerns
2021-02-20 14:59:50

我有一个 web 组件x-counter,它在一个文件中。

const template = document.createElement('template');
template.innerHTML = `
  <style>
    button, p {
      display: inline-block;
    }
  </style>
  <button aria-label="decrement">-</button>
    <p>0</p>
  <button aria-label="increment">+</button>
`;

class XCounter extends HTMLElement {
  set value(value) {
    this._value = value;
    this.valueElement.innerText = this._value;
  }

  get value() {
    return this._value;
  }

  constructor() {
    super();
    this._value = 0;

    this.root = this.attachShadow({ mode: 'open' });
    this.root.appendChild(template.content.cloneNode(true));

    this.valueElement = this.root.querySelector('p');
    this.incrementButton = this.root.querySelectorAll('button')[1];
    this.decrementButton = this.root.querySelectorAll('button')[0];

    this.incrementButton
      .addEventListener('click', (e) => this.value++);

    this.decrementButton
      .addEventListener('click', (e) => this.value--);
  }
}

customElements.define('x-counter', XCounter);

这里模板被定义为使用 JavaScript 并且 html 内容被添加为内联字符串。有没有办法将模板与x-counter.html文件、cssx-counter.css和相应的 JavaScript 代码分开xcounter.js并加载到 index.html 中?

我查找的每个示例都混合了 Web 组件。我想要关注点分离,但我不确定如何使用组件来做到这一点。你能提供一个示例代码吗?谢谢。

1个回答

在主文件中,用于<script>加载 Javascript 文件x-counter.js

在 Javascript 文件中,用于fetch()加载 HTML 代码x-counter.html

在 HTML 文件中,用于<link rel="stylesheet">加载 CSS 文件x-counter.css

CSS文件: x-counter.css

button, p {
    display: inline-block;
    color: dodgerblue;
}

HTML 文件: x-counter.html

<link rel="stylesheet" href="x-counter.css">
<button aria-label="decrement">-</button>
    <p>0</p>
<button aria-label="increment">+</button>

Javascript 文件: x-counter.js

fetch("x-counter.html")
    .then(stream => stream.text())
    .then(text => define(text));

function define(html) {
    class XCounter extends HTMLElement {
        set value(value) {
            this._value = value;
            this.valueElement.innerText = this._value;
        }

        get value() {
            return this._value;
        }

        constructor() {
            super();
            this._value = 0;

            var shadow = this.attachShadow({mode: 'open'});
            shadow.innerHTML = html;

            this.valueElement = shadow.querySelector('p');
            var incrementButton = shadow.querySelectorAll('button')[1];
            var decrementButton = shadow.querySelectorAll('button')[0];

            incrementButton.onclick = () => this.value++;
            decrementButton.onclick = () => this.value--;
        }
    }

    customElements.define('x-counter', XCounter);
}

主文件: index.html

<html>
<head>
    <!-- ... -->
    <script src="x-counter.js"></script>
</head>
<body>
    <x-counter></x-counter>
</body>
</html>
真的很好的答案!假设您要对 x-count.js Web 组件进行单元测试?你会怎么做?例如,如果您想使用 karma 进行非常基本的单元测试,只是为了检查 webcomponet 是否已呈现,如何实现?
2021-04-20 14:59:50
@JimC 我不使用 Karma,但我想您可以像检查任何其他元素一样检查自定义元素的 html 内容。我知道你可以用 Chai.js + Selenium Webdriver 做到这一点。
2021-04-23 14:59:50
我写了一篇 Medium 文章 - 其中一个可能的解决方案是roshan-khandelwal.medium.com/web-components-c7aef23fe478
2021-04-24 14:59:50
TypeError: failed to fetch在 Chrome 扩展程序中尝试将 html 文件提取到 js 类时遇到问题
2021-04-29 14:59:50