大家好,我是韋恩,今天是第十二天,讓我們來學習如何提供客製化樹狀選單的選項,讓使用者可以瀏覽大綱資訊,並點擊選單執行我們的命令服務。
今天一樣會有範例讓我們練習這些api,唯有動手練習才是熟悉它們的關鍵啊!
當我們在VSCode裡面使用TreeView API,和先前提的Context Menu一樣,需要先在Contribution Points
裡註冊TreeView,讓我們來看一下註冊TreeView的json格式吧!
{
...
"contributes": {
"views": {
"${選單元件位置}": [
{
"id": "${樹狀選單Id}",
"name": "${樹狀選單名字}",
"icon": "${選單Icon路徑}",
"contextualTitle": "${樹狀選單標題}"
}
]
}
},
...
}
首先,我們需要Views
作為key值,並在下面的views物件裡設定對應的選單位置(如: explorer
),並在選單位置屬性的array陣列裡面註冊點擊後觸發的選單物件設定。
大家還記得嗎?我們常用的檔案explorer的treeView是屬於sidebar的部分,點開sideBar裡面會有不同的View。現在我們要設定TreeView,就是在contributes裡面的views屬性裡設定它。views下面屬性跟Context Menu一樣需設定要呈現TreeView的選單位置,這裡我們透過自動補全,會看到預設有以下幾個位置可以貢獻。
package.json
新增enableProposedApi : true
的設定。前面三個explorer、debug、scm的選單,分別對應到下圖ActivityBar的第一、第四、第三位置的Icon。
Test的icon是下圖第六個Icon,平常不會出現,需等執行測試才會出現。讀者們需到Run的選單上選取並執行Extension專案提供的Extension Tests
選項執行測試,這時Text Explorer才會出現。
當我們在Contribution Points
時註冊Treeview,以下面設定為例:
{
...
"contributes": {
"views": {
"explorer": [
{
"id": "day12TreeView",
"name": "Day12TreeView"
}
]
},
}
...
}
我們會在explorer的sidebar上的最下方產生一個放置TreeView的元件。
此時我們沒有像VSCode提供TreeView的DataProvider設定與資料,因此會顯示一片空白。
VSCode針對這種情境,提供了Welcome content,讓我們可以在viewsWelcome
屬性下面指定沒有跟VSCode註冊Tree的DataProvider的狀況,以下面範例為例:
{
...
"contributes": {
"viewsWelcome": [
{
"view": "day12TreeView",
"contents": "Welcome to NewTreeView \n [learn more](https://code.visualstudio.com/api/extension-guides/tree-view/).\n[Resgister Data Provider](command:day12-treeview-practice.registerDataProvider)",
}
],
}
...
}
我們需先指定welcome內容的viewId(此處是剛才註冊的day12TreeView),再來,我們可以指定將顯示的內容,並且使用[LinkName](LinUrl)
的markdown語法建立超連結,同時可以透過[ButtonName](CommandId)
的語法顯示一個點擊後觸發命令的按鈕,結果如下:
好的,以上就是跟TreeView在Contribution Point
的設定,接下來,我們將透過TreeView API來顯示對應的資料。API操作的部分,我們會用專案練習的方式一步一步介紹,讓我們開啟VSCode的Extension專案開始練習吧!
yo code
如果環境建立有問題,請再次參照之前的教學建立專案與環境喔!
Contribution Points
命令配置:讓我們照以下指示設定extension專案,首先於packagage.json,我們要在Contribution Points
裡的View註冊TreeView跟相關Command,如下所示:
{
...
"contributes": {
"views": {
"explorer": [
{
"id": "day12TreeView",
"contextualTitle": "Day12-TreeViewTitle",
"name": "Day12TreeView"
}
]
},
"viewsWelcome": [
{
"view": "day12TreeView",
"contents": "Welcome to NewTreeView \n [learn more](https://code.visualstudio.com/api/extension-guides/tree-view/).\n[Resgister Data Provider](command:day12-treeview-practice.registerDataProvider)",
}
],
"commands": [
{
"command": "day12-treeview-practice.registerDataProvider",
"title": "Day12: Register Treeview DataProvider"
}
]
},
...
}
activationEvents
配置:設置完Command後,我們一樣要在package.json
配置activationEvents
{
...
"activationEvents": [
"*"
],
...
}
extension.ts
範例程式配置:
import * as vscode from 'vscode';
export function activate(context: vscode.ExtensionContext) {
let disposable = vscode.commands.registerCommand('day12-treeview-practice.registerDataProvider', () => {
vscode.window.showInformationMessage('Hello World from day12-treeview-practice!');
});
context.subscriptions.push(disposable);
}
export function deactivate() {}
請讀者照順序配置今天的vscode專案,接下來,我們要開始撰寫今天的TreeView邏輯了!
在昨天的介紹裡,我已經提過我們需要先為TreeView提供一個DataProvider的class,並new出他的實例(instance)提供給register方法,因此先讓我們實作VSCode給定的Interface介面,如下所示:
從圖可以發現,vscode.TreeDataProvider
雖然被實作,可是下面卻有紅色邱蚓狀的語法錯誤提示,讓我們把滑鼠移到發生錯誤的文字上。
可以看到,VSCode告訴我們這個vscode.TreeDataProvider
需要提供一個泛型參數,在此處是vscode.TreeItem
,因此也讓我們先繼承VSCode內建的TreeItem
的class,並設定item的label屬性及點擊後觸發的command屬性等等,並將其類型提供給TreeDataProvider,如下所示:
現在換DataProvider下方出現紅色邱蚓狀的語法錯誤提示,因此再讓我們把鼠標移到錯誤文字上,點擊一下,再按⌘(command)
+.
,此時會觸發VSCode的Code Action
,展開一個選單:
我們可以清楚看到,選單上面有一個Implement interface vscode.TreeDataProvider<TreeItem>
的選項,請直接點擊下去,DataProvider的類別會自動產生需實作的方法的骨架。
有三個需實作的方法,分別是
TreeDataProvider方法 | 描述 |
---|---|
getTreeItem | 回傳TreeView呈現的TreeItem Element。 |
getChildren | 回傳TreeView底下的treeItem們。 |
onDidChangeTreeData | 回傳VSCode提供的EventEmitter的event監聽方法,通知DataProvider的訂閱者資料已經發生變化。 |
讓我們先實作getTreeItem
與getChildren
方法吧,如下所示:
class TreeViewItem extends vscode.TreeItem {
constructor(label: string, collapsibleState?: vscode.TreeItemCollapsibleState) {
super(label, collapsibleState);
}
}
class DataProvider implements vscode.TreeDataProvider<TreeViewItem> {
getTreeItem(element: TreeViewItem): vscode.TreeItem | Thenable<vscode.TreeItem> {
return element;
}
getChildren(element?: TreeViewItem): vscode.ProviderResult<TreeViewItem[]> {
return Promise.resolve([
new TreeViewItem('TreeItem-01'),
new TreeViewItem('TreeItem-02'),
new TreeViewItem('TreeItem-03'),
])
}
}
export function activate(context: vscode.ExtensionContext) {
let disposable = vscode.commands.registerCommand('day12-treeview-practice.registerDataProvider', () => {
vscode.window.registerTreeDataProvider('day12TreeView', new DataProvider());
vscode.window.showInformationMessage('Create day12-treeview!');
});
context.subscriptions.push(disposable);
}
export function deactivate() {}
好的,現在點擊UI上的Register按鈕,可以看到TreeView已經正確顯示。
好啦,今天,我們創建了一個最基本的TreeView,並了解TreeView的使用方法。在範例裡,我們使用了大量typescript的繼承(extends)、介面(interface)實作(implement)等技巧,對初學者而言,確實需要不少typescript和javascript ES6的class語法知識才能順利掌握。如對範例有疑問或覺得難懂,請在下方留言給我,我會嘗試為您解答!
TreeView有更多的應用,明天我們會解析DataProvider的設計理念,並用開始實際的案例練習。
我們明天見,謝謝大家。