组件

通用的 Lume 组件

组件是可以用于其他模板的模板片段。一些模板引擎,如 Vento、Nunjucks、Pug 或 Liquid,具有代码复用的方法(如 includes、macros 等)。Lume 组件具有以下优点:

  • 它们与模板引擎无关。例如,你可以使用 JSX 或 JavaScript 创建组件,并在 Nunjucks 中使用它们。
  • 它们不仅可以生成 HTML 代码,还可以生成客户端所需的 CSS 和 JavaScript 代码。
  • 它们在任何地方都自动可用;无需手动导入。
  • 对于基于 ESM 模块的组件(如 JavaScript、TypeScript、JSX 或 TSX),这是热重载组件而无需停止和重启本地服务器的唯一方法。

Important

Lume 组件不在浏览器中运行。它们旨在构建时生成静态 HTML 代码。

对于交互式的客户端组件(带有 onclick 回调和类似功能),你可能需要使用 esbuild 插件 来编译你的 JavaScript 代码。但代码架构由你决定 (Lume 不是一个前端框架)。

创建你自己的组件

组件存储在 _components 目录中。与 _data 类似,你可以在不同的子目录中创建 _components 目录,以使它们仅对特定页面可用。要创建一个新组件,只需在此目录中创建一个文件,文件名为你组件的名称,扩展名为你想使用的模板引擎的扩展名。例如,一个用 Vento 编写的渲染按钮的组件可以存储在 _components/button.vto 中:

<button class="button">{{ text }}</button>

此组件在你的布局中通过 comp 变量可用(你可以在 _config.ts 中配置不同的变量名)。它是一个全局变量,包含所有组件。在我们的示例中,我们可以使用 comp.button() 函数渲染按钮组件:

<h1>欢迎来到我的网站。</h1>
{{ comp.button({ text: "登录" }) }}

请注意,该组件接受一个带有属性的对象。此组件在任何其他模板引擎中都可用。例如,JavaScript:

export default function ({ comp }) {
  return `
  <h1>欢迎来到我的网站。</h1>
  ${comp.button({ text: "登录" })}
`;
}

Vento 模板:

<h1>欢迎来到我的网站。</h1>
{{ comp.button({ text: "登录" }) }}

Nunjucks 模板:

<h1>欢迎来到我的网站。</h1>
{{ comp.button({ text: "登录" }) | safe }}

Eta 模板:

<h1>欢迎来到我的网站。</h1>
<%= comp.button({ text: "登录" }) %>

如果你正在使用 JSX 插件,Lume 组件可以像 React 组件一样使用:

export default function ({ comp }) {
  return (
    <>
      <h1>欢迎来到我的网站。</h1>
      <comp.Button text="登录" />
    </>
  );
}

请注意,使用基于文本的模板引擎(如 Vento 或 Nunjucks)创建的组件在 JSX 模板中无法按预期工作,因为 HTML 代码将被转义。要修复它,你必须使用 dangerouslySetInnerHTML 属性:

export default function ({ comp }) {
  // comp.Button 是一个 Vento 组件:它返回一个字符串,而不是一个 JSX 元素。
  return (
    <>
      <h1>欢迎来到我的网站。</h1>
      <div
        dangerouslySetInnerHTML={{ __html: <comp.Button text="登录" /> }}
      />
    </>
  );
}

嵌套组件

在 Vento 中,你可以通过这种方式嵌套组件:

{{ comp Container }}
  Container 组件的内容

  {{ comp Button }}
    这是 Container 组件内部的一个按钮
  {{ /comp }}
{{ /comp }}

在 Nunjucks 中,它非常相似:

{% comp "Container" %} Container 组件的内容 {% comp "Button" %}
这是 Container 组件内部的一个按钮 {% endcomp %} {% endcomp %}

组件的内容通过 content 变量传递:

<section class="container">{{ content }}</section>
<button>{{ content }}</button>

组件资源

组件可以导出 CSS 和 JS 代码。为此,组件需要导出 cssjs 变量。

在我们的示例中,我们可能想为按钮应用一些样式。在 Nunjucks 模板中,导出数据的方式是使用 front matter:

---
css: |
  .button {
    background-color: blue;
    color: white;
  }
---
<button class="button">{{ text }}</button>

此 CSS 代码将与其他已使用组件的 CSS 代码一起导出到你的 dest 文件夹中的 /components.css 文件中。请注意,如果组件未使用,则 CSS 代码将不会导出。这是一个有趣的功能,它允许你拥有一个包含许多组件的库,并且只导出你需要的 CSS 和 JS 代码。

组织你的组件

组件可以保存在子目录中。例如,button 组件可以保存在 ui 子目录中(在你的 src 文件夹中的 _components/ui/button.vto)。在这种情况下,你可以使用 comp.ui.button() 访问此组件。

组件内部的组件

组件可以在内部使用其他组件。假设我们要创建内部使用 buttonsearch 组件。让我们看一个使用 JS 模板的例子:

// _components/search.js

export const css = `
.search {
  background: gray;
  padding: 20px;
}
`;

export const js = `
import from "js/search.js"
`;

export default function ({ comp }) {
  return `
<form class="search">
  <label>
    Search:
    <input type="search" name="q">
  </label>
  ${comp.button({ text: "Submit" })}
</form>
`;
}

在此示例中,除了 HTML 代码外,该组件还导出了 CSS 和 JS 代码。

从 _config 文件注册组件

除了 _components 文件夹之外,你还可以在 _config 文件中使用 site.component() 函数动态注册组件。此函数接受两个参数:组件上下文和组件对象:

site.component("ui", {
  name: "button",
  css: ".btn { background: blue; color: white }",
  render({ text }) {
    return `<button class="btn">${text}</button>`;
  },
});

现在,你可以像往常一样使用该组件:

{{ comp.ui.button({ text: "登录" }) }}