Vscode 插件开发 - TreeView

树状视图很多插件都可能用到,通常作为一个简单的列表使用,比如管理项目依赖、展示搜索结果。那么 Vscode 的 TreeView 具体怎么玩呢?

基础操作

1.创建视图

在 package.json 的 contributes.views 节点下定义视图:

json 复制代码
{
  "name": "custom-view-samples",
  ...
  "contributes": {
    "views": {
      "my-tree-view": [
        {
          "id": "myTreeView",
          "name": "My Tree View"
        }
      ]
    }
  },
  ...
}

创建视图:

less 复制代码
vscode.window.createTreeView('myTreeView', {});

2.实现树节点

首先实现树节点的数据结构:

typescript 复制代码
class MyTreeItem extends vscode.TreeItem {
  constructor(
    public readonly label: string,
    public readonly collapsibleState: vscode.TreeItemCollapsibleState
  ) {
    super(label, collapsibleState);
    this.tooltip = `MyTreeItem - ${this.label}`;
    this.iconPath = new vscode.ThemeIcon('file');    this.command = {      title: 'Click on me',      command: 'myExtension.myTree.onClick',      arguments: [ { label } ]    };  }
}

vscode.TreeItem 预定义了诸多属性,允许我们控制 TreeItem 的外观与行为:

  • label:用于节点展示文本

  • iconPath:用于设置节点图标,可通过 new vscode.ThemeIcon('file'); 引用 Vscode 内置图标

  • description:节点描述,设置之后将展示在 label 内容之后

  • tooltip:节点提示,当鼠标悬停时展示

  • command:用于设置鼠标点击时绑定的操作,这是一个对象:

  • title:名称

  • command:命令 ID

  • arguments:参数数组

  • collapsibleState:控制节点是否能够展开

  • contextValue:用来控制树状视图的特殊行为,与 action(视图绑定的操作)产生联动,在定义 action 时,通过判断节点 contextValue 来实现在指定节点上绑定操作,如:

    // package.json "contributes": { "menus": { "view/item/context": [ { "command": "myExtension.myTree.deleteNode", "when": "viewItem == nodeA" // nodeA 为 contextValue } ] }}

3.为视图提供数据

通过实现vscode.TreeDataProvider为树状视图提供数据,主要实现以下方法:

  • getChildren(element?: T): ProviderResult<T[]>;

在加载根节点时,入参为undefined;入参有值时,表示加载该节点的子节点。T 是泛型,需要替换为自己实现的树节点类型。如:

kotlin 复制代码
  getChildren(element?: MyTreeItem): vscode.ProviderResult<MyTreeItem[]> {
    if (element) {
      return Promise.resolve(this.loadItemsOfRootNode());
    } else {
      return Promise.resolve(this.loadItemsUnder(element));
    }
  }

4.注册 TreeDataProvider

通过调用 registerTreeDataProvider 注册视图数据 Provider:

dart 复制代码
vscode.window.registerTreeDataProvider(
  'myTreeDataProvider', // 视图 ID
  new MyTreeDataProvider()
);

或者在创建视图时绑定:

php 复制代码
vscode.window.createTreeView('myTreeView', {  treeDataProvider: new MyTreeDataProvider()});

5.刷新视图

要实现视图刷新,我们需要实现 TreeDataProvider 的事件触发器属性:

  • _onDidChangeTreeData

  • onDidChangeTreeData

这两个属性一个 public 可见,一个 private 可见。实现如下:

typescript 复制代码
private _onDidChangeTreeData: vscode.EventEmitter<Dependency | undefined | null | void> = new vscode.EventEmitter<Dependency | undefined | null | void>();
readonly onDidChangeTreeData: vscode.Event<Dependency | undefined | null | void> = this._onDidChangeTreeData.event;

我们可以通过 _onDidChangeTreeData 触发刷新:

kotlin 复制代码
this._onDidChangeTreeData.fire();

Vscode 在监听到该事件后会重新渲染视图。其他 module 可以访问 onDidChangeTreeData 属性监听刷新事件:

javascript 复制代码
myTreeDataProvider.onDidChangeTreeData(() => { console.log('do something') });

进阶

1.实现拖拽

首先实现 vscode.TreeDragAndDropController,定义如下:

typescript 复制代码
export interface TreeDragAndDropController<T> {  readonly dropMimeTypes: readonly string[];  readonly dragMimeTypes: readonly string[];  handleDrag?(source: readonly T[], dataTransfer: DataTransfer, token: CancellationToken): Thenable<void> | void;  handleDrop?(target: T | undefined, dataTransfer: DataTransfer, token: CancellationToken): Thenable<void> | void;}

dropMimeTypesdragMimeTypes 的值是与树状视图的 id 关联的,也就是用来告诉 Vscode 该控制器只处理从 dragMimeTypes 指定的视图 A 拖拽到 dropMimeTypes 指定的视图 B,如:

csharp 复制代码
dropMimeTypes: readonly string[] = ['application/vnd.code.tree.myExtension_myTreeView'];dragMimeTypes: readonly string[] = ['application/vnd.code.tree.myExtension_myTreeView'];

这里的 'application/vnd.code.tree.myExtension_myTreeView' 对应了 package.json 里定义的:

json 复制代码
"views": {  "automan": [    {      "id": "myExtension.myTreeView",      "name": "MyTreeView"    }  ]},

注意命名转换规则,vscode 对此要求比较严格但官方文档解释又很简略:

  • 点号转换为下划线
  • 点好分割出的每个词必须首字母小写

接下来需要实现 handleDrophandleDrag 的逻辑。handleDrag 为拖拽开始时要做的动作,在这个方法里我们能知道拖拽开始于哪个元素,同时我们需要将数据使用 MIME_TYPE 进行标记、以传递给 handleDrop 方法:

php 复制代码
handleDrag(source: readonly MyTreeItem[], dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Thenable<void> | void {  dataTransfer.set(MIME_TYPE, new vscode.DataTransferItem(source));}

接着在 handleDrop 中取出数据,实现移动逻辑:

php 复制代码
handleDrop(target: MyTreeItem | undefined, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Thenable<void> | void {  const transferItem = dataTransfer.get(MIME_TYPE);  if (!transferItem) {    return;  }
  ...
}

将控制器绑定到视图上:

php 复制代码
vscode.window.createTreeView('myTreeView', {  treeDataProvider: new MyTreeDataProvider(),  showCollapseAll: true,  canSelectMany: true,  dragAndDropController: new MyTreeDragAndDropController()});

在创建视图的同时设置 canSelectMany,以允许同时拖拽多个项目。

相关推荐
vueTmp2 天前
VSCode 插件离线下载攻略
visual studio code
穷人小水滴6 天前
在 Android 设备上写代码 (Termux, code-server)
android·linux·visual studio code
哎呦你好9 天前
VS Code 安装后设置中文界面并添加常用插件的详细指南
编辑器·visual studio code
魔术师ID19 天前
vue2.0 组件生命周期
前端·javascript·vue.js·学习·visual studio code
MingT 明天你好!19 天前
在vs code 中无法运行npm并报无法将“npm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查
前端·npm·node.js·visual studio code
Ynov23 天前
详细解释api
javascript·visual studio code
程序员Bears1 个月前
现代前端工具链深度解析:从包管理到构建工具的完整指南
前端·python·visual studio code
formulahendry1 个月前
把 MCP Server 打包进 VS Code extension
visual studio code·vs code·mcp
程序员Bears1 个月前
深入理解CSS3:Flex/Grid布局、动画与媒体查询实战指南
前端·css3·媒体·visual studio code
优弧1 个月前
VSCode配置重置完全指南
visual studio code