这里以 obsidian-sample-plugin 里的例子说明,官方代码如下:

this.addCommand({
id: 'open-sample-modal-complex',
name: 'Open sample modal (complex)',
checkCallback: (checking: boolean) => {
const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);
if (markdownView) {
if (!checking) {
new SampleModal(this.app).open();
}
return true;
}
return false;
}
});

这里的代码是什么意思呢?

通过测试得知,checkCallback 会被调用两次,第一次是按下 mod+p 时(这里的 mod 再 Windows 上是 ctrl,Mac 上是 command),第二次是选择命令时,比如这里当你执行 Open sample modal (complex)命令时。

在第一次时,如果 checkCallback 里返回 false,那么就不会把 Open sample modal (complex)命令加入到命令列表中,那么你也就无法执行命令了。但如果你返回 true,就会加入到命令列表,而不管你判断条件是什么。在第一次执行时,checking 的值总是 true。

第二次执行时,checking 的值,总是 false,这时无论你返回 true 还 false 都没有影响,只有第一次的返回有影响。

总结:

  1. 第一次判断你的返回值决定是否显示命令,这是在弹出命令面板时执行;
  2. 第二次直接执行,不受返回结果影响;
  3. 第一次 checking 传值总是 true,第二次总是 false。

所以你的判断条件是什么,checkCallback api 根本就不关心,那是你自己代码逻辑应该关心的事。

有了上面的了解,可以把上面的代码逻辑做如下优化:

const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);

if(checking && !markdownView) return false;
if(checking && markdownView) return true;

if(!markdownView) return;

new SampleModal(this.app).open();

嗯,去掉逻辑嵌套,看起来舒服多了。

但是,还不够,每个地方都这样判断,也显得啰嗦,进一步优化:

//定义判断函数
const checkCondition = (checking: boolean, condition: any): boolean|string => {
//如果预检(第一次执行),且条件不符返回false
if(checking && !condition) return false;
//如果预检(第一次执行),且条件符合,返回true
if(checking && condition) return true;

//如果非预检(第二次执行),条件不符返回空
if(!condition) return '';

//如果非预检(第二次执行),且条件符合返回pass
return 'pass';
}


//实际使用

const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);

//判断条件是否符合,不符合返回
const checkRet = checkCondition(checking, markdownView)
if('pass' !== checkRet) return Boolean(checkRet);

//条件符合执行
new SampleModal(this.app).open();

这样逻辑看起来简单多了,而且方便复用。

你以为这样就好了,还有更好的方案,哈哈。

釜底抽薪式的优化

const markdownView = this.app.workspace.getActiveViewOfType(MarkdownView);		
if(checking) return Boolean(markdownView) // return condition
new SampleModal(this.app).open();

结束。