You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Obsidian插件中嵌入并使用<script>引入WGo.js

Obsidian插件嵌入WGo.js SGF播放器实现方案

我正在开发首个Obsidian插件,目标是嵌入WGo.js SGF围棋对局播放器。WGo.js虽已发布至NPM,但因文档过时无法直接正常使用,目前已有项目雏形,也在Obsidian论坛发布了相关讨论帖。我设想通过以下步骤实现:

  1. 自定义语法!![game1.sgf]链接本地SGF文件
  2. 插件将该语法替换为WGo.js所需的<div>容器
  3. 加载WGo.js相关资源,渲染内嵌对局查看器

以下是具体实现方法:

1. 自定义语法解析与替换(Markdown后置处理)

Obsidian插件可通过注册Markdown后置处理器,识别自定义语法并替换为目标DOM结构:

import { Plugin } from 'obsidian';

export default class SGFViewerPlugin extends Plugin {
  async onload() {
    // 注册Markdown后置处理器
    this.registerMarkdownPostProcessor((element, context) => {
      // 匹配自定义语法 `!![filename.sgf]`
      const regex = /!!\[([^\]]+\.sgf)\]/g;
      const codeBlocks = element.querySelectorAll('code');
      
      codeBlocks.forEach(block => {
        const content = block.textContent;
        if (content && regex.test(content)) {
          const match = content.match(regex);
          if (match) {
            match.forEach(m => {
              const filename = m.replace(/!!\[|\]/g, '');
              // 创建WGo播放器容器
              const wgoDiv = document.createElement('div');
              wgoDiv.className = 'SGF';
              wgoDiv.setAttribute('data-wgo', filename);
              wgoDiv.setAttribute('data-wgo-board', `stoneHandler: WGo.Board.drawHandlers.NORMAL, background: '${this.getResourcePath('assets/wgo/textures/wood2.jpg')}'`);
              // 添加降级提示
              const fallbackP = document.createElement('p');
              fallbackP.textContent = '你的浏览器不支持WGo.js播放器,请使用Chrome、Firefox等现代浏览器。';
              wgoDiv.appendChild(fallbackP);
              // 替换原code块
              block.replaceWith(wgoDiv);
            });
          }
        }
      });
    });
  }

  // 获取插件内资源的绝对路径
  getResourcePath(relativePath: string): string {
    return this.app.vault.getResourcePath(this.addResource(relativePath));
  }
}

2. 加载WGo.js依赖资源

将WGo.js的所有JS/CSS文件打包到插件的assets/wgo目录下,通过动态加载方式导入,避免直接插入<script>标签的兼容性问题:

async loadWGoResources() {
  const jsFiles = [
    'wgo.js', 'kifu.js', 'sgfparser.js', 'player.js',
    'basicplayer.js', 'basicplayer.component.js',
    'basicplayer.infobox.js', 'basicplayer.commentbox.js',
    'basicplayer.control.js', 'player.editable.js',
    'scoremode.js', 'player.permalink.js'
  ];

  // 加载JS文件
  for (const file of jsFiles) {
    await this.loadScript(`assets/wgo/${file}`);
  }

  // 加载CSS文件
  await this.loadStylesheet(`assets/wgo/wgo.player.css`);
}

// 封装加载脚本方法
async loadScript(path: string) {
  const script = document.createElement('script');
  script.src = this.getResourcePath(path);
  document.head.appendChild(script);
  await new Promise(resolve => script.onload = resolve);
}

// 封装加载样式方法
async loadStylesheet(path: string) {
  const link = document.createElement('link');
  link.rel = 'stylesheet';
  link.href = this.getResourcePath(path);
  document.head.appendChild(link);
  await new Promise(resolve => link.onload = resolve);
}

在插件onload方法中调用loadWGoResources(),确保依赖加载完成后再处理DOM。

3. 初始化WGo播放器

由于是动态生成的DOM,需要手动触发WGo的初始化逻辑。可在后置处理器替换DOM后立即初始化,或在依赖加载完成后批量初始化:

// 方式1:替换DOM后立即初始化
if (window.WGo?.Player) {
  WGo.Player.init(wgoDiv);
}

// 方式2:资源加载完成后批量初始化
this.loadWGoResources().then(() => {
  WGo.Player.init(document.querySelectorAll('.SGF'));
});

4. SGF文件路径处理

Obsidian中的文件路径需转换为WGo可访问的路径,可通过以下方式获取SGF文件的绝对路径:

async getSGFPath(filename: string) {
  const file = this.app.vault.getAbstractFileByPath(filename);
  if (file) {
    return this.app.vault.getResourcePath(file);
  }
  return '';
}

将data-wgo属性的值替换为该方法返回的路径,确保WGo能正确读取SGF文件。


参考示例HTML结构:

<script type="text/javascript" src="../../assets/wgo/wgo.js"></script>
<script type="text/javascript" src="../../assets/wgo/kifu.js"></script>
<script type="text/javascript" src="../../assets/wgo/sgfparser.js"></script>
<script type="text/javascript" src="../../assets/wgo/player.js"></script>
<script
    type="text/javascript"
    src="../../assets/wgo/basicplayer.js"
></script>
<script
    type="text/javascript"
    src="../../assets/wgo/basicplayer.component.js"
></script>
<script
    type="text/javascript"
    src="../../assets/wgo/basicplayer.infobox.js"
></script>
<script
    type="text/javascript"
    src="../../assets/wgo/basicplayer.commentbox.js"
></script>
<script
    type="text/javascript"
    src="../../assets/wgo/basicplayer.control.js"
></script>
<script
    type="text/javascript"
    src="../../assets/wgo/player.editable.js"
></script>
<script type="text/javascript" src="../../assets/wgo/scoremode.js"></script>
<script
    type="text/javascript"
    src="../../assets/wgo/player.permalink.js"
></script>
<link
    rel="stylesheet"
    type="text/css"
    href="../../assets/wgo/wgo.player.css"
/>

<!-- 自定义语法`!![AncientGame.sgf]`替换后的结构 -->
<div
    data-wgo="AncientGame.sgf"
    data-wgo-board="stoneHandler: WGo.Board.drawHandlers.NORMAL,
                                    background: '../../assets/wgo/textures/wood2.jpg'"
    class="SGF"
>
    <p>
        Your browser doesn't support the WGo.js Player. Please use a more
        modern browser, like Brave, Chrome, Firefox or Edge.
    </p>
</div>

内容的提问来源于stack exchange,提问作者psygo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 08:02:15