Quartz 中的 Obsidian Bases 支持:用 `.base` 文件构建交互式数据库视图
2026/9/15 18:02:01 网站建设 项目流程

Quartz 中的 Obsidian Bases 支持:用.base文件构建交互式数据库视图

【免费下载链接】quartz🌱 a fast, batteries-included static-site generator that transforms Markdown content into fully functional websites项目地址: https://gitcode.com/GitHub_Trending/qua/quartz

Quartz(一个将 Markdown 内容转换为完整网站的静态站点生成器)在 v5 中引入了对 Obsidian Bases 的原生支持:它能够读取 vault 中的.base文件,将其定义的查询解析为匹配的笔记集合,并以表格、列表、卡片、画廊、看板等可配置视图渲染成交互式"数据库"页面。读完本文,你将掌握在 Quartz 中启用 BasesPage 插件、理解.base文件语法(过滤器、公式、属性、视图)、自定义视图渲染器,以及处理与unlisted页面协作的全部实战技能。

Bases 是什么

Bases 是 Obsidian 桌面端 1.8.0(2025-04-15 发布)引入的功能:.base文件描述了针对 vault 中笔记的查询(filters),并把这些查询结果以可配置的视图形式呈现,例如表格(table)、列表(list)、卡片(cards)、画廊(gallery)和看板(board)。Quartz 将这种能力移植到了静态站点生成流程中,使文档站点本身也能拥有"可交互的数据库式视图"。

在 Quartz 中,Bases 支持由BasesPage插件提供,它属于"Page Type + Component"双重类别:既会针对每个.base文件生成页面,也会渲染页面中的视图 UI。从源码结构看,.base文件的渲染与.canvas文件处于同一套"虚拟页面"机制中——pageTypes/dispatcher.ts 在处理![[file.base]]这类嵌入(transclusion)时,会与.canvas一起解析跨虚拟页面的嵌入;emit.ts 也将 bases 页面与 tag 页面、folder 页面并列为由 page type 插件生成的虚拟页面。

快速启用

Bases 支持默认已随 Quartz 模板启用。在 quartz/cli/templates/default.yaml 中可以看到它被声明为默认插件:

- source: "@quartz-community/bases-page" enabled: true options: {} order: 50

如果你使用的是自定义配置,按标准流程安装即可:

npx quartz plugin add github:quartz-community/bases-page

该插件同样出现在blog.yamlobsidian.yamlttrpg.yaml等模板中(quartz/cli/templates),并在各模板的layout.byPageType.bases中留出了页面布局配置入口(默认空配置)。

[!note] 有关插件的增删与配置方式,详见 Configuration 文档的 Plugins 章节。

内置视图与核心功能

BasesPage 插件渲染的视图具备以下能力(详见 BasesPage 插件文档):

  • Table 视图:列可排序,支持字符串、数字、布尔值、数组、链接等类型的自动渲染。
  • List 视图:紧凑列表,每条目附带元数据徽章(chips)。
  • Cards 视图:卡片布局,可选的图片属性支持。
  • Map 视图:为未来基于地图的可视化预留的占位视图。
  • 多视图:单个.base文件可以定义多个视图,以可切换的标签页展示。
  • 过滤器(Filters):支持and/or/not操作符的递归过滤器树。
  • 公式(Formulas):通过表达式计算派生属性。
  • 汇总(Summaries):列级聚合,如 Sum、Average、Min、Max、Median 等。
  • 属性配置:为属性自定义显示名称。
  • 链接渲染:单元格内的 wikilinks 与 Markdown 链接渲染为可点击链接。

一个真实的.base文件:仓库演示

Quartz 文档站自身的 docs/Base.base 就是一个完整的示例,它同时演示了过滤器、公式、属性显示名与多种视图的写法:

filters: and: - file.ext == "md" formulas: doc_type: | if(file.hasTag("plugin/transformer"), "transformer", if(file.hasTag("plugin/emitter"), "emitter", if(file.hasTag("plugin/filter"), "filter", if(file.hasTag("component"), "component", if(file.inFolder("features"), "feature", if(file.inFolder("advanced"), "advanced", if(file.inFolder("plugins"), "plugin", if(file.inFolder("getting-started"), "getting-started", if(file.inFolder("cli"), "cli", "guide"))))))))) last_modified: file.mtime.relative() section: | if(file.inFolder("plugins"), "plugins", if(file.inFolder("features"), "features", if(file.inFolder("advanced"), "advanced", if(file.inFolder("getting-started"), "getting-started", if(file.inFolder("cli"), "cli", if(file.inFolder("tags"), "tags", "core")))))) properties: title: displayName: Title formula.doc_type: displayName: Type formula.last_modified: displayName: Updated formula.section: displayName: Section views: - type: table name: All Documentation groupBy: property: formula.section direction: ASC order: - file.name - title - formula.doc_type - formula.section - formula.last_modified sort: - property: formula.doc_type direction: ASC - property: file.name direction: ASC columnSize: file.name: 185 note.title: 268 formula.doc_type: 146 formula.section: 276 - type: table name: Plugins filters: or: - file.hasTag("plugin/transformer") - file.hasTag("plugin/emitter") - file.hasTag("plugin/filter") groupBy: property: formula.doc_type direction: ASC order: - file.name - title - formula.doc_type - formula.last_modified - type: list name: Recently Updated order: - file.name - formula.last_modified limit: 15 - type: board name: By Type (Board) groupBy: property: formula.doc_type direction: ASC order: - file.name - title - formula.last_modified - type: gallery name: Gallery order: - title - formula.doc_type - formula.section limit: 30 - type: cards name: Cards order: - file.name - title - formula.doc_type - formula.section - formula.last_modified limit: 24 - type: cards name: Image Cards filters: and: - file.folder == "plugins" - "!image.isEmpty()" order: - file.name image: note.image cardSize: 220 imageAspectRatio: 1

这个示例覆盖了.base语法的核心要素,值得逐段拆解:

filters:查询哪些笔记

顶层filtersand/or/not组合表达式。示例中file.ext == "md"只纳入 Markdown 文件;"Plugins" 视图则用or组合三个 tag 判断;"Image Cards" 视图通过"!image.isEmpty()"(字符串形式的取反表达式)只显示有图片的插件页。

formulas:计算派生属性

公式表达式以内联字符串或多行字符串(|块)形式出现。示例演示了三类典型用法:

  • 基于 tag 与目录的多重嵌套if,把页面归类为 transformer / emitter / filter / component / feature / plugin / guide 等类型;
  • file.mtime.relative()计算相对修改时间;
  • 目录判断函数file.inFolder(...)用于划分区块。

properties:显示名定制

properties节点为属性指定displayName。注意formula.doc_type这种键名——公式计算结果被当作属性参与展示与排序,这正是公式系统的核心用法。

views:一文件多视图

单个.base文件可声明多个views,每个视图有自己的typenamefiltersgroupByorder(列顺序)、sort(排序规则)、limitcolumnSizeimagecardSize等配置。示例文件同时声明了 table、list、board、gallery、cards 五种类型共 8 个视图,最终在页面上以可切换标签页呈现。

配置选项

BasesPage 接受以下配置项(完整列表见 BasesPage 插件文档):

选项类型默认值说明
defaultViewTypestring"table".base文件未指定视图类型时的默认视图。
linkResolutionstring"shortest"视图渲染器中内部链接的解析方式,取值"absolute"/"relative"/"shortest",应与 CrawlLinks 插件 的markdownLinkResolution保持一致。
customViewsobject{}自定义视图渲染器映射,键为视图类型名,可覆盖内置渲染器或注册新类型,需要 TS override。

默认配置(零参数启用):

- source: github:quartz-community/bases-page enabled: true

自定义视图渲染器(TS override)

自定义视图需要在quartz.ts中通过 TS override 实现。插件注册(包括 Bases 视图注册这类副作用)必须在loadQuartzConfig()之前完成——这与 config-loader.ts 中"部分插件依赖副作用进行注册"的加载机制相印证:

import * as ExternalPlugin from "./.quartz/plugins" // Must be placed before loadQuartzConfig() ExternalPlugin.BasesPage({ defaultViewType: "table", customViews: { myView: ({ entries, view, basesData, total, locale }) => { // return JSX }, }, })

自定义视图渲染器收到entries(查询结果条目)、view(视图配置)、basesData(基础数据)、total(条目总数)、locale(国际化信息)等参数,返回 JSX 即可。

unlisted页面的协作

BasesPage 遵循由 UnlistedPages 插件 与 EncryptedPages 插件 写入的file.data.unlisted约定:

  • 被标记为unlisted: true的页面(以及stealth: true的加密页面)会从所有base 视图(table、list、board、cards、gallery 及任何自定义视图)中排除,无论 base 的过滤表达式是否匹配它们;
  • unlisted 页面也无法通过可见页面公式中的.asFile()被解引用。

构建时渲染的固有限制

Base 视图是在构建期服务端渲染(server-side rendered)的 HTML,不会在访问者解密加密页面后在客户端更新。与之对比,Graph、explorer、search 会从打了补丁的内存内容索引重新水合(re-hydrate),从而在整个浏览器会话中显示新解锁的页面;而 base 视图不会,因为它们是在构建时物化(materialized)的,unlisted 页面早已被排除。访问者成功解密一个可揭示(revealable)的加密页面后,该页面会出现在 graph、explorer 和 search 中,但在站点重新构建并将该页面列入之前,不会出现在任何 base 视图中。这与 backlinks、recent notes、folder listings、tag listings 面临的是同一种结构性限制。

渲染管线中的位置

从源码角度可以看到 Bases 参与渲染管线的几个关键节点:

  • renderPage.tsx:renderPage在渲染 transclusion 后执行"插件提供的树变换(tree transforms)",注释明确提到其用途之一是"解析内联的 bases codeblocks";
  • pageTypes/dispatcher.ts:.base文件与.canvas文件一样,作为虚拟页面参与![[file.base]]式嵌入的解析;
  • config-loader.ts:插件加载器在合并配置时会执行具有副作用的插件注册(Bases 视图注册即为此类);
  • emit.ts:bases 页面与 tag 页面、folder 页面一样,属于 page type 插件生成的虚拟页面,走统一发射流程。

这套机制保证了.base文件既能作为独立页面被生成,也能被嵌入到其他笔记(如本文所在的 Features 文档中通过![[Base.base]]内嵌演示),并遵守与其他页面类型一致的构建与布局约定。

小结

Quartz 的 Bases 支持将 Obsidian 的数据库式视图能力带入了静态站点:filters定义查询、formulas计算派生字段、properties定制显示名、views声明多类型多标签的展示层,而 BasesPage 插件在构建期把这些声明渲染为可排序、可分组、带汇总的服务端 HTML。配合defaultViewTypelinkResolutioncustomViews三个配置项,你可以完全控制视图的默认形态、内部链接解析方式与自定义渲染逻辑;同时,unlisted约定与构建时渲染特性决定了它在隐私页面场景下的行为边界。上述演示文件 docs/Base.base 可直接作为编写自己.base文件的语法参考。

【免费下载链接】quartz🌱 a fast, batteries-included static-site generator that transforms Markdown content into fully functional websites项目地址: https://gitcode.com/GitHub_Trending/qua/quartz

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询