数据模型
了解 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
,并且特殊变量 url
、date
和 basename
被赋值,它会与在 _data
文件 中定义的其他数据合并。存储在 _components
文件夹中的组件会被添加到页面的 comp
变量下。插件(如 search
或 paginate
)定义的其他变量也会被添加。所以,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
- 用于分页搜索页面结果的函数。