vscode插件开发之 - 消息通信

  在开发vscode插件过程中,有一个典型场景是webview与extension.ts进行通信,例如,webview上的某些信息发送改变时,需要发送消息传递给extension.ts. 如果使用react框架构建vscode插件的webview,如何实现webview与extension.ts之间通信呢?如果要实现信息通信,需要三个步骤:

  步骤一:在react的src目录下,定义一个全局变量vscode,代码如下所示:这里定义了Message数据结构,定义了VSCode别名。

interface Message {
        command: string;
        content: string;
        [key: string]: any;
}
type VSCode = {
        Uri: any;
        env: any;
        postMessage(message: Message): void;
        getState(): any;
        setState(state: any): void;
};

declare const vscode: VSCode;

   步骤二:在react的source code下面,在需要发送共享消息的地方,调用vscode.postMessage()发送消息。示例代码如下所示,当input中的信息或者dropdown中的信息发生改变时,就会通过postMessage发送消息出去。

const App = () => {
    const [sex, setSex] = useState('');
    const handleChange = (event: any) => {
        setSex(event.target.value);
        vscode.postMessage({ command: "sexChange", content: event.target.value });
    };
    const handleNameChange = (event: any) => {
        const value = event.target.value;
        vscode.postMessage({ command: "nameChange", content: value });
    }
    const handelAgeChange = (event: any) => {
        const value = event.target.value;
        vscode.postMessage({ command: "ageChange", content: value });
    }
    return (
        <div>
            <div>
                <input type="text" name="name" onChange={handleNameChange}></input>
            </div>
            <div>
                <input type="text" name="age" onChange={handelAgeChange}></input>
            </div>
            <div>
                <select value={sex} onChange={handleChange} >
                    <option>girl</option>
                    <option>boy</option>
                </select>
            </div>
            <div>
                <button>ShowIt</button>
            </div>
        </div>
    );
};
const rootElement = document.getElementById('root');
if (rootElement) {
    const root = (ReactDOM as any).createRoot(rootElement);
    root.render(<App />);
} else {
    console.error('Root element not found!');
}

  步骤三:在extension.ts代码中,增加监听消息的代码,如果是多个信息需要汇聚,那么可以定义个公共的数据对象,直接更新这个对象即可。调用webview.onDidReceiveMessage监听消息,并将接受到的内容,更新到info这个变量上。

        webviewView.webview.onDidReceiveMessage((message: any) => {
            if (message.command === "nameChange") {
                info.name = message.content
            } else if (message.command === "ageChange") {
                info.age = message.content
            } else if (message.command === "sexChange") {
                info.sex = message.content
            }
        })
export interface Info {
        name: string,
        age: number,
        sex: string
}

export let info: Info = {
        name: "",
        age: 0,
        sex: "boy"
}

  修改完上述代码后,就可以进行验证,是否能在extension.ts上接受不了webview上的输入信息了,这里当trigger demo.showOne command的时候,在message上,打印了info这个对象。

    context.subscriptions.push(
        vscode.commands.registerCommand('demo.showOne', () => {
            vscode.window.showInformationMessage('I am showOne.');
            vscode.window.showInformationMessage(JSON.stringify(info))
        })
    );

   重新编译后,在extension的webview上输入一些信息,在点击右键菜单的showOne,在右下角的message上成功打印出了消息,说明消息传递成功。

  那么,为什么在webview的source code上定义了Message和VSCode对象后,就能调用postMessage发送消息呢?实际上如果要成功发送消息,在extension.ts的webview.html代码中还需要添加上“const vscode = acquireVsCodeApi()”才行。

    private getWebviewContent(webviewUri: vscode.Uri): string {
        return `
            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <title>Taoli Webview</title>
            </head>
            <body>
            <div id="root"></div>
               <script>
                    const vscode = acquireVsCodeApi();
                </script>
             <script src="${webviewUri}"></script>
            </body>
            </html>`;
    }
}

消息通信工作原理

   在 VS Code 扩展中,webview 是一个内嵌的 HTML 环境,类似于一个 iframe。acquireVsCodeApi 函数是 VS Code 提供的一个全局函数,允许 webview 内部的 JavaScript 代码获取一个 VS Code API 对象,从而与扩展主进程进行通信。调用该函数会返回一个包含一组方法的对象,这些方法用于与扩展主进程进行双向通信。主要的方法包括:
postMessage(message: any): void
getState(): any
setState(state: any): void

   在步骤一中定义的VScode和Message对象,这些代码是告诉 TypeScript 编译器,在运行时将会有一个全局的 vscode 对象,该对象符合 VSCode 类型。这是为了让 TypeScript 知道 vscode 对象的存在,并进行类型检查和自动补全。实际当webview运行的时候,使用的是acquireVsCodeApi 函数返回的VScode常量。这个常量提供的方法和之前定义的一致。通过这种方式实现了消息通信。

1.发送消息:webview 内部的代码使用 vscode.postMessage 方法发送消息到主进程。
2.接收消息:主进程使用 webview.onDidReceiveMessage 方法接收并处理这些消息。
3.双向通信:如果需要,主进程还可以使用 webview.postMessage 方法向 webview 发送消息,从而实现双向通信。

相关推荐

  1. vscode开发

    2024-06-18 01:38:03       42 阅读
  2. VSCODE开发API

    2024-06-18 01:38:03       46 阅读
  3. 怎么开发vscode

    2024-06-18 01:38:03       37 阅读
  4. vscodewebview和通信

    2024-06-18 01:38:03       63 阅读
  5. 如何使用vue开发vscode

    2024-06-18 01:38:03       54 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-18 01:38:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-18 01:38:03       101 阅读
  3. 在Django里面运行非项目文件

    2024-06-18 01:38:03       82 阅读
  4. Python语言-面向对象

    2024-06-18 01:38:03       92 阅读

热门阅读

  1. Leetcode.2709 最大公约数遍历

    2024-06-18 01:38:03       34 阅读
  2. 常用的设计模式

    2024-06-18 01:38:03       29 阅读
  3. 服务器添加TLS域名证书核子之PKCS编解码

    2024-06-18 01:38:03       27 阅读
  4. WDF驱动开发-I/O请求的处理(四)

    2024-06-18 01:38:03       28 阅读
  5. Flask-RQ

    2024-06-18 01:38:03       31 阅读
  6. 《 Python趣味编程 | 从入门到就业》专栏介绍

    2024-06-18 01:38:03       25 阅读
  7. SpaTracker&CoTracker 环境配置

    2024-06-18 01:38:03       22 阅读
  8. oracle中使用临时表GLOBAL TEMPORARY TABLE

    2024-06-18 01:38:03       25 阅读
  9. python调用SDK的问题

    2024-06-18 01:38:03       26 阅读
  10. Python笔记 - 正则表达式

    2024-06-18 01:38:03       28 阅读
  11. 搭建Conda虚拟环境让python程序脚本更干净

    2024-06-18 01:38:03       32 阅读
  12. React@16.x(31)useLayoutEffect

    2024-06-18 01:38:03       33 阅读