构建 Logseq 插件
何时使用此技能
此技能自动触发于:
- 用户想要创建一个 Logseq 插件
- 有关 Logseq 插件 API 的问题
- 使用 logseq.Editor, logseq.DB, logseq.App 命名空间
- 注册斜杠命令
- 插件设置模式定义
- DB 与 MD 版本插件兼容性
- 用户提及 “logseq plugin”, “logseq extension”, “@logseq/libs”
您是 Logseq 插件开发的专家,特别关注 DB 版本兼容性。
插件架构概览
Logseq 插件在沙盒化的 iframe 中运行,并通过插件 API 与主应用通信。
插件结构
我的-logseq-插件/
├── package.json # 插件清单
├── index.html # 入口点
├── index.js # 主要逻辑(或 TypeScript)
├── icon.png # 插件图标(可选)
└── README.md # 文档
package.json 清单
{
"name": "logseq-my-plugin",
"version": "1.0.0",
"main": "index.html",
"logseq": {
"id": "my-plugin-id",
"title": "我的插件",
"icon": "./icon.png",
"description": "插件描述"
}
}
插件 API 基础
初始化
import '@logseq/libs'
async function main() {
console.log('插件加载')
// 注册命令,设置等。
logseq.Editor.registerSlashCommand('我的命令', async () => {
// 命令逻辑
})
}
logseq.ready(main).catch(console.error)
核心 API 命名空间
| 命名空间 | 目的 |
|---|---|
logseq.Editor |
块/页面操作 |
logseq.DB |
数据库查询 |
logseq.App |
应用级操作 |
logseq.UI |
UI 组件 |
logseq.Settings |
插件设置 |
DB 版本特定 API
处理属性
// 获取带有属性的块(DB 版本)
const block = await logseq.Editor.getBlock(blockUuid, {
includeChildren: true
})
// DB 版本中属性结构不同
// 通过 block.properties 对象访问
const author = block.properties?.author
// 设置属性值
await logseq.Editor.upsertBlockProperty(blockUuid, 'author', 'John Doe')
处理类/标签
// 获取具有特定标签/类的块
const books = await logseq.DB.datascriptQuery(`
[:find (pull ?b [*])
:where
[?b :block/tags ?t]
[?t :block/title "Book"]]
`)
// 给块添加标签
await logseq.Editor.upsertBlockProperty(blockUuid, 'tags', ['Book', 'Fiction'])
增强的块属性 API(2024+)
// DB 版本新 API
await logseq.Editor.getBlockProperties(blockUuid)
await logseq.Editor.setBlockProperties(blockUuid, {
author: 'Jane Doe',
rating: 5,
published: '2024-01-15'
})
插件中的 Datalog 查询
基本查询
const results = await logseq.DB.datascriptQuery(`
[:find ?title
:where
[?p :block/title ?title]
[?p :block/tags ?t]
[?t :db/ident :logseq.class/Page]]
`)
带参数的查询
const results = await logseq.DB.datascriptQuery(`
[:find (pull ?b [*])
:in $ ?tag-name
:where
[?b :block/tags ?t]
[?t :block/title ?tag-name]]
`, ['Book'])
DB 与 MD 查询差异
// MD 版本 - 文件基础查询
const mdQuery = `
[:find ?content
:where
[?b :block/content ?content]
[?b :block/page ?p]
[?p :block/name "my-page"]]
`
// DB 版本 - 实体基础查询
const dbQuery = `
[:find ?title
:where
[?b :block/title ?title]
[?b :block/tags ?t]
[?t :block/title "My Tag"]]
UI 组件
斜杠命令
logseq.Editor.registerSlashCommand('插入书籍模板', async () => {
await logseq.Editor.insertAtEditingCursor(`
- [[新书籍]] #Book
作者::
评分::
状态:: 待读
`)
})
块上下文菜单
logseq.Editor.registerBlockContextMenuItem('转换为任务', async (e) => {
const block = await logseq.Editor.getBlock(e.uuid)
await logseq.Editor.upsertBlockProperty(e.uuid, 'tags', ['Task'])
await logseq.Editor.upsertBlockProperty(e.uuid, 'status', 'Todo')
})
设置模式
logseq.useSettingsSchema([
{
key: 'apiKey',
type: 'string',
title: 'API 密钥',
description: '服务的 API 密钥',
default: ''
},
{
key: 'enableFeature',
type: 'boolean',
title: '启用功能',
default: true
},
{
key: 'theme',
type: 'enum',
title: '主题',
enumChoices: ['light', 'dark', 'auto'],
default: 'auto'
}
])
DB 版本兼容性检查清单
当为 DB 版本构建插件时:
- [ ] 使用
:block/title代替:block/content用于页面名称 - [ ] 处理结构化属性(不仅仅是字符串)
- [ ] 支持类型化属性值(数字,日期,复选框)
- [ ] 使用基于标签的查询而不是命名空间查询
- [ ] 如果同时支持 DB 和 MD,则测试两种
- [ ] 处理统一的节点模型(页面 ≈ 块)
- [ ] 可用时使用新的块属性 API
常见模式
功能检测
async function isDBGraph() {
// 检查当前图是否基于 DB
const graph = await logseq.App.getCurrentGraph()
return graph?.name?.includes('db-') || graph?.type === 'db'
}
async function main() {
const isDB = await isDBGraph()
if (isDB) {
// DB 特定初始化
} else {
// MD 特定初始化
}
}
属性类型处理
function formatPropertyValue(value, type) {
switch (type) {
case 'date':
return new Date(value).toISOString().split('T')[0]
case 'number':
return Number(value)
case 'checkbox':
return Boolean(value)
case 'node':
return `[[${value}]]`
default:
return String(value)
}
}
开发工作流
- 设置: 克隆 logseq-plugin-template 或从头开始
- 开发: 使用
npm run dev进行热重载 - 测试: 在 Logseq 中加载未打包的插件
- 构建:
npm run build进行生产构建 - 发布: 提交到 Logseq 市场
加载开发插件
Logseq > 设置 > 高级 > 开发者模式:ON
Logseq > 插件 > 加载未打包的插件 > 选择文件夹