「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战」。
Webviews
webview API为开发者提供了完全自定义视图的能力,用来支撑原生vscode api 不能支撑的场景,可以把 Webview 当成特殊的一种iframe,具有渲染全部html的能力,他通过消息机制与插件通信,提供了高可定制型和潜力
我应该用吗?
webview很nice,但是计算机世界没有银弹,webview,十分占用资源,不要滥用webview,要多加思考,慎重慎重
API
为了整这个webView 的api,咱们继续在原来的项目开发,打开一个页面静态页面,从命令行调试 z-ui.start
{
"name": "z-ui",
"displayName": "",
"description": "",
"version": "0.0.1",
"engines": {
"vscode": "^1.64.0"
},
"categories": [
"Other"
],
"activationEvents": [
"onCommand:z-ui.helloWorld",
"onLanguage:vue"
],
"main": "./extension.js",
"contributes": {
"commands": [
{
"command": "z-ui.start",
"title": "start 页面",
"category": "z-ui"
}
],
"snippets": [
{
"language": "vue-html",
"path": "./snippets/ui-tag.json"
}
]
},
"scripts": {
"lint": "eslint .",
"pretest": "yarn run lint",
"test": "node ./test/runTest.js"
},
"devDependencies": {
"@types/vscode": "^1.64.0",
"@types/glob": "^7.2.0",
"@types/mocha": "^9.0.0",
"@types/node": "14.x",
"eslint": "^8.6.0",
"glob": "^7.2.0",
"mocha": "^9.1.3",
"typescript": "^4.5.4",
"@vscode/test-electron": "^2.0.3"
}
}
实现catCoding.start命令
// @ts-nocheck
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
const vscode = require('vscode');
const utils = require('./src/utils')
const attributes = require('./src/attributes')
const tags = require('./src/tags')
const fs = require('fs')
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
//获取静态文件
function getWebview() {
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="https://ftp.bmp.ovh/imgs/2022/02/8de1be3916ac782a.jpeg" />
</body>
</html>`
}
/**
* @description:激活事件
* @param {vscode.ExtensionContext} context
*/
function activate(context) {
function provideCompletionItemsAttrValue(document, position, token, context) {
try {
const tag = utils.getTag(document, position)
const attr = utils.getPreAttr(document, position)
const { options: single } = attributes[attr] || {}
if (single) {
return single.map(dep => {
// vscode.CompletionItemKind 表示提示的类型
return new vscode.CompletionItem(dep, vscode.CompletionItemKind.Text);
})
}
const attrKey = `${tag}/${attr}`
const { options } = attributes[attrKey] || {}
if (options) {
return options.map(dep => {
return new vscode.CompletionItem(dep, vscode.CompletionItemKind.Text);
})
}
} catch (error) {
console.log(error)
}
}
function provideCompletionItemsAttr(document, position, token, context) {
try {
const tag = utils.getTag(document, position)
const { attributes } = tags[tag] || {}
if (attributes) {
return attributes.map(dep => {
return new vscode.CompletionItem(dep, 14);
})
}
} catch (error) {
console.log(error)
}
}
let completionAttrValue = vscode.languages.registerCompletionItemProvider(['vue'], { provideCompletionItems: provideCompletionItemsAttrValue }, '', ':', '<', '"', "'", '/', '@', '(', '>', '{');
let completionAttr = vscode.languages.registerCompletionItemProvider(['vue'], { provideCompletionItems: provideCompletionItemsAttr }, ' ',);
context.subscriptions.push(vscode.commands.registerCommand('z-ui.start', () => {
// 创建并显示新的webview
const panel = vscode.window.createWebviewPanel(
'catCoding', // 只供内部使用,这个webview的标识
"Cat Coding", // 给用户显示的面板标题
vscode.ViewColumn.One, // 给新的webview面板一个编辑器视图
{
enableScripts: true, // 启用JS,默认禁用
retainContextWhenHidden: true, // webview被隐藏时保持状态,避免被重置
}
);
// 设置HTML内容
panel.webview.html = getWebview();
panel.onDidDispose(() => {
// 当面板关闭时,触发一些操作
}, null, context.subscriptions)
}));
context.subscriptions.push(completionAttrValue);
context.subscriptions.push(completionAttr);
}
// this method is called when your extension is deactivated
function deactivate() { }
module.exports = {
activate,
deactivate
}
展示
生命周期
webview从属于创建他们的插件,因为webview是一个文件视图,用户关闭了,资源就释放了.
- onDidDispose 事件在webview被销毁时触发,我们在这个事件结束之后更新并释放webview资源。
移动和可见性
.visible属性告诉你当前webview面板是否是可见的。
let currentPanel;
context.subscriptions.push(vscode.commands.registerCommand('z-ui.start', () => {
// 创建并显示新的webview
const columnToShowIn = vscode.window.activeTextEditor ? vscode.window.activeTextEditor.viewColumn : undefined;
if(currentPanel){
currentPanel.reveal(columnToShowIn);
}else{
currentPanel = vscode.window.createWebviewPanel(
'start', // 只供内部使用,这个webview的标识
"start", // 给用户显示的面板标题
vscode.ViewColumn.One, // 给新的webview面板一个编辑器视图
{
enableScripts: true, // 启用JS,默认禁用
retainContextWhenHidden: true, // webview被隐藏时保持状态,避免被重置
}
);
// 设置HTML内容
currentPanel.webview.html = getWebview();
}
}));
读取本地资源
webview运行的换进跟vscode 是隔离开的,要是使用资源要使用特殊协议 vscode-resource:协议,使用localResourceRoots 显示资源目录
currentPanel = vscode.window.createWebviewPanel(
'start', // 只供内部使用,这个webview的标识
"start", // 给用户显示的面板标题
vscode.ViewColumn.One, // 给新的webview面板一个编辑器视图
{
enableScripts: true, // 启用JS,默认禁用
retainContextWhenHidden: true, // webview被隐藏时保持状态,避免被重置
localResourceRoots: [
vscode.Uri.file(path.join(extensionPath, ''))
]
}
);
const diskPath = vscode.Uri.file(path.join(context.extensionPath, "/resources/img/WX20220214-213950.png"));
const imgSrc = diskPath.with({ scheme: 'vscode-resource' }).toString();
// 设置HTML内容
currentPanel.webview.html = getWebview(imgSrc);