数据模型

了解 Lume 页面数据模型

内容

当 Lume 加载页面时,页面的所有内容都会被转换为一个 Data 对象。 这个对象可能包含 content 变量,其中是文件的内容。例如,以下 markdown 文件:

**页面** 内容

会被转换为如下对象:

{
  content: "**页面** 内容",
}

如果文件有额外的变量,例如 front matter,它们也会被添加到 Data 对象中:

---
title: 页面标题
---

**页面** 内容

现在标题被添加到页面数据中:

{
  title: "页面标题",
  content: "**页面** 内容",
}

对于 Lume 可以加载的任何文件,这个模型都是相同的。即使是图片也一样:假设你使用了 transform_images 插件来加载和转换数据。文件内容会被加载并存储在 content 变量中:

{
  content: Uint8Array(...)
}

如果你为页面使用 JavaScript 模块,它们也会被转换为这个模型。例如:

export const title = "页面标题";

export default function ({ title }) {
  return `<h1>${title}</h1>`;
}

这会被转换为:

{
  title: "页面标题",
  content: function ({title}) {
    return `<h1>${title}</h1>`;
  }
}

请注意,默认导出的内容存储在 content 变量中(与上面的 markdown 示例相同)。你可以将函数导出为 content 而不是作为 default 导出,但不能同时导出两者:

// 这样可以
export function content({ title }) {
  return `<h1>${title}</h1>`;
}
// 混合 content 和 default 将不起作用!!
export const content = "页面内容";

export default function ({ title }) {
  return `<h1>${title}</h1>`;
}

content 变量并非总是存在。某些数据格式,例如 .yaml.json 可能不会导出 content 变量。例如,以下在 YAML 文件中定义的页面:

layout: main.vto
title: 页面标题
description: 页面描述

会被转换为:

{
  layout: "main.vto",
  title: "页面标题",
  description: "页面描述",
}

在这个例子中,没有 content 变量,这也没问题。content 变量仅仅是一种约定,用于可以导出匿名变量的格式,例如 ES 模块中的默认导出或带有 front matter 和下方内容的文件。

额外的变量

一旦文件被加载并转换为 Data 模型,Lume 会自动添加 3 个变量:

  • url: 定义页面的输出 URL。
  • date: 定义页面的日期。
  • basename: 定义页面的 basename(仅在 Lume 2 中)。

你可以将 url 定义为绝对路径或相对路径,甚至是一个函数(更多信息请参阅 URLs 文档)。Lume 会将这个值解析为一个字符串,如果 url 是 false,则页面会被忽略。

date 变量可以在 文件名中定义 (例如 2023-11-30_hello-world.md),使用 页面变量 等方式定义。Lume 会尝试解析它,并将文件创建日期作为后备方案。

basename 类似于文件名。它可以用来更改 URL 的最后一部分。

例如,以下 markdown 文件保存在 posts/2023-11-30_hello-world.md 文件中:

Hello **world**

这会被转换为:

{
  url: "/posts/hello-world/",
  date: Date("2023-11-30 00:00:00"),
  basename: "hello-world",
  content: "Hello **world**"
}

数据继承

一旦页面被加载,转换为 Data,并且特殊变量 urldatebasename 被赋值,它会与在 _data 文件 中定义的其他数据合并。存储在 _components 文件夹中的组件会被添加到页面的 comp 变量下。插件(如 searchpaginate)定义的其他变量也会被添加。所以,markdown 文件:

Hello **world**

会被转换为:

{
  url: "/posts/hello-world/",
  date: Date("2023-11-30 00:00:00"),
  basename: "hello-world",
  content: "Hello **world**",
  search: Searcher(),
  paginate: Paginate(),
  comp: {}
  // etc...
}

生成器

如果 content 变量是一个 Generator function,Lume 将会在此时生成页面。更多关于 生成页面 的信息。

例如,假设我们有以下生成器页面:

export const layout = "main.vto";

export default function* () {
  const numbers = [1, 2, 3];

  for (const number of numbers) {
    yield {
      url: `/page-${number}/`,
      content: `This is the page number ${number}`,
    };
  }
}

这将生成以下三个页面:

{
  layout: "main.vto",
  url: "/page-1/",
  content: "This is the page number 1",
  date: Date(),
  basename: "page-1",
  search: Searcher(),
  paginate: Paginate(),
  comp: {}
}

{
  layout: "main.vto",
  url: "/page-2/",
  content: "This is the page number 2",
  date: Date(),
  basename: "page-2",
  search: Searcher(),
  paginate: Paginate(),
  comp: {}
}

{
  layout: "main.vto",
  url: "/page-3/",
  content: "This is the page number 3",
  date: Date(),
  basename: "page-3",
  search: Searcher(),
  paginate: Paginate(),
  comp: {}
}

预处理器

如果你在 _config 文件中定义了 任何预处理器,它将在这个阶段执行。预处理器允许在渲染之前修改 Data 对象。预处理器接收 Page 实例,而 Data 对象存储在 Page.data 属性中。

// _config.js

site.preprocess([".html"], (pages) => {
  for (const page of pages) {
    const data = page.data; // 获取 Data 对象
    data.title += " - My site name"; // 修改 title 变量
  }
});

渲染

这是渲染 Data 对象并将结果保存在 Page.content 属性中的过程。在 Data 对象中定义的任何变量都将在模板引擎中可用。

<!-- 渲染 title 变量 -->
<h1>{{ title }}</h1>

处理

虽然 Page.data 返回页面的 Data 对象,但 Page.content 返回渲染数据的结果,或者换句话说,将输出到目标文件夹的内容。你可以使用处理器来修改此内容:

site.process([".html"], (page) => {
  // 获取渲染后的内容
  const content = page.content;

  // 修改内容
  page.content = content + "\n<!-- Created by Óscar Otero -->";
});

如果页面内容是 HTML 代码,则可以使用 document 属性和 DOM API 来修改内容:

site.process([".html"], (page) => {
  // 获取 DOM
  const document = page.document;

  // 修改内容
  document.querySelectorAll('a[href^="http"]').forEach((link) => {
    link.setAttribute("target", "_blank");
  });
});

数据约定

Data 对象中,你可以存储所有你想要的变量,并使用你选择的结构。但是,Lume 理解一些特殊的变量(请参阅 标准变量文档),以及其他被认为是良好实践或常见约定的变量。以下是所有这些变量的列表:

url string
如果缺失,Lume 会自动创建。
date Date
如果缺失,Lume 会自动创建。
basename string
如果缺失,Lume 会自动创建。
tags string[]
由 Lume 自动标准化。用于分配标签到页面。
draft boolean
如果为 true,页面将被忽略。使用环境变量 LUME_DRAFTS=true 来显示草稿页面。
renderOrder number
用于配置页面的渲染顺序。
content string | Uint8Array | function | object
页面的原始内容。
children string | Uint8Array | function | object
在被布局包裹之前渲染的内容。
layout string
用于渲染页面的布局文件。
templateEngine string | string[]
配置用于渲染页面的不同模板引擎。
mergedKeys Record<string, "array" | "stringArray" | "object">
配置某些数据键如何与父数据合并。
onDemand boolean
是否按需渲染此页面。
lang string
页面的语言。
type string
页面的类型(post, article 等)。用于在不同的集合中对页面进行分组。
id string | number
页面的 id。用于标识类型内的页面。
comp object
此页面可用的组件(来自 _components 文件夹)。
page Page
当前的 Page 实例。
alternates Data[]
具有相同内容翻译成其他语言的其他页面。
search Searcher
用于搜索页面和文件的实用程序类。
paginate function
用于分页搜索页面结果的函数。