为logseq添加内容组件
起步
在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后面的内容就会存在payload的arguments中。我们可以通过解构的方式去得到里面的值。
修改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 !== 判断。他们的区别与优劣是什么?
未完待续...
最后更新于