树视图(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 视图,以及如何添加刷新、删除等按钮。