VSCode插件开发全攻略(七)WebView (2)

重头戏来了,Webview和普通网页非常类似,不能直接调用任何VSCodeAPI,但是,它唯一特别之处就在于多了一个名叫acquireVsCodeApi的方法,执行这个方法会返回一个超级阉割版的vscode对象,这个对象里面有且仅有如下3个可以和插件通信的API:

W624xH430

插件和Webview之间如何互相通信呢?

插件给Webview发送消息(支持发送任意可以被JSON化的数据):

panel.webview.postMessage({text: '你好,我是小茗同学!'});

Webview端接收:

window.addEventListener('message', event => { const message = event.data; console.log('Webview接收到的消息:', message); }

Webview主动发送消息给插件:

vscode.postMessage({text: '你好,我是Webview啊!'});

插件接收:

panel.webview.onDidReceiveMessage(message => { console.log('插件收到的消息:', message); }, undefined, context.subscriptions); 简单通信封装

为了双方通信方便,我把它们简单封装了一下,仅供参考,Webview端:

const callbacks = {}; // 存放所有的回调函数 /** * 调用vscode原生api * @param data 可以是类似 {cmd: 'xxx', param1: 'xxx'},也可以直接是 cmd 字符串 * @param cb 可选的回调函数 */ function callVscode(data, cb) { if (typeof data === 'string') { data = { cmd: data }; } if (cb) { // 时间戳加上5位随机数 const cbid = Date.now() + '' + Math.round(Math.random() * 100000); // 将回调函数分配一个随机cbid然后存起来,后续需要执行的时候再捞起来 callbacks[cbid] = cb; data.cbid = cbid; } vscode.postMessage(data); } window.addEventListener('message', event => { const message = event.data; switch (message.cmd) { // 来自vscode的回调 case 'vscodeCallback': console.log(message.data); (callbacks[message.cbid] || function () { })(message.data); delete callbacks[message.cbid]; // 执行完回调删除 break; default: break; } });

插件端:

let global = { projectPath, panel}; panel.webview.onDidReceiveMessage(message => { if (messageHandler[message.cmd]) { // cmd表示要执行的方法名称 messageHandler[message.cmd](global, message); } else { util.showError(`未找到名为 ${message.cmd} 的方法!`); } }, undefined, context.subscriptions); /** * 存放所有消息回调函数,根据 message.cmd 来决定调用哪个方法, * 想调用什么方法,就在这里写一个和cmd同名的方法实现即可 */ const messageHandler = { // 弹出提示 alert(global, message) { util.showInfo(message.info); }, // 显示错误提示 error(global, message) { util.showError(message.info); }, // 回调示例:获取工程名 getProjectName(global, message) { invokeCallback(global.panel, message, util.getProjectName(global.projectPath)); } } /** * 执行回调函数 * @param {*} panel * @param {*} message * @param {*} resp */ function invokeCallback(panel, message, resp) { console.log('回调消息:', resp); // 错误码在400-600之间的,默认弹出错误提示 if (typeof resp == 'object' && resp.code && resp.code >= 400 && resp.code < 600) { util.showError(resp.message || '发生未知错误!'); } panel.webview.postMessage({cmd: 'vscodeCallback', cbid: message.cbid, data: resp}); }

按上述方法封装之后,例如,Webview端想要执行名为openFileInVscode命令只需要这样:

callVscode({cmd: 'openFileInVscode', path: `package.json`}, (message) => { this.alert(message); });

然后在插件端的messageHandler实现openFileInVscode方法即可,其它都不用管:

const messageHandler = { // 省略其它方法 openFileInVscode(global, message) { util.openFileInVscode(`${global.projectPath}/${message.path}`); invokeCallback(global.panel, message, '打开文件成功!'); } };

以上封装的比较随便,只是给大家提供一个思路,有时间可以好好封装一下。

主题适配

Webview可以根据VS Code的当前主题更改其外观,原理是body上面添加当前主题名称,主要有以下三种:

vscode-light - 浅色主题;

vscode-dark -深色主题;

vscode-high-contrast - 高对比度主题;

所以我们可以通过自己写样式来适配不同主题:

/* 浅色主题 */ .body.vscode-light { background: white; color: black; } /* 深色主题 */ body.vscode-dark { background: #252526; color: white; } /* 高对比度主题 */ body.vscode-high-contrast { background: white; color: red; }

深色主题效果:

W1404xH770

生命周期

webview由创建它的扩展程序所有,返回的panel对象你必须自己保存,如果你的扩展程序丢失了这个引用,那么将无法再次重新访问该webview,即使Web视图继续显示在vscode中。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpyfxy.html