Heim > Entwicklungswerkzeuge > VSCode > Vertiefendes Verständnis des Implementierungsprinzips der Markdown-Vorschau in vscode

Vertiefendes Verständnis des Implementierungsprinzips der Markdown-Vorschau in vscode

青灯夜游
Freigeben: 2021-09-01 18:13:17
nach vorne
3091 Leute haben es durchsucht

Vertiefendes Verständnis des Implementierungsprinzips der Markdown-Vorschau in vscode

vscode 的 markdown 预览是我们整天都在用的功能,有没有想过它是怎么实现的。或许有一天你会接到个定制 markdown 预览的需求,应该怎么做呢?【推荐学习:《vscode教程》】

其实整体思路比较简单,就是创建一个 webview panel,设置内容为 markdown 生成的 html,之后在 markdown 更新的时候同步修改 webview 的 html 就可以了。

思路分析

通过 vscode.window.createWebviewPanel 创建一个 webview,指定在侧边打开,之后通过该  panel 对象的 webview.html 属性来设置 html。

html 是通过编辑器的 markdown 内容生成的, 编辑器内容通过 editor.document.getText() 拿到,然后调用第三方的 markdown 转 html 的库来生成。

这样就完成了 markdown 的预览。

预览之后需要更新,监听 vscode.workspace.onDidSaveTextDocument 和 vscode.workspace.onDidChangeTextDocument 的事件,在文档更新和保存的时候,拿到编辑器的内容,重新生成 html,然后设置到 webview。

webviewPanel 支持 webview.postMessage(message); 的方式传递消息,支持 updateHTML 等一系列 command,可以通过传递消息来触发。

但是怎么知道哪个文档更新哪个 webview 呢?

可以维护一个 map,在创建 webviewPanel 的时候记录到 map 中,key 为文件路径,这样更新的时候就能查找到对应的 webview 进行更新。

这样,就完成了 markdown 内容的更新。

其实整体思路还是比较简单的,下面我们来写下代码

代码实现

我们看下 vscode-markdown-preview-enhanced 的插件的代码,这也是一个预览 markdown 的插件,代码还算简洁,可以用来学习。

(以下代码是简化后的代码)

首先,插件要指定触发的条件,也就是在 package.json 里面指定 activationEvents:

"activationEvents": [
    "onLanguage:markdown",
    "onCommand:markdown-preview-enhanced.openPreviewToTheSide"
],
Nach dem Login kopieren

这里一个是编辑 markdown 内容的时候激活,一个是执行 command 的时候激活。

具体激活的逻辑在 active 方法里:

export function activate(context: vscode.ExtensionContext) {

  const contentProvider = new MarkdownPreviewEnhancedView(context);

  context.subscriptions.push(
    vscode.commands.registerCommand(
      "markdown-preview-enhanced.openPreviewToTheSide",
      openPreviewToTheSide,
    ),
  );
  
  function openPreviewToTheSide(uri?: vscode.Uri) {
    let resource = uri;
    if (!(resource instanceof vscode.Uri)) {
      if (vscode.window.activeTextEditor) {
        resource = vscode.window.activeTextEditor.document.uri;
      }
    }
    contentProvider.initPreview(resource, vscode.window.activeTextEditor, {
      viewColumn: vscode.ViewColumn.Two,
      preserveFocus: true,
    });
  }
}
Nach dem Login kopieren

我们注册了那个 command,执行 command 会拿到当前 editor 的 url,然后进行 markdown 的 preview。

preview 的所有逻辑都集中定义在了 MarkdownPreviewEnhancedView 的实例对象中,在 command 触发时执行 initPreivew。

public async initPreview(
    sourceUri: vscode.Uri,
    editor: vscode.TextEditor,
    viewOptions: { viewColumn: vscode.ViewColumn; preserveFocus?: boolean },
) {
    // 创建 webview
    let previewPanel: vscode.WebviewPanel = vscode.window.createWebviewPanel(
        "markdown-preview-enhanced",
        `Preview ${path.basename(sourceUri.fsPath)}`,
        viewOptions
    );

    // 监听 webview 的消息
    previewPanel.webview.onDidReceiveMessage((message) => {});

    // 记录 webview 到 map 中
    this.previewMaps[sourceUri.fsPath] = previewPanel;
    
    // 拿到编辑器的文本,生成 html
    const text = editor.document.getText();
    engine
      .generateHTMLTemplateForPreview({inputString: text})
      .then((html) => {
        // 设置 html 到 previewPanel
        previewPanel.webview.html = html;
      });
}
Nach dem Login kopieren

在 initWebivew 里面创建 webviewPanel,同时把 webviewPanel 保存到 map 中,key 为文档的文件路径。拿到编辑器文本来生成 html,设置到 webview.html,这样就完成了 markdown 的预览。

这条路径走通之后,我们就实现了 markdown 的预览。

但是只预览一次不行,更新文档之后需要自动更新,我们继续在 active 方法里添加事件监听:

  context.subscriptions.push(
    vscode.workspace.onDidSaveTextDocument((document) => {
      if (isMarkdownFile(document)) {
        contentProvider.updateMarkdown(document.uri, true);
      }
    }),
  );

  context.subscriptions.push(
    vscode.workspace.onDidChangeTextDocument((event) => {
      if (isMarkdownFile(event.document)) {
        contentProvider.update(event.document.uri);
      }
    }),
  );
Nach dem Login kopieren

监听文本修改和保存的时候,调用 update 方法来更新。

public updateMarkdown(sourceUri: Uri) {

    // 从 map 中根据文件路径取出对应的 webviewPanel
    const previewPanel = this.previewMaps[sourceUri.fsPath];
    
    // 生成最新的 html 传递给 webview
    const text = document.getText();
    engine
        .parseMD(text)
        .then(({ markdown, html }) => {
            previewPanel.webview.postMessage({
              command: "updateHTML",
              html
            });
        }

}
Nach dem Login kopieren

这里是通过 webview.postMessage 给 html 内容传递 updateHTML 的 command 消息,触发 html 内容的更新。

这样,我们就实现了 markdown 的同步刷新。

总结

vscode 里面 markdown 的预览是一个常用但实现起来并不难的功能,我们看了下 vscode-markdown-preview-enhanced 插件的源码,理清了整体的流程:

  • 通过 vscode.window.createWebviewPanel 创建 webviewPanel 来显示 html
  • html 通过 editor.document.getText() 拿到文本内容之后通过第三方包生成,设置到 webviewPanel
  • 监听 workspace.onDidSaveTextDocument 和 workspace.onDidChangeTextDocument,来拿到最新内容,之后生成 html 通过 webview.postMessage 传递 udpateHTML 的消息来更新到 webview。
  • 要注意的是,需要记录一个 map 来保存 uri.fsPath 和 webviewPanel 的对应关系,实现文本内容改变更新对应的 webview

markdown 的预览是一个常见但是并不难的需求,也比较适合入门 vscode 插件的开发,希望这篇文章能够帮大家理清思路。

更多编程相关知识,请访问:编程入门!!

Das obige ist der detaillierte Inhalt vonVertiefendes Verständnis des Implementierungsprinzips der Markdown-Vorschau in vscode. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:juejin.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage