沐沫沫
1
meta-bind-js-view代码块创建的按钮可以变成行内使用吗?
花了几个小时,终于写出了代码,让在正文中也可以手动填写/直接选库中特定属性的所有值,但是生成的按钮是占领全行的,希望能添个id属性之类的,用类似 BUTTON[button-id] 语法在行内使用
```meta-bind-js-view
---
// 只需要改这里:你要提取哪个字段?
const FIELD_NAME = "科属"; // 各笔记的属性名
// ==============================================
// 1. 遍历全库,提取所有该字段的值(自动去重)
const files = app.vault.getMarkdownFiles();
const valueSet = new Set();
files.forEach(file => {
const value = app.metadataCache.getFileCache(file)?.frontmatter?.[FIELD_NAME];
if (value) valueSet.add(value);
});
// 2. 转成 option(xxx) 格式
const options = Array.from(valueSet)
.filter(Boolean)
.map(item => `option(${item})`)
.join(", ");
// 3. 加上 allowOther
const finalOptions = `${options}, allowOther`;
// 4. 输出 Meta Bind 选择器
const str = `\`INPUT[suggester(${finalOptions}):${FIELD_NAME}]\``;
return engine.markdown.create(str);
```
scope可以嵌套2次吗?

最好让早餐名称和早餐价格还是在一个单元格内
```js-engine
const mb = engine.getPlugin('obsidian-meta-bind-plugin').api;
const tableOptions = {
bindTarget: mb.createBindTarget('frontmatter', context.file.path, ['食物记录']),
tableHead: ['消费日期', '记录日期', '早', '早餐价格', '中', '晚'],
columns: [
'INPUT[datePicker:scope^记录日期]',
'INPUT[datePicker:scope^消费日期]',
'INPUT[suggester(option(包子), option(粉), option(不吃), allowOther):scope^早餐]',
`INPUT[number:scope^早餐价格]`,
'INPUT[text:scope^中餐]',
'INPUT[text:scope^晚餐]',
],
};
const mountable = mb.createTableMountable(context.file.path, tableOptions);
mb.wrapInMDRC(mountable, container, component);
```
Probe
(Probe)
2
没用过这些, 这也太复杂了… 只尝试讨论第一个问题吧
首先, 最容易想的肯定是把楼主的 meta-bind-js-view 代码改造为只定义 suggester, 之后另行引用
经过一番折腾, 目前我觉得这插件只有 button 可以通过 id 引用 (即先声明按钮再渲染按钮, 两部分在笔记里分离), 其他的诸如 suggester 之类都不行
然后下一个方案是, 放弃 js-engine, 只借助 inline dataviewjs 去做出 suggester, 经实验这具备基本的可行性, 例如以下代码应该是能用的
(其中 $= 是 inline dvjs 的标识符)
`$= String.fromCharCode(96)+"INPUT[number:distance]"+String.fromCharCode(96)`
所以打算放弃 js-engine 的代码块, 把楼主代码改造为用行内 dataviewjs 实现, 容易理解的版本是
const FIELD_NAME = "科属";
const files = app.vault.getMarkdownFiles();
const valueSet = new Set();
files.forEach(file => {
const value = app.metadataCache.getFileCache(file)?.frontmatter?.[FIELD_NAME];
if (value) valueSet.add(value);
});
const options = Array.from(valueSet).filter(Boolean).map(item => `option(${item})`).join(", ");
const finalOptions = options ? `${options}, allowOther` : "allowOther";
// 使用 String.fromCharCode(96) 生成反引号,防止 Markdown 解析冲突
return String.fromCharCode(96) + `INPUT[suggester(${finalOptions}):${FIELD_NAME}]` + String.fromCharCode(96);
但上面代码还是不能直接用, 得改成单行 $= xxx 形态且转义掉所有的碍事字符, 改完是:
`$= const FIELD_NAME = "科属"; const valueSet = new Set(); app.vault.getMarkdownFiles().forEach(file => { const v = app.metadataCache.getFileCache(file)?.frontmatter?.[FIELD_NAME]; if (v) valueSet.add(v); }); const options = Array.from(valueSet).filter(Boolean).map(item => "option(" + item + ")").join(", "); const finalOptions = options ? options + ", allowOther" : "allowOther"; const tick = String.fromCharCode(96); tick + "INPUT[suggester(" + finalOptions + "):" + FIELD_NAME + "]" + tick`
最后这段在我这是能用的, 楼主可以试试
1 个赞
沐沫沫
3
谢谢!成功啦!
可以正式开始用Meta Bind参与我的笔记
之前为了方便base管理笔记,得让笔记的内容更多的记录在属性区 → 需要添加的属性名很多 → 如果不模板一次性添加属性名,就可能导致不同属性管理同一内容;事先添加了,属性一大堆列出来,有点眼花;直接通过base添加,得由卡片切至表格再切回来
现在准备使用Meta Bind+Callout折叠+Virtual Content,预计会方便多了
1 个赞
沐沫沫
4
再次求助变为1行,找AI改不成功 
代码用了 await,说inline dvjs 不支持
这个是选填手动添加的列表子项值:
需要放在**根目录**的「test.md」文件中
```meta-bind-js-view
---
// ===================== 配置区 =====================
const TARGET_CATEGORY = "植物名"; // 要提取 test.md 里的哪个列表分类
const OUTPUT_FIELD = "易混淆植物"; // 要保存到哪个字段
const file = app.vault.getAbstractFileByPath('test.md'); // test.md文件路径
// ==================================================
const content = await app.vault.cachedRead(file);
const lines = content.split("\n").filter(line => line.trim() !== '');
// 解析缩进级别 + 清洗文字
const parsedLines = lines.map(line => {
const indent = line.match(/^(\s*)/)[0].length;
const text = line.trim()
.replace(/^- /, '')
.replace(/[::\s]*$/, '') //去掉冒号、空格
.trim();
return { indent, text };
});
const values = [];
let targetIndent = -1;
let found = false;
let childIndent = null; // 记录直接子项的真实缩进
for (let i = 0; i < parsedLines.length; i++) {
const pl = parsedLines[i];
// 1. 找到目标分类
if (!found && pl.text === TARGET_CATEGORY) {
found = true;
targetIndent = pl.indent;
continue;
}
// 2. 收集子项
if (found) {
if (pl.indent <= targetIndent) break; // 缩进回到 <= 目标 → 停止
if (childIndent === null) { childIndent = pl.indent;} // 第一个比目标大的缩进,就是子项层级
if (pl.indent === childIndent) { values.push(pl.text);} // 只收集和 childIndent 相同缩进的项,孙子项(更深层级)不收集
}
}
// 生成选择框
const options = values.map(v => `option(${v})`).join(", ");
const finalStr = `${OUTPUT_FIELD}:\`INPUT[suggester(${options}, allowOther):${OUTPUT_FIELD}]\``; //去前面属性名提示:const finalStr = `\`INPUT[suggester(${options}, allowOther):${OUTPUT_FIELD}]\``;
return engine.markdown.create(finalStr);
```
%%
- 备选值
- 植物名:
- [[香樟]]
- 栾树
- [[桂花]]
- 银杏
- 科属
- 木樨科
- 马鞭草科
%%
目前在用的代码是根据这个改来的:
Probe
(Probe)
5
试了在 inline dataviewjs 里使用 await , 能想到的办法全都失败了, 感觉搞不定…