Skip to content

Commit

Permalink
Merge pull request #841 from Moyf/moy-new-articles
Browse files Browse the repository at this point in the history
关于 Note toolbar 插件的介绍文章
  • Loading branch information
windily-cloud committed Sep 11, 2024
2 parents 6693cb8 + 067a94e commit 242990f
Show file tree
Hide file tree
Showing 6 changed files with 576 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
uid: 20240808235819
title: 如何创建动态的笔记目录
tags: [Obsidian/插件, Obsidian, OB分享]
description:
author: Moy
type: other
draft: false
editable: false
modified: 20240911095148
---

# 如何创建动态的笔记目录

> 本帖的想法来自 [DataviewJS 的提取与汇总 - 经验分享 - Obsidian 中文论坛](https://forum-zh.obsidian.md/t/topic/28337/6) 以及 [使用 Dataview 读取文件中所有标题 - 经验分享 - Obsidian 中文论坛](https://forum-zh.obsidian.md/t/topic/36955/2)
> 感谢前人的经验分享,希望也能对你有所帮助。
## 效果

![](https://cdn.pkmer.cn/images/202409110952715.png!pkmer)

其中,**目录** 里的链接是使用 Dataview JS 脚本自动生成的,会随着笔记内容自动更新。

和其他方案的对比:

1.**Automatic Table of Content** 等插件相比,使用了大部分人都在用的 Dataview 插件,减少额外的插件安装
2.**Table of Contents** 插件相比,优势是可以自动实时更新,劣势是并非实际的 Markdown 文本,无法脱离插件使用

## 使用方法

将 dataviewjs 代码粘贴进笔记,开启 Dataview 插件的脚本渲染功能的情况下,直接会生效。

生成的目录本质是 `[[#标题]]` 形式的链接,可以直接点击跳转。

## 代码

![](https://cdn.pkmer.cn/images/202409110952672.png!pkmer)

第一版:纯列表形式

````javascript
```dataviewjs
const startHeadinglevel = 2;
const file = app.workspace.getActiveFile();
const { headings } = app.metadataCache.getFileCache(file);
// 全列表的形式
const raws = headings.map( p => {
let repeatCount = Math.max((p.level - startHeadinglevel) * 4, 0);
let spacesPrefix = ' '.repeat( repeatCount + 4 );
let listSign = repeatCount > 0 ? '- ' : '';
let linkText = `[[#${p.heading}]]`;
let headingList = (p.level < startHeadinglevel) ? `- ${linkText}` : `${spacesPrefix}- ${linkText}`;
return headingList;
}
)
let result = raws.join('\n');
// 添加行距
dv.container.style.lineHeight = "1.5em";
dv.paragraph(result)
```
````

第二种:分层形式

````javascript
```dataviewjs
// 尝试另一种形式,个人更喜欢让一级列表特殊一点
const startHeadinglevel = 2;
const file = app.workspace.getActiveFile();
const { headings } = app.metadataCache.getFileCache(file);
let output = '';
const additionalAttr = {attr: {style: 'margin-block-start: 0 !important; margin-block-end: 0 !important;'}};
// 整个 dv 容器的样式调整
dv.container.style.marginBlockStart = "0em";
headings.forEach ( h => {
if (h.level < startHeadinglevel) {
// 先输出之前的子列表内容
if (output) dv.paragraph(output, additionalAttr);
// 将一级标题输出成单独的段落
output = `[[#${h.heading}]]\n`;
dv.paragraph(output);
output = '';
} else {
output += `${' '.repeat((h.level - startHeadinglevel) * 4)}- [[#${h.heading}]]\n`;
}
})
// 把最后的残余内容输出出来
if (output) dv.paragraph(output, additionalAttr);
```
````

## 脚本要点

- 最初的难点就是 ==怎么用 Dataview 输出有层级的列表==,因为直接加空格前缀会导致文本内容被识别成「代码」而非「嵌套列表」
- 查看 @PlayerMiller 的代码发现可以通过 **将所有文本一起输出成 paragraph** 的方式渲染成正确的列表
- 但是对第二版来说,没法让作为「非列表」的一级标题很好地共同渲染,所以分段进行单独渲染
- DV 样式调整
- 为了调整行间距等样式,使用 `dv.container.style` 直接给 dv 容器指定样式
- 针对列表的段落,用 `dv.paragraph(output, {attr: {style: 'margin-block-start: 0 !important; margin-block-end: 0 !important;'}} )` 单独指定样式
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
---
uid: 20240801133135
title: 如何在单篇笔记里实现轻量数据库
tags: [Obsidian, OB分享]
description: 在单篇笔记里实现轻量数据库
author: Moy
type: other
draft: false
editable: false
modified: 20240911095343
---

# 如何在单篇笔记里实现轻量数据库

## 介绍

众所周知,在 Obsidian 里实现类似「数据库」的需求一直都是痛点。

虽然借助插件能实现,但往往得给每一项数据都创建单独页面……颇为麻烦,完全不像 Notion 那样舒适且无感。

很久以前我就有一个设想:

> 如果我有一篇笔记**专门收集某个专题的内容**,想要把它做成一个「小数据库」——不要求编辑,只求汇总展示里面各个内容的特定属性,能行吗?
这个问题困扰了我半年之久,终于在最近,随着对 OB 和 Dataview 插件的学习,我实现了这个陈年需求。

## 展示

效果展示:

![](https://cdn.pkmer.cn/images/202409110952965.png!pkmer)

可以看到,通过笔记内的多个标题,就能自动生成一个「轻量数据库」进行呈现。

支持特性:

1. 点击标题可以直接跳转到对应内容
2. 只需要一篇笔记就可以创建数据库
3. 支持多个属性的组合
4. 根据元数据自适应生成表格列
5. (大体上)实时更新,具体取决于 Dataview 的刷新间隔
6. 简单易用:只需要三行代码加一个 JS 脚本文件即可实现

## 工作原理

### 笔记的书写

需要借助 Dataview 插件,以及固定的格式:

```markdown
## 标题
[属性::值] [属性2::值]
```

1. 元数据行紧挨着标题行写(标题层级不限制——几个井号都行)
2. 可以有多个元数据,使用 `[key::value]` 的格式,一行内的多个属性之间要 **隔开 2 个空格** ⚠️
3. 同一个属性(例如 `标签` )可以在一个内联属性里用逗号写多个值,也可以一行里写多个同名属性(会自动合并)
- 第一种: `[标签:Obsidian,css]`
- 第二种:`[标签:Obsidian] [标签:css]`

文章在开始的那张图片,源代码模式下就长这样儿:

![](https://cdn.pkmer.cn/images/202409110953893.png!pkmer)

> [!Info] 关于内联属性
> 详见 Dataview 的文档:[Adding Metadata - Dataview](https://blacksmithgu.github.io/obsidian-dataview/annotation/add-metadata/#inline-fields)
### 数据库的呈现

首先,打开 Dataview 插件的设置,确保这几个选项都是打开的:

![](https://cdn.pkmer.cn/images/202409110953349.png!pkmer)

然后需要将这个 JS 文件放入你的笔记库,命名为 `liteDatabase.js`

````js
const useList = false;
const curNote = dv.current();

if (!curNote){
dv.span("当前文档未加载,请重新打开");
return;
}

let tarFile = await app.vault.getAbstractFileByPath(curNote.file.path);

// 获取当前文件的 meta 数据
const curFileMeta = app.metadataCache.getFileCache(tarFile);
const headings = curFileMeta.headings;

const headingsList = headings.map( k => k.heading )

// 获取当前文章的文本内容
const curFilePath = curNote.file.path;
const curTFile = await app.vault.getFileByPath(curFilePath)
const content = await app.vault.cachedRead(curTFile);

if (!headings) {
dv.span("当前文档缺少标题");
return;
}

const meta = content.matchAll(/#+ (.*)\n(\[.*\:.*\])/gm);

// 标题作为 key,元数据作为 value,做成 DV 表格
let tableHeads = ["标题"]

// 先存成一个 dict
let metaValues = []

if (meta) {
for (let m of meta) {
let title = m[1]

// 检查 title 是否在 headings 内(避免把一些代码块内的内容也当作元数据)
if (headingsList.indexOf(title) == -1) {
continue
}

let metaList = m[2].split(" ")
let metaDict = {}

// 添加元数据的 key 到表头
for (let i = 0; i < metaList.length; i++) {
let keyValue = metaList[i].replace("[", "").replace("]", "").split("::")
// console.log(metaList[i], keyValue)

let key = keyValue[0].trim()
if (tableHeads.indexOf(key) == -1) {
tableHeads.push(key)
}

if (useList){
// 1. 列表形式,重复属性会合并
let value = [keyValue[1]]
metaDict[key] = metaDict[key] ? metaDict[key].concat(value) : value
} else {
// 2. 文本形式,重复属性会使用最新的
let value = keyValue[1]
metaDict[key] = metaDict[key] ? metaDict[key] + `,${value}` : value
}
}

let returnValuesList = []

for (let i = 0; i < tableHeads.length; i++) {
if (i == 0) {
returnValuesList.push(`[[#${m[1]}]]`)
} else {
returnValuesList.push(metaDict[tableHeads[i]] ? metaDict[tableHeads[i]] : "")
}
}

metaValues.push(returnValuesList)
}
}

dv.table(
tableHeads,
metaValues.map( k => k )
)


````

> 你也可以直接在 Github Gist 中查看或下载这个代码文件:[DVJS Code - Lite Database for Obsidian](https://gist.github.com/Moyf/f2fa6e88c589e70217188e0998e303f0)
> (后续如果有更新会直接传到 Gist 里)
然后,在笔记中插入:

````markdown

```dataviewjs
dv.view("liteDatabase")
```

````

在笔记书写符合规则的情况下,现在你应该就能看到轻量数据库的呈现了!

### 测试文本

如果暂时没写内容,你也可以直接复制这段内容进笔记查看效果:

````markdown
## 传说之下
[英文名::Undertale] [标签::感人,剧情向]

「你落入了地底,然后——」
关于友情的故事。

## 星际拓荒
[英文名::Outer Wilds] [标签::探索,感人]

「嘿,尝试过掉进黑洞吗?」
关于探索的故事。

## 生化奇兵:无限
[标签::好玩] [标签::感人,剧情向] [英文名::BioShock Infinite]

「过去多少年,我依旧在你身边」
关于时间的故事。
````

## 拓展

因为用的是 JS 语言,所以理论上来讲**形式和内容都有很大的拓展可能性**

比如你也可以不用 Dataview 内联属性,就用自己定义的某种格式。

或者你想对获取到的元数据再进行二次处理……

修改 JS 文件(或者让 GPT 帮你修改)就可以按自己想要的方式进行定制化!

## 碎碎念时间

### 起源

一开始是今年一月份的时候,看 GameOff 的游戏开发比赛发现好多作品非常有趣,然后就一边记录一边想着「打标记」:

![](https://cdn.pkmer.cn/images/202409110953170.png!pkmer)

你可以看到,当时我就在尝试类似的「标题 + 下方的标记」这种方式来进行记录,但是苦于 **没有办法把它们汇总到一起展示出来**

(甚至开始怀念起了 Notion 的数据库 lol)

但是这个问题放到今天,只需要把当时还在探索的「标记方式」替换成 Dataview 的内联属性,就能得到:

![](https://cdn.pkmer.cn/images/202409110953481.png!pkmer)

——每个游戏是不是 Godot 开发的,有哪些值得注意的亮点,一目了然!

### 属性的定义

关于元数据定义形式,主要是参考了 Github Badges 的样式:

![](https://cdn.pkmer.cn/images/202409110953912.jpg!pkmer)

这样一排小徽标排在一起看着还挺好看的。

(应该也可以通过 css 来实现多彩的背景色)

另外就是……放在同一行也可以让正则表达式的筛选更简化一些。

最早其实也尝试过「标签」还有「内联代码」这两种形式。

但标签的话……会污染我的标签池,这种内容我还是希望就局限在「这个页面内」;内联代码倒是没啥问题,想用也可以用的。

至于多个 KeyValue 中间的 **两个空格**,这个可能是 Dataview 自己的限制?只有一个空格的情况下似乎会有一些识别问题,所以就强行规定两个空格了。

(但我自己都经常忘记打两个,嗨呀)
6 changes: 4 additions & 2 deletions 10-Obsidian/Obsidian使用技巧/Obsidian使用技巧.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ author: OS
type: awesome
draft: false
editable: false
modified: 20240806215746
modified: 20240911100114
---

# Obsidian 使用技巧
Expand All @@ -22,6 +22,7 @@ modified: 20240806215746
- [[改善笔记内的链接编辑体验]]
- [[一键搞定快速操作笔记的元数据并统计最近完成事项]]
- [[右对齐作者的引用样式]]
- [[【快捷键】使用连续按键来快速打开页面]]

### 综合

Expand Down Expand Up @@ -72,6 +73,8 @@ modified: 20240806215746
- [[【外观】分享一种好看的月历做法]]
- [[【快捷键】使用连续按键来快速打开页面]]
- [[【实用技巧】实现OB内的文本指令]]
- [[【实用技巧】如何在单篇笔记里实现轻量数据库]]
- [[【Dataview】如何创建动态的笔记目录]]
- [[破折号作者自动右对齐]]
- Quickadd
- [[Quickadd结合CSS实现挖空复习]] by Mon
Expand All @@ -94,7 +97,6 @@ modified: 20240806215746
- [[QuickAdd脚本-插入并编辑SVG文件]]
- [[quickadd#社区使用技巧|更多请参考Quickadd社区技巧...]]


## 与第三方软件联动

- Thino
Expand Down
Loading

0 comments on commit 242990f

Please sign in to comment.