1062 字
5 分钟
Logseq Plugins 开发实战系列:2.为logseq添加内容组件
2022-02-26

为logseq添加内容组件#

前言#

本文为本人发布gitbook的书籍,但是因为gitbook一直没有被谷歌索引,我也没有办法提交给谷歌(无法证明所有权)。无奈只能把该本的章节逐步搬运过来,提高SEO。希望那些想学习logseq plugins 开发的同学们能直接通过搜索引擎看到此书。

原书本章地址https://correctroad.gitbook.io/logseq-plugins-in-action/

起步#

logseq中有一种特殊的语法{{renderer }},我们可以通过插件实现把{{renderer }}渲染为特定的内容。

比如在 logseq-plugin-link-preview插件中{{renderer :linkpreview,https://google.com}}将会被显示为:

注册渲染函数#

我们可以用上一章的项目为基础,改一下package.json中的项目内容。

我们使用onMacroRendererSlotted去实现该功能

logseq.App.onMacroRendererSlotted(({ slot, payload} ) => { const [type,name] = payload.arguments if (type !== ':hello') return logseq.provideUI({ key: 'h1-playground', slot, template: ` <div class="hello"> hello! ${name} </div> `, }) })

我们在{{renderer :hello,Logseq}}renderer后面的内容就会存在payloadarguments中。我们可以通过解构的方式去得到里面的值。

修改main.tsx

import '@logseq/libs' async function main () { logseq.App.onMacroRendererSlotted(({ slot, payload} ) => { const [type,name] = payload.arguments if (type !== ':hello') return logseq.provideUI({ key: 'hello', slot, template: ` <div class="hello" > hello! ${name} </div> `, }) }) } logseq.ready(main).catch(console.error)

npm build并载入logseq

添加样式#

光有html实现好看的内容,我们还需要为其提供css样式。

logseq中, logseq.provideStyle提供了这个功能。

logseq.provideStyle(` .hello { background-color: red; border: 1px solid var(--ls-border-color); white-space: initial; padding: 2px 4px; border-radius: 4px; user-select: none; cursor: default; display: flex; align-content: center; }`)

ps:该css出自logseq-plugin-samples

现在我们的main.tsx是这样的

import '@logseq/libs' async function main () { logseq.provideStyle(` .hello { background-color: red; border: 1px solid var(--ls-border-color); white-space: initial; padding: 2px 4px; border-radius: 4px; user-select: none; cursor: default; display: flex; align-content: center; }`) logseq.App.onMacroRendererSlotted(({ slot, payload} ) => { const [type,name] = payload.arguments if (type !== ':hello') return logseq.provideUI({ key: 'hello', slot, template: ` <div class="hello"> hello! ${name} </div> `, }) }) } logseq.ready(main).catch(console.error)

来看看效果:

事件触发#

还有内容还不够,我们还可以为该html添加上事件

我们继续制作,当点击hello! logseq时,logseq消息提示出hello! logseq。logseq中logseq.provideModel可以让我们自己编写事件。并可以通过e.dataset传参。

事件函数:

logseq.provideModel({ msg(e: any) { const {msg} = e.dataset; logseq.App.showMsg(`Hello! ${msg}`); } })

组件函数:

logseq.App.onMacroRendererSlotted(({ slot, payload} ) => { const [type,name] = payload.arguments if (type !== ':hello') return logseq.provideUI({ key: 'hello', slot, template: ` <div class="hello" data-msg="${name}" data-on-click="msg" > hello! ${name} </div> `, }) })

通过data-xxx我们可以向事件函数传参。

效果:

组件参数持久化#

如果组件中存在特别的值并改变组件样式。比如我们希望本来背景是红的。点击一下变成绿的,再次点击再变回来。

修改组件增加背景颜色项#

修改css:去掉了上面写死的backgrounp-color

logseq.provideStyle(` .hello { border: 1px solid var(--ls-border-color); white-space: initial; padding: 2px 4px; border-radius: 4px; user-select: none; cursor: default; display: flex; align-content: center; }`)

修改组件

logseq.App.onMacroRendererSlotted(({ slot, payload} ) => { const [type,name,color] = payload.arguments if (type !== ':hello') return logseq.provideUI({ key: 'hello', reset: true, slot, template: ` <div style="background-color: ${ color }" class="hello" data-block-uuid="${payload.uuid}" data-on-click="update" > hello! ${name} </div> `, }) }) }

注意:这里增加了reset,这个有什么用,后面会演示

事件改变block#

我们现在来写我们的事件。

logseq.provideModel({ async update(e: any) { const { blockUuid } = e.dataset; const block = await logseq.Editor.getBlock(blockUuid) let newContent = block?.content; if(block?.content?.indexOf("red") > -1) { newContent = block?.content?.replace(`red`, `green`) }else{ newContent = block?.content?.replace(`green`, `red`) } await logseq.Editor.updateBlock(blockUuid, newContent) } })

我们先通过logseq.Editor.getBlock用传进来的blockuuid去得到block的内容。然后通过logseq.Editor.updateBlock去更新block的值。

效果:

到了最后,我们再回来去看看之前设置的reset有什么用?如何一个组件的reset没有设置。那么点击的效果就会变成这样:

项目受logseq-plugin-samples中的logseq-pomodoro-timer启发,部分代码源于此。

最后附上main.tsx完整代码

import '@logseq/libs' async function main () { logseq.provideModel({ async update(e: any) { const { blockUuid } = e.dataset; const block = await logseq.Editor.getBlock(blockUuid) let newContent = block?.content; if(block?.content?.indexOf("red") > -1) { newContent = block?.content?.replace(`red`, `green`) }else{ newContent = block?.content?.replace(`green`, `red`) } await logseq.Editor.updateBlock(blockUuid, newContent) } }) logseq.provideStyle(` .hello { border: 1px solid var(--ls-border-color); white-space: initial; padding: 2px 4px; border-radius: 4px; user-select: none; cursor: default; display: flex; align-content: center; }`) logseq.App.onMacroRendererSlotted(({ slot, payload} ) => { const [type,name,color] = payload.arguments if (type !== ':hello') return logseq.provideUI({ key: 'hello', reset: true, slot, template: ` <div style="background-color: ${ color }" class="hello" data-block-uuid="${payload.uuid}" data-on-click="msg" > hello! ${name} </div> `, }) }) } logseq.ready(main).catch(console.error)

拓展#

onMacroRendererSlotted中常见判断组件类型有:通过type.startsWith判断和通过type !==判断。他们的区别与优劣是什么?

未完待续…

Logseq Plugins 开发实战系列:2.为logseq添加内容组件
https://correctroadh.github.io/posts/plugins-2/
作者
CorrectRoad
发布于
2022-02-26
许可协议
CC BY-NC-SA 4.0