VSCode插件开发三:webview通信

2,641 阅读4分钟

在前一篇文章中,我们介绍了如何在 VSCode 中使用 WebView 来展示页面。然而,仅仅呈现页面可能不足以满足你的需求。在实际应用中,可能需要在插件和 WebView 页面之间进行更多的交互,涉及插件配置获取、网络请求等复杂操作。在本文中,我们将详细说明如何实现插件与 WebView 之间的通信。

插件向 WebView 传递信息

首先,让我们看一下如何在插件中向 WebView 传递信息。以下是一个代码示例:

// 插件端代码
import * as vscode from 'vscode';

export function activate(context: vscode.ExtensionContext) {
    const panel = vscode.window.createWebviewPanel(
        'exampleWebView', // WebView 面板的标识符
        '示例 WebView', // WebView 面板的标题
        vscode.ViewColumn.One, // WebView 在编辑器中的显示位置
        {}
    );

    const message = '这是来自插件的信息';
    panel.webview.postMessage(message);
}

在上述代码中,我们使用 postMessage 方法将消息从插件端发送到 WebView。

接下来,让我们看一下 WebView 端如何接收来自插件的信息:

// 在 WebView 中监听来自插件的消息
window.addEventListener('message', event => {
    const receivedMessage = event.data;
    // 在 WebView 中处理收到的消息
    // 可以根据消息内容进行相应的操作
});

通过在 WebView 页面中添加对 message 事件的监听器,我们可以捕获来自插件发送的消息并在 WebView 中进行处理。

WebView 向插件传递信息

与此同时,WebView 也可以向插件传递信息,以实现双向通信。以下是一个代码示例:

// Webview 中的 JavaScript 代码
const vscode = acquireVsCodeApi();

// 发送消息给插件
vscode.postMessage('这是来自 WebView 的信息');

在上述代码中,我们使用了 acquireVsCodeApi 方法来获取一个用于与插件通信的实例,然后使用 postMessage 方法将消息从 WebView 端发送给插件。

插件端如何接收来自 WebView 的信息呢?让我们看一下下面的代码:

// 监听 webview 发送的消息
panel.webview.onDidReceiveMessage(message => {
    // 处理接收到的消息
    // 可以根据消息内容进行相应的操作
});

通过在插件端的代码中监听 webviewonDidReceiveMessage 事件,我们可以获取来自 WebView 发送的消息,并在插件中进行相应的处理。

通信逻辑封装

在开发过程中,随着代码的不断增加,页面会有各种发送信息和接收信息的处理函数。如果不采取适当的组织方式,这些消息传递的代码会变得混乱不堪,使得项目难以维护和扩展。为了解决这个问题,我们可以考虑将相关代码进行封装和优化,以提高代码的可管理性和可读性。下面将介绍一个处理方案。

首先,我们可以将发送和处理消息的代码放在一个类中,以减少重复性代码。以下是一个在 Webview 端的示例代码:

// 定义处理 Webview 消息的类
class WebviewMessages {
  constructor() {
    this.vscode = acquireVsCodeApi();
  }

  // 调用 VSCode 原生的消息提示
  showInformationMessage(msg: string) {
    this.vscode.postMessage({ command: 'SHOW_INFORMATION_MESSAGE', data: msg });
  }
}

// 导出实例
export default new WebviewMessages();

在插件端,我们可以创建一个类来接收和处理来自 Webview 的消息:

import * as vscode from 'vscode'

class ExtensionMessage {
  webview: Webview
  constructor(webview: Webview) {
    this.webview = webview
    webview.onDidReceiveMessage((message) => {
      if (message.command === 'SHOW_INFORMATION_MESSAGE') {
        vscode.window.showInformationMessage(message.data)
      }
    })
  }
}

export default ExtensionMessage

上述代码实现了一个简单的单向消息传递,适用于在 Webview 中调用插件端的功能。但是,当我们需要在发送消息后获得返回结果时,就需要考虑更复杂的情况。例如,在 Webview 发送消息以获取某个配置项,并在插件端接收信息后返回结果。我们可以通过 Promise 来处理这种情况,以下是一个关于如何使用 Promise 在插件端获取配置的示例:

const command = 'CONFIG';

class WebviewMessages {
  constructor() {
    this.vscode = acquireVsCodeApi();
    this.promises = new Map();

    webview.onDidReceiveMessage((message) => {
      // 插件端返回的类型要与发送的类型一致
      if (message.command === command && this.promises.has(command)) {
        // 处理返回结果,调用 resolve 方法
        this.promises.get(command).resolve(message.data);
        this.promises.delete(command) // 调用之后移除
      }
    });
  }

  // 添加 getConfig 方法,创建 promise 并返回
  getConfig() {
    const promise = new Promise((resolve, reject) => {
      // 保存 resolve 和 reject 函数
      this.promises.set(command, { resolve, reject });
    });
    this.vscode.postMessage({ command });
    return promise;
  }
}

// 调用
new WebviewMessages().getConfig().then(config => {
  // 处理获取到的配置
});

这个示例简单展示了在 Webview 和插件端之间如何利用 Promise 实现双向消息传递。在实际应用中,可能会涉及到更多的逻辑和场景。这是我个人在开发过程中的一个思路,可以作为一个参考和借鉴。

更多代码可以查看,github.com/wenyikun/do…