你好!
本人为 2019.7 毕业的应届毕业生,目前从事前端工程师的职业。对知识充满渴望。如果本文中有什么错误的地方,还请各位指正。谢谢。
本文定位为初次接触vs code插件开发的小伙伴,开始有详细的教程如何一步一步的运用基础的插件开发
接下来会用完成的 demo 教大家 treeView 和 webView 的初级完成开发流程。小伙伴耐心跟着代码敲一遍能学会的哈。
先给小伙伴们看一下本文的目录架构:
此文章为第二部分,如需从头开始阅读,请移步第一部分
首先,我们先在 src
下创建 TreeViewProvider.ts
文件。重要的代码都展示在这里了。
import { TreeItem, TreeItemCollapsibleState, TreeDataProvider, Uri, window } from 'vscode';
import { join } from 'path';
这里重点讲解一下上面这两句代码:
vscode
提供了很多的 API 让我们使用,我们可以打开官网 VS code API
我讲解一下上面需要用到的几个项:
TreeItem
:
创建 TreeItem
类型的构造函数,传递参数 label
、collapsibleState
.
label
: tree 该项的标题。
collapsibleState
: 该项是否折叠状态。参数有三: Collapsed(折叠状态)、Expanded(展开状态)、None(无状态)。
?
: 代表参数为非必填项,可不传。注意:非必填项,必须放在最后面
TreeItemCollapsibleState
: 就是 collapsibleState
的类型。
TreeDataProvider
: 为树数据的数据提供程序(如果不理解,可以先放着,一会看代码)。
Uri
: 通用资源标识符,表示磁盘上的文件或其他资源(用来读取文件路径)。
join
: 用来拼接文件路径。
import { TreeItem, TreeItemCollapsibleState, TreeDataProvider, Uri, window } from 'vscode';
import { join } from 'path';
// 创建每一项 label 对应的图片名称
// 其实就是一个Map集合,用 ts 的写法
const ITEM_ICON_MAP = new Map<string, string>([
['pig1', 'pig1.svg'],
['pig2', 'pig2.svg'],
['pig3', 'pig3.svg']
]);
// 第一步:创建单项的节点(item)的类
export class TreeItemNode extends TreeItem {
constructor(
// readonly 只可读
public readonly label: string,
public readonly collapsibleState: TreeItemCollapsibleState,
){
super(label, collapsibleState);
}
// command: 为每项添加点击事件的命令
command = {
title: this.label, // 标题
command: 'itemClick', // 命令 ID
tooltip: this.label, // 鼠标覆盖时的小小提示框
arguments: [ // 向 registerCommand 传递的参数。
this.label, // 目前这里我们只传递一个 label
]
}
// iconPath: 为该项的图标因为我们是通过上面的 Map 获取的,所以我额外写了一个方法,放在下面
iconPath = TreeItemNode.getIconUriForLabel(this.label);
// __filename:当前文件的路径
// 重点讲解 Uri.file(join(__filename,'..', '..') 算是一种固定写法
// Uri.file(join(__filename,'..','assert', ITEM_ICON_MAP.get(label)+'')); 写成这样图标出不来
// 所以小伙伴们就以下面这种写法编写
static getIconUriForLabel(label: string):Uri {
return Uri.file(join(__filename,'..', '..' ,'src' ,'assert', ITEM_ICON_MAP.get(label)+''));
}
}
接下来我们就会用到 TreeDataProvider
: 为树数据的数据提供程序。
当我们编写完上面的代码时,我们命名的 class 会报错,但是没关系鼠标覆盖报错的地方,选中 快速修复
,就会弹出如上的标签。确认即可。
来看看完整的代码,继续在 TreeViewProvider.ts
上编写:
export class TreeItemNode extends TreeItem {
...
}
export class TreeViewProvider implements TreeDataProvider<TreeItemNode>{
// 自动弹出的可以暂不理会
onDidChangeTreeData?: import("vscode").Event<TreeItemNode | null | undefined> | undefined;
// 自动弹出
// 获取树视图中的每一项 item,所以要返回 element
getTreeItem(element: TreeItemNode): TreeItem | Thenable<TreeItem> {
return element;
}
// 自动弹出,但是我们要对内容做修改
// 给每一项都创建一个 TreeItemNode
getChildren(element?: TreeItemNode | undefined): import("vscode").ProviderResult<TreeItemNode[]> {
return ['pig1','pig2','pig3'].map(
item => new TreeItemNode(
item as string,
TreeItemCollapsibleState.None as TreeItemCollapsibleState,
)
)
}
// 这个静态方法时自己写的,你要写到 extension.ts 也可以
public static initTreeViewItem(){
// 实例化 TreeViewProvider
const treeViewProvider = new TreeViewProvider();
// registerTreeDataProvider:注册树视图
// 你可以类比 registerCommand(上面注册 Hello World)
window.registerTreeDataProvider('treeView-item',treeViewProvider);
}
}
最后一步: 完善 extension.ts
import * as vscode from 'vscode';
// 引入 TreeViewProvider 的类
import { TreeViewProvider } from './TreeViewProvider';
export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(vscode.commands.registerCommand('extension.helloWorld', () => {
vscode.window.showInformationMessage('Hello World!');
}));
// 实现树视图的初始化
TreeViewProvider.initTreeViewItem();
// 还记得我们在 TreeViewProvider.ts 文件下 TreeItemNode 下创建的 command 吗?
// 创建了 command 就需要注册才能使用
// label 就是 TreeItemNode->command 里 arguments 传递过来的
context.subscriptions.push(vscode.commands.registerCommand('itemClick', (label) => {
vscode.window.showInformationMessage(label);
}));
}
export function deactivate() {}
好了完成到这里如果小伙伴们启动插件的话,会出现报错。为什么呢?
因为 命令:itemClick
没有激活。
打开 package.json
找到 activationEvents
补上: "onCommand:itemClick"
即可。
去验证一下吧。
因为这里量比较大:给小伙伴们分个步骤好一步一步测试和检查:
1、创建 TreeItem
的类,并带上构造函数,命令,图标
2、创建 TreeDataProvider
的类,并写好 getTreeItem
、getChildren
、initTreeViewItem
3、完善 extension.js
给树视图初始化,并加上每项的点击事件
4、重要的一步: package.json
-> activationEvents
在 src
目录下创建 WebView.ts
文件,那么现在在 src
下的 .ts
文件就有三个,
分别是: extension.ts
、TreeViewProvider.ts
、WebView.ts
。接下来我们来看 WebView.ts
。
import { ExtensionContext, ViewColumn, WebviewPanel, window, commands } from 'vscode';
上面这行代码不难理解,从 vscode
中导入我们需要的 API。
ExtensionContext
: 插件上下文是扩展的私有实用程序的集合。这个类型小伙伴们可以看 extension.ts
下的 activate
方法,就是这个传递过来的。目前没有什么用,只是为了以防万一就存下来。
ViewColumn
: 表示窗口中编辑器的位置,就是如下图的位置
WebviewPanel
: 包含webview的面板,就是接下来要创建的网页视图面板。
这里重点 window 下的 createWebviewPanel() 方法
这里重点 window 下的 createWebviewPanel() 方法
window.createWebviewPanel
:
传递的参数有四:
viewType
: 标识Webview面板的类型(可随意命名)。
title
: 面板展示在 ViewColumn
上的标题。
showOptions
: 类型为 ViewColumn
, 即我们要展示在哪个面板上
options
: 设置项,下面会说,如果为空就传 {}
即可
好了,我们来看代码吧~
import { ExtensionContext, ViewColumn, WebviewPanel, window, commands } from 'vscode';
// 创建一个全局变量,类型为:WebviewPanel 或者 undefined
let webviewPanel : WebviewPanel | undefined;
// 创建一个可导出的方法,并且带上参数
export function createWebView(
context: ExtensionContext, // 上面的代码刚介绍过,可忽略
viewColumn: ViewColumn, // 窗口编辑器
label: string // 传递进来的一个 label 值,就是点击树视图项 showInformationMessage 的值
) {
if(webviewPanel === undefined) {
// 上面重点讲解了 createWebviewPanel 传递4个参数
webviewPanel = window.createWebviewPanel(
'webView', // 标识,随意命名
label, // 面板标题
viewColumn, // 展示在哪个面板上
{
retainContextWhenHidden: true, // 控制是否保持webview面板的内容(iframe),即使面板不再可见。
enableScripts: true // 下面的 html 页可以使用 Scripts
}
)
// 面板嵌入 html getIframeHtml() 方法在下面
webviewPanel.webview.html = getIframeHtml(label);
} else {
// 如果面板已经存在,重新设置标题
webviewPanel.title = label;
webviewPanel.reveal(); // Webview面板一次只能显示在一列中。如果它已经显示,则此方法将其移动到新列。
}
// onDidDispose: 如果关闭该面板,将 webviewPanel 置 undefined
webviewPanel.onDidDispose(() => {
webviewPanel = undefined;
});
return webviewPanel;
}
// 这个方法没什么了,就是一个 最简单的嵌入 iframe 的 html 页面
export function getIframeHtml(label: string) {
return `
`;
}
那么至此,我们的 WebView.ts
就完成了,现在我们来 extension.ts
页面注册激活它。
import * as vscode from 'vscode';
import { TreeViewProvider } from './TreeViewProvider';
// 导入 WebView.ts 下的 createWebView 方法
import { createWebView } from './WebView';
export function activate(context: vscode.ExtensionContext) {
...
TreeViewProvider.initTreeViewItem();
context.subscriptions.push(vscode.commands.registerCommand('itemClick', (label) => {
vscode.window.showInformationMessage(label);
// 将 context, vscode.ViewColumn.Active, label 传递进去
// vscode.ViewColumn.Active: 表示当前选中的面板
const webView = createWebView(context, vscode.ViewColumn.Active, label);
context.subscriptions.push(webView);
}));
}
那么注册完毕,运行插件看看效果吧~
这里我也给小伙伴们补充上步骤:
1、创建 createWebView
方法,面板存在与否的代码,面板销毁的代码,面板嵌入 html 的代码
2、完善 extension.ts
文件,当点击项时创建面板
好啦。那么至此已经完成了树视图和网页视图的创建,现在我们移步第三部分来阅读下vscode-网页视图之间的数据传递