多多读书
1049 字
5 分钟
VSCode插件开发六:树视图其实也没那么难

树视图(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 来异步获取子元素
    // 如果没有子元素,可以返回一个空数组
    // 在实际使用中,你需要根据你的插件逻辑来实现这个方法
  }
}

上述代码中,getTreeItemgetChildren方法是视图提供器必须提供的方法,因为内部程序在创建视图时会调用这两个方法。

注册提供器#

视图提供器类定义好之后,如何调用这个类呢?你不需要调用里面的方法自行创建,只需要注册让内部程序去调用。有两种注册方式。

  1. vscode.window.registerTreeDataProvider
vscode.window.registerTreeDataProvider('epubTree', new EpubTreeProvider())
  1. 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 视图,以及如何添加刷新、删除等按钮。

VSCode插件开发六:树视图其实也没那么难
https://fuwari.vercel.app/posts/20230905/
作者
我也困了
发布于
2023-09-05
许可协议
CC BY-NC-SA 4.0