Webview 的功能想必不用过多赘述,就像微信小程序一样借助于 VS Code 平台承载页面,一般用来做可视化,或者比较复杂的配置页面,当然你非要把自己的工具站塞到这里也行,但就和小程序嵌 H5 一样,何必多此一举呢?
配置启动信息
当编辑的文件为指定语言时,将 Start a visual preview
注册到命令菜单和右键菜单中,选择该菜单时,会广播 preview.start
事件
"commands": [
{
"command": "preview.start",
"title": "Start a visual preview"
}
],
"menus": {
"commandPalette": [
{
"command": "preview.start",
"when": "editorLangId == language id"
}
],
"editor/context": [
{
"command": "preview.start",
"when": "editorLangId == antlr"
}
]
}
注册命令监听
context.subscriptions.push(
vscode.commands.registerCommand("preview.start", () => {
// ......
})
)
创建 Webview
vscode.ViewColumn.Two
代表的是分屏创建,如果想在新页面打开,使用 vscode.ViewColumn.One
即可
const panel = vscode.window.createWebviewPanel(
"preview",
previewConfig.title,
vscode.ViewColumn.Two,
{ enableScripts: true }
);
如果需要启动时获取当前正在编辑的文本,可以通过访问 vscode.window.activeTextEditor?.document.getText()
获取,后续更新可以通过诸如 vscode.workspace.onDidSaveTextDocument
保存后或者变更后发送数据到页面
加载 HTML
let html = readFileSync(
vscode.Uri.file(
path.join(context.extensionUri.path, "templates/preview.html")
).with({ scheme: "vscode-resource" }).fsPath,
"utf-8"
);
加载外部资源
const getResourceUri = (name: string) => {
return panel?.webview.asWebviewUri(
vscode.Uri.joinPath(context.extensionUri, 'templates/media', name)
)
}
const getNonce() {
let text = "";
const possible =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < 32; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
const nonce = getNonce();
const scripts = ['xxx.js', 'xxxx.js', 'main.js'].map(name => `
<script nonce="${nonce}" src="${getResourceUri(name)}"></script>`).join('');
const styles = `
<link href="${getResourceUri("main.css")}" rel="stylesheet">
`;
html = html
.replace("'${initData}'", JSON.stringify(data))
.replace("${scripts}", scripts)
.replace("${cspSource}", panel.webview.cspSource)
.replace(/(\$\{nonce\})/g, nonce)
.replace("${styles}", styles);
panel.webview.html = html;
其中的 nonce 和 cspSource 是因为限制的安全等级比较高,所以必须要配置相应的 CSP 规则才能使用。
例如上面的报错截图,就必须要配置 connect-src 才可以访问
通信
通过 postMessage
进行双向通信
panel.webview.onDidReceiveMessage((e) => {
})
panel.webview.postMessage({
type: 'update:data',
data: {}
})
window.onmessage = (e) => {
const { type, data } = e.data;
}
使用
打开目标文件,唤出命令面板,输入 >
出现配置的命令,选择注册的菜单,或者编辑器中按右键也会出现改菜单。
按下菜单后,自动在编辑器右侧打开 Webview