手摸手开发一款vscode 代码提示插件 - 进阶 Webviews 通讯

239 阅读1分钟

「这是我参与2022首次更文挑战的第10天,活动详情查看:2022首次更文挑战」。

书接上文

脚本和信息传递

webview跟iframe 一样同样是可以运行js 脚本的,但是在webview中默认是禁用的,在创建页面加上这个配置

//新创建webView
currentPanel = vscode.window.createWebviewPanel(
  "start", // 只供内部使用,这个webview的标识
  "start", // 给用户显示的面板标题
  vscode.ViewColumn.One, // 给新的webview面板一个编辑器视图
  {
    enableScripts: true, // 启用JS,默认禁用
    retainContextWhenHidden: true, // webview被隐藏时保持状态,避免被重置
    localResourceRoots: [vscode.Uri.file(path.join(extensionPath, ""))],
  }
);

在源码中我们修改 getWebview 方法,让咱们的冰墩墩出现奔跑的数字,当前只是演示,实践中酌情开启脚本

function getWebview(imgSrc) {
    return `<!DOCTYPE html>
	<html lang="en">
	<head>
		<meta charset="UTF-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>Document</title>
	</head>
	<body>
		<img src="${imgSrc}" />
		<h1 id="count">0</h1>
		<script>
        const counter = document.getElementById('count');
        let count = 0;
        setInterval(() => {
            counter.textContent = count++;
        }, 100);
    </script>
	</body>
	</html>`
}

02e0fb85-c9a7-4563-8b3d-658acde05fb2.gif 看,数字跑的多快 but 虽然webveiw能做到任何普通页面脚本能做的到的事情,但是脚本不能直接使用vscode 提供的api

8bb38fd2-711f-4938-87e3-39dbf0d09dfc (1).gif

把插件信息传递给webView

插件可以调用 webview.postMessage()把数据发送到 它的webview,这个方法可以把json信息发送到webview中,在webview中使用messgae 接收事件 现在咱们实现一下,在 插件中注册时一个新命令把消息发给webview.webview接收信息展示在页面上

function getWebview(imgSrc) {
  return `<!DOCTYPE html>
	<html lang="en">
	<head>
		<meta charset="UTF-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>Document</title>
	</head>
	<body>
		<img src="${imgSrc}" />
		<h1 id="count">0</h1>
		<script>
        const counter = document.getElementById('count');
        let count = 0;
        let timer = setInterval(() => {
            counter.textContent = count++;
        }, 100);
		window.addEventListener('message', event => {
            const message = event.data; // The JSON data our extension sent
            counter.textContent  =  message.msg
			clearInterval(timer)
        });
    </script>
	</body>
	</html>`;
}
  context.subscriptions.push(
    vscode.commands.registerCommand("z-ui.sendMsg", () => {
		console.log(currentPanel);
      if (!currentPanel) {
        return;
      }
      // 把信息发送到webview
      // 你可以发送任何序列化的JSON数据
      currentPanel.webview.postMessage({ msg: "这是传递过来的信息" });
    })
  );

8bb38fd2-711f-4938-87e3-39dbf0d09dfc.gif

webView 把信息传递给插件

webView接收到插件发来的消息,webView接收到信息,发送信息给插件,完成一来一回

        // 接收webView信息
        currentPanel.webview.onDidReceiveMessage(
          (message) => {
            vscode.window.showInformationMessage(message.msg);
          },
          undefined,
          context.subscriptions
        );

a2215207-0756-4567-997e-21eabb0e7938.gif

安全性

每一个你创建的webview都必须遵循这些基础的安全性最佳实践,限制能力,如果webview不使用资源的话,localResourceRoots设置[]和[vscode.Uri.file(extensionContext.extensionPath)]