将 HTML 和 CSS 与 Javascript 点亮元素分开

Seperating HTML and CSS from Javascript Lit Element

我们正在使用 Lit Element,我们的组件文件变得相当大,因为我们必须在 .js 文件中编写样式和 html。有没有办法将它们拆分成单独的文件,然后将它们导入到我们的组件中?这样做的最佳方法是什么? HTML 和 CSS 尤其让我们的工作流程变得困难,因为我们的文件变得过于臃肿。

更新:Supersharp 的建议帮助我分离了 CSS 和 html 模板,但我在绑定 html 模板时遇到问题具有指定的属性。我有一个服务文件,它正在对我指定的文件发出 XML 请求,我将它们导入到我的组件文件中。这是我的组件:

import { LitElement, html} from '@polymer/lit-element';

import HtmlLoader from './Service/HtmlLoader';

class TestAnimatedButtonElement extends LitElement {

  static get properties() {
    return {
      _text: {
        type: String
      }
    }
  }

  constructor() {
    super();
    this.htmlTemplate = HtmlLoader.prototype.getHtmlTemplate('/src/Components/ExampleElements/test-animated-button-element.html');
  }

  render(){
    this.htmlTemplate.then( template => this.shadowRoot.innerHTML = template)
    return html( [this.htmlTemplate] );
  }

  handleButton(e) {
    //e.preventDefault();
    console.log('Button pressed');
  }
}
customElements.define('test-animated-button-element', TestAnimatedButtonElement);

这是我的 html 文件:

<link rel="stylesheet" href="src/Components/animatedButton/animated-button-element.css"/>
<a href="#" class="btn btn--white btn--animated" @click="${(e) => this.handleButton(e)}">${this._text}</a>

这是我用来制作 XMLHttpRequest:

的服务文件
export default class HtmlLoader {

    xhrCall(url){
      return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open("GET", url);
        xhr.onload = () => resolve(xhr.responseText);
        xhr.onerror = () => reject(xhr.statusText);
        xhr.send();
      });
    }

    getHtmlTemplate(url) {
       return this.xhrCall(url);
    }

}

您可以分别导入 CSS 和 HTML 部分。

CSS

在 HTML 代码中使用 <link rel="stylesheet"> 元素。

HTML

您可以使用 HTML Imports(已弃用)或 XMLHttpRequest 或 fetch(),如 post 关于 的解释。

更新

有了 XMLHtpRequest,您将在 Promise 中得到答案。

render(){
    this.htmlTemplate.then( template =>
        this.shadowRoot.innerHTML = template
    )
}

这是 ES 模块的缺点,这就是为什么 Google 推动 HTML 导入这么久,尽管其他浏览器供应商坚决反对它们。

您可以将 CSS 和 JS 分开,但如果您在 运行 时获取它们,则会向浏览器添加额外的往返行程。特别是你的模板是异步检索的,如果你等待它们,你会在你做的时候阻塞主 JS 线程,如果你 await 它们你会破坏 lit-element 因为它期望根模板同步。

可以(但不应该)使用until:

import { until } from 'lit-html/directives/until';

...

render(){
    return html`until(
        this.loadTemplate(
            '/src/Components/ExampleElements/test-animated-button-element.html',
            this.foo, 
            this.bar), html`Loading...`)`;
}

async loadTemplate(path, ...parts) {
    // You're using templates you can use fetch, instead of XMLHttpRequest
    const r = await fetch(path, { method: 'GET', credentials: 'same-origin' });
    if(r.ok)
         return html(await r.text(), parts);

    return html`Not Found: ${path}`
}

但是,我注意到您使用的是裸模块(即开头没有 . 结尾没有 .js),因此您不能将此文件直接提供给浏览器(none 还可以处理裸模块)。简而言之:您必须拥有可以转动的东西:

import { LitElement, html} from '@polymer/lit-element';

进入:

import { LitElement, html } from '../../node_modules/@polymer/lit-element/lit-element.js';

或者将它们捆绑到一个文件中。鉴于您正在这样做,为什么不让您的捆绑器(Webpack、RollupJS、Browserify 等)在 构建时间 将您的 CSS 和 HTML 导入到文件中?

最后,使用这些解决方案中的任何一个,您都会失去写入时间部分<->html 关系,这对 CSS 无关紧要,但会使 HTML 部分变得更重要更难 develop/maintain。对于像 lit 这样的库,你 想要 你的 HTML 在你的 JS 中,出于与 JSX/React/Preact 工作得很好的相同原因。如果您的文件太大,那么我认为解决方案不是将它们拆分为 JS/CSS/HTML - 而是将它们拆分为更多组件。

因此,例如,假设您有一个巨大的 <product-detail> 控件...

不要

  • 产品-detail.js
  • 产品-detail.html
  • 产品-detail.css

  • 产品-detail.js
  • 产品详情-dimensions.js
  • 产品详情-specs.js
  • 产品详情-parts.js
  • 产品详情-preview.js
  • 等等

分解每个组件以完成特定任务。 lit-element 的全部要点是让所有这些尽可能简单地创建,而你需要很多小的、独立的组件。