树视图(Tree View)通常用来展示项目目录列表等视图。与 webview 视图不同的是,webview 视图可以嵌套网页内容,而树视图通过定义树的数据来展示内容。这与 web 开发的流程有所不同,初次接触可能会有点晦涩难懂。今天我来讲解一下树视图的使用。
package.json
配置
在使用树视图之前,首先需要配置 package.json
文件。
{
// ...
"contributes": {
"views": {
"explorer": [
{
"id": "epubTree",
"name": "Epub TOC"
}
]
}
}
// ...
}
上面的配置中,explorer
表示项目目录面板,如图所示。
explorer
是一个数组,可以定义多个视图。其中,id
是注册内容时需要使用的标识符,name
是面板上方显示的标题。
除了explorer
面板,还可以定义其他 4 种类型的面板,如下所示:
debug
调试面板scm
资源控制面板test
测试面板自定义面板,如图所示,可以自定义 logo 和显示面板。
视图提供器
配置好 package.json
后,首先要定义一个视图提供器,就是一个类用来定义怎么显示每个节点。下面是一个最基本的结构:
import * as vscode from 'vscode'
// 创建一个类 EpubTreeProvider,实现了 TreeDataProvider 接口
export default class EpubTreeProvider implements vscode.TreeDataProvider<vscode.TreeItem> {
// 创建一个事件发射器,用于通知树数据发生变化
private _onDidChangeTreeData: vscode.EventEmitter<vscode.TreeItem | undefined> = new vscode.EventEmitter<
vscode.TreeItem | undefined
>()
// 定义一个只读的事件,允许外部订阅树数据变化事件
readonly onDidChangeTreeData: vscode.Event<vscode.TreeItem | undefined> = this._onDidChangeTreeData.event
// 定义刷新方法,用于通知视图数据发生变化
refresh(): void {
this._onDidChangeTreeData.fire(undefined)
}
// 获取树中的单个项目,这里可以定义如何显示单个项目
getTreeItem(element: vscode.TreeItem): vscode.TreeItem {
return element
}
// 获取树的子元素,可以是一个异步操作
getChildren(element?: vscode.TreeItem): Thenable<vscode.TreeItem[]> {
// 在这里实现获取树的子元素的逻辑
// 可以返回一个 Promise 来异步获取子元素
// 如果没有子元素,可以返回一个空数组
// 在实际使用中,你需要根据你的插件逻辑来实现这个方法
}
}
上述代码中,getTreeItem
和getChildren
方法是视图提供器必须提供的方法,因为内部程序在创建视图时会调用这两个方法。
注册提供器
视图提供器类定义好之后,如何调用这个类呢?你不需要调用里面的方法自行创建,只需要注册让内部程序去调用。有两种注册方式。
vscode.window.registerTreeDataProvider
vscode.window.registerTreeDataProvider('epubTree', new EpubTreeProvider())
vscode.window.createTreeView
vscode.window.createTreeView('epubTree', {
treeDataProvider: new EpubTreeProvider(),
})
显示内容
注册完成后,需要显示内容。只需在getChildren
方法中添加数据。例如,添加一个简单的数据:
return new Promise((resolve, reject) => {
resolve([new vscode.TreeItem('Hello World!', vscode.TreeItemCollapsibleState.None)])
})
getChildren
方法的处理逻辑是:当没有传入element
时,返回树的顶层节点。当父节点默认展开或点击某个父节点时,会再次调用getChildren
方法,并传入父节点。你只需根据传入的element
进行数据处理即可。例如,对上述代码进行修改:
return new Promise((resolve, reject) => {
if (!element) {
resolve([new vscode.TreeItem('Hello World!', vscode.TreeItemCollapsibleState.Expanded)])
} else {
resolve([new vscode.TreeItem('happy coding', vscode.TreeItemCollapsibleState.None)])
}
})
结果如下所示:父节点是”Hello World!”,子节点是”happy coding”。
第一个参数 label
实际上,第一个参数也可以是vscode.Uri
类型,此时节点表示一个文件。例如,将”happy coding”修改如下:
vscode.Uri.file('index.html')
结果将如下所示:
在节点前面会自动添加 html 图标。当然,你也可以自定义前面的图标,只需修改 TreeItem 对象的iconPath
属性。例如,添加如下代码到getTreeItem
方法中即可自定义图标:
element.iconPath = {
light: path.join(__filename, '..', '..', 'resources', 'light', 'dependency.svg'),
dark: path.join(__filename, '..', '..', 'resources', 'dark', 'dependency.svg'),
}
第二个参数 collapsibleState
第二个参数参数是节点的展开状态。
vscode.TreeItemCollapsibleState.Expanded
表示节点是展开的。vscode.TreeItemCollapsibleState.Collapsed
表示节点是闭合的。vscode.TreeItemCollapsibleState.None
表示没有展开与否的状态,如文件。
树视图从定义到展示今天就到这里,后面继续会讲怎么自定义侧边栏的树视图和 webview 视图,以及如何添加刷新、删除等按钮。