vscode树形菜单栏实现

最终呈现样式如下:

首先需要在packge.json中定义命令command, 定义view,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
"contributes": {
"commands": [
{
"command": "datadic-auth",
"title": "当前管理用户设置",
"category": "DHC"
},
{
"command": "datadicmanager-table-insert",
"title": "数据表字典新增",
"category": "DHC"
},
{
"command": "datadicmanager-table-search",
"title": "数据表字典查询",
"category": "DHC"
},
{
"command": "datadicmanager-view-insert",
"title": "视图字典新增",
"category": "DHC"
},
{
"command": "datadicmanager-view-search",
"title": "视图字典查询",
"category": "DHC"
},
{
"command": "datadicmanager-view-columninsert",
"title": "字段关联视图新增",
"category": "DHC"
},
{
"command": "datadicmanager-view-columnsearch",
"title": "字段关联视图查询",
"category": "DHC"
},
{
"command": "datadicmanager-seq-insert",
"title": "序列新增",
"category": "DHC"
},
{
"command": "datadicmanager-seq-search",
"title": "序列查询",
"category": "DHC"
},
{
"command": "datadicmanager-imp",
"title": "数据字典导入",
"category": "DHC"
},
{
"command": "datadicmanager-exp",
"title": "数据字典导出",
"category": "DHC"
},
{
"command": "usermanager-insert",
"title": "数据字典用户新增",
"category": "DHC"
},
{
"command": "usermanager-search",
"title": "数据字典用户查询",
"category": "DHC"
}
],
"viewsContainers": {
"activitybar": [
{
"id": "package-explorer",
"title": "辅助插件",
"icon": "images/activebar3.svg"
}
]
},
"views": {
"package-explorer": [
{
"id": "nodeDependencies",
"name": "系统配置模块"
},
{
"id": "dataDictionary",
"name": "数据字典系统"
}
]
},
```

在extension.ts文件中注册实现

![](/images/vscode1.png)



require('./webview/datadic/index')(context);的代码如下

import { ExtensionContext } from ‘vscode’;

module.exports = function(context: ExtensionContext) {
// 加载数据字典菜单列表
require(‘./auth’)(context);
require(‘./datadicExp’)(context);
require(‘./datadicImp’)(context);
require(‘./seqInsert’)(context);
require(‘./seqSearch’)(context);
require(‘./tableInsert’)(context);
require(‘./tableSearch’)(context);
require(‘./usermanagerInsert’)(context);
require(‘./usermanagerSearch’)(context);
require(‘./viewColumnInsert’)(context);
require(‘./viewColumnSearch’)(context);
require(‘./viewInsert’)(context);
require(‘./viewSearch’)(context);
}

1
2
3


initTreeList代码实现如下:

import as vscode from ‘vscode’;
import
as path from ‘path’;

export class DatadicMenuItemProvider implements vscode.TreeDataProvider {
private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter();
readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event;

public static tree: Dependency[] = [];
public static mrConnect: myTreeFilesNode[] = [{ fileName: "当前管理用户设置", command: {command: 'datadic-auth', title: '当前管理用户设置'} }];
public static mrDataDic: myTreeFilesNode[] = [{ fileName: "数据表维护" }, { fileName: "数据视图维护" }, { fileName: "序列(sequence)维护" }, { fileName: "数据字典导入导出" }];
public static mrUsers: myTreeFilesNode[] = [{ fileName: "数据字典用户新增", command: {command: 'usermanager-insert', title: '数据字典用户新增'} }, { fileName: "数据字典用户查询", command: {command: 'usermanager-search', title: '数据字典用户查询'} }];
public static mrTables: myTreeFilesNode[] = [{ fileName: "数据表字典新增", command: {command: 'datadicmanager-table-insert', title: '数据表字典新增'} }, { fileName: "数据表字典查询", command: {command: 'datadicmanager-table-search', title: 'datadicmanager-table-search'} }];
public static mrViews: myTreeFilesNode[] = [{ fileName: "视图字典新增", command: {command: 'datadicmanager-view-insert', title: '视图字典新增'} }, { fileName: "视图字典查询", command: {command: 'datadicmanager-view-search', title: '视图字典查询'} }, { fileName: "字段关联视图新增", command: {command: 'datadicmanager-view-columninsert', title: '字段关联视图新增'} }, { fileName: "字段关联视图查询", command: {command: 'datadicmanager-view-columnsearch', title: '字段关联视图查询'} }];
public static mrSeq: myTreeFilesNode[] = [{ fileName: "序列新增", command: {command: 'datadicmanager-seq-insert', title: '序列新增'} }, { fileName: "序列查询", command: {command: 'datadicmanager-seq-search', title: '序列查询'} }];
public static mrImpOrExp: myTreeFilesNode[] = [{ fileName: "数据字典导入", command: {command: 'datadicmanager-imp', title: '数据字典导入'} }, { fileName: "数据字典导出", command: {command: 'datadicmanager-exp', title: '数据字典导出'} }];

constructor() {
}

public static initTreeList() {
    let datadicMenuItemProvider = new DatadicMenuItemProvider();
    vscode.window.registerTreeDataProvider('dataDictionary', datadicMenuItemProvider);
    DatadicMenuItemProvider.tree.push(new Dependency("连接管理", myTreeKind.MR,DatadicMenuItemProvider.mrConnect, vscode.TreeItemCollapsibleState.Collapsed, undefined),
    new Dependency("数据字典维护", myTreeKind.MR,DatadicMenuItemProvider.mrDataDic, vscode.TreeItemCollapsibleState.Collapsed, undefined),
    new Dependency("数据字典用户管理", myTreeKind.MR,DatadicMenuItemProvider.mrUsers, vscode.TreeItemCollapsibleState.Collapsed, undefined)
    );

}

refresh(): void {
    this._onDidChangeTreeData.fire();
}

getTreeItem(element: Dependency): vscode.TreeItem {
    return element;
}

getChildren(element?: Dependency): Thenable<Dependency[]> {
    let trees: Dependency[] = [];
    if(element == undefined) {
        if(DatadicMenuItemProvider.tree != undefined) {
            for(let i=0; i< DatadicMenuItemProvider.tree.length; i++) {
                let currentElement = DatadicMenuItemProvider.tree[i];
                if(currentElement.label == '连接管理') {
                    let temp: Dependency = new Dependency(currentElement.label, myTreeKind.MR,DatadicMenuItemProvider.mrConnect, vscode.TreeItemCollapsibleState.Collapsed, undefined);
                    temp.contextValue = 'connectTreeNode';
                    temp.tooltip = 'connectTreeNode';
                    temp.iconPath = currentElement.iconPath;
                    trees.push(temp);
                }
                if(currentElement.label == '数据字典维护') {
                    let temp: Dependency = new Dependency(currentElement.label, myTreeKind.MR,DatadicMenuItemProvider.mrDataDic, vscode.TreeItemCollapsibleState.Collapsed, undefined);
                    temp.contextValue = 'datadicManagerTreeNode';
                    temp.tooltip = 'datadicManagerTreeNode';
                    temp.iconPath = currentElement.iconPath;
                    trees.push(temp);
                }
                if(currentElement.label == '数据字典用户管理') {
                    let temp: Dependency = new Dependency(currentElement.label, myTreeKind.MR,DatadicMenuItemProvider.mrUsers, vscode.TreeItemCollapsibleState.Collapsed, undefined);
                    temp.contextValue = 'datadicUserManagerTreeNode';
                    temp.tooltip = 'datadicUserManagerTreeNode';
                    temp.iconPath = currentElement.iconPath;
                    trees.push(temp);
                }
            }
        }
    } else {
        if(element.label == '连接管理') {
            if (element.kind == myTreeKind.MR) {
                for (let i = 0;i < element.mrFiles.length; i++) {
                    let currentElement = element.mrFiles[i];
                    let mrreviewnode: Dependency = new Dependency(currentElement.fileName, myTreeKind.file,[], vscode.TreeItemCollapsibleState.None, currentElement.command);
                    trees.push(mrreviewnode);
                }
            }
        }
        if(element.label == '数据字典维护') {
            if (element.kind == myTreeKind.MR) {
                for (let i = 0;i < element.mrFiles.length; i++) {
                    let currentElement = element.mrFiles[i];
                    if(currentElement.fileName == '数据表维护') {
                        let mrreviewnode: Dependency = new Dependency(currentElement.fileName, myTreeKind.MR, DatadicMenuItemProvider.mrTables, vscode.TreeItemCollapsibleState.Collapsed, undefined);
                        trees.push(mrreviewnode);
                    }
                    if(currentElement.fileName == '数据视图维护') {
                        let mrreviewnode: Dependency = new Dependency(currentElement.fileName, myTreeKind.MR, DatadicMenuItemProvider.mrViews, vscode.TreeItemCollapsibleState.Collapsed, undefined);
                        trees.push(mrreviewnode);
                    }
                    if(currentElement.fileName == '序列(sequence)维护') {
                        let mrreviewnode: Dependency = new Dependency(currentElement.fileName, myTreeKind.MR, DatadicMenuItemProvider.mrSeq, vscode.TreeItemCollapsibleState.Collapsed, undefined);
                        trees.push(mrreviewnode);
                    }
                    if(currentElement.fileName == '数据字典导入导出') {
                        let mrreviewnode: Dependency = new Dependency(currentElement.fileName, myTreeKind.MR, DatadicMenuItemProvider.mrImpOrExp, vscode.TreeItemCollapsibleState.Collapsed, undefined);
                        trees.push(mrreviewnode);
                    }

                }
            }
        }
        if(element.label == '数据字典用户管理') {
            if (element.kind == myTreeKind.MR) {
                for (let i = 0;i < element.mrFiles.length; i++) {
                    let currentElement = element.mrFiles[i];
                    let mrreviewnode: Dependency = new Dependency(currentElement.fileName, myTreeKind.file,[], vscode.TreeItemCollapsibleState.None, currentElement.command);
                    trees.push(mrreviewnode);
                }
            }
        }
        if(element.label == '数据表维护') {
            if (element.kind == myTreeKind.MR) {
                for (let i = 0;i < element.mrFiles.length; i++) {
                    let currentElement = element.mrFiles[i];
                    let mrreviewnode: Dependency = new Dependency(currentElement.fileName, myTreeKind.file,[], vscode.TreeItemCollapsibleState.None, currentElement.command);
                    trees.push(mrreviewnode);
                }
            }
        }
        if(element.label == '数据视图维护') {
            if (element.kind == myTreeKind.MR) {
                for (let i = 0;i < element.mrFiles.length; i++) {
                    let currentElement = element.mrFiles[i];
                    let mrreviewnode: Dependency = new Dependency(currentElement.fileName, myTreeKind.file,[], vscode.TreeItemCollapsibleState.None, currentElement.command);
                    trees.push(mrreviewnode);
                }
            }
        }
        if(element.label == '序列(sequence)维护') {
            if (element.kind == myTreeKind.MR) {
                for (let i = 0;i < element.mrFiles.length; i++) {
                    let currentElement = element.mrFiles[i];
                    let mrreviewnode: Dependency = new Dependency(currentElement.fileName, myTreeKind.file,[], vscode.TreeItemCollapsibleState.None, currentElement.command);
                    trees.push(mrreviewnode);
                }
            }
        }
        if(element.label == '数据字典导入导出') {
            if (element.kind == myTreeKind.MR) {
                for (let i = 0;i < element.mrFiles.length; i++) {
                    let currentElement = element.mrFiles[i];
                    let mrreviewnode: Dependency = new Dependency(currentElement.fileName, myTreeKind.file,[], vscode.TreeItemCollapsibleState.None, currentElement.command);
                    trees.push(mrreviewnode);
                }
            }
        }

    }
    return new Promise(resolve => {
        return resolve(trees);
    })
}

}

export interface myTreeFilesNode {
fileName: string;
command?: vscode.Command
}

export enum myTreeKind {
MR,
file,
comment,
catatory,
issue
}

export class Dependency extends vscode.TreeItem {

constructor(
    public readonly label: string,
    public readonly kind: myTreeKind,
    public readonly mrFiles: myTreeFilesNode[],
    public readonly collapsibleState: vscode.TreeItemCollapsibleState,
    public readonly command?: vscode.Command
) {
    super(label, collapsibleState);
}

iconPath = {
    light: path.join(__filename, '..', 'images', 'light', 'activebar.svg'),
    dark: path.join(__filename, '..', '..', 'images', 'dark', 'dependency.svg')
};

}

1
2

单个webview(例如:Auth.js 文件)实现如下:

import * as path from ‘path’;
import { ExtensionContext, WebviewPanel, commands, window, ViewColumn, Uri } from ‘vscode’;

function loadScript(context: ExtensionContext, path: string) {
//console.log(Uri.file(context.asAbsolutePath(path)).with({ scheme: ‘vscode-resource’}).toString())
return <script src="${Uri.file(context.asAbsolutePath(path)).with({ scheme: 'vscode-resource' }).toString()}"></script>;
}
function loadCssFile(context: ExtensionContext, path: string) {
//console.log(Uri.file(context.asAbsolutePath(path)).with({ scheme: ‘vscode-resource’}).toString())
return <link href="${Uri.file(context.asAbsolutePath(path)).with({ scheme: 'vscode-resource' }).toString()}" rel="stylesheet">;
}

/**

  • 取能被Webview加载的HTML内容
  • @param context 上下文
  • @param name
    */
    function getWebViewContent(context: ExtensionContext, name: string) {
    return `
    <!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <style type="text/css">
      .Resizer {
        background: #000;
        opacity: .2;
        z-index: 1;
        -moz-box-sizing: border-box;
        -webkit-box-sizing: border-box;
        box-sizing: border-box;
        -moz-background-clip: padding;
        -webkit-background-clip: padding;
        background-clip: padding-box;
      }
      .Resizer:hover {
        -webkit-transition: all 2s ease;
        transition: all 2s ease;
      }
      .Resizer.horizontal {
        height: 5px;
        margin: -5px 0;
        border-top: 5px solid rgba(255, 255, 255, 0);
        border-bottom: 5px solid rgba(255, 255, 255, 0);
        cursor: row-resize;
        width: 100%;
      }
      .Resizer.horizontal:hover {
        border-top: 5px solid rgba(0, 0, 0, 0.5);
        border-bottom: 5px solid rgba(0, 0, 0, 0.5);
      }
      .Resizer.vertical {
        width: 5px;
        margin: 0 -5px;
        border-left: 5px solid rgba(255, 255, 255, 0);
        border-right: 5px solid rgba(255, 255, 255, 0);
        cursor: col-resize;
      }
      .Resizer.vertical:hover {
        border-left: 5px solid rgba(0, 0, 0, 0.5);
        border-right: 5px solid rgba(0, 0, 0, 0.5);
      }
      .Resizer.disabled {
        cursor: not-allowed;
      }
      .Resizer.disabled:hover {
        border-color: transparent;
      }
      #container {
        height: 100%
      }
      .noselect {
        moz-user-select: -moz-none;
        -moz-user-select: none;
        -o-user-select: none;
        -khtml-user-select: none;
        -webkit-user-select: none;
        -ms-user-select: none;
        user-select: none;
      }
      .vddl-list, .vddl-draggable {
        position: relative;
        margin-right: 1px;
        margin-bottom: 2px;
      }
    
      .vddl-dragging-source {
        display: none;
      }
    
      input, button, select, textarea {
        outline: none;
      }
    
      textarea {
        resize: none;
      }
    
      .inactive {
        outline: 1px dashed #080808
      }
    </style>
    ${loadCssFile(context, `out/${name}/bundle.css`)}
    ${loadCssFile(context, `out/${name}/vendor.css`)}
    <script>
      try {
        window.vscode = acquireVsCodeApi();
    
      } catch (e) {
        console.error(e);
      }
    </script>
    


    <div id="root">资源加载中.....</div>
    ${loadScript(context, `out/${name}/auth.js`)}
    ${loadScript(context, `out/${name}/vendor.js`)}
    



    `
    }

module.exports = function(context: ExtensionContext) {
let datadicPanel: WebviewPanel | undefined = undefined;

context.subscriptions.push(
    commands.registerCommand('datadic-auth', (uri) => {
      const columnToShowIn = window.activeTextEditor
        ? window.activeTextEditor.viewColumn
        : undefined;
      if (datadicPanel) {
        // If we already have a panel, show it in the target column
        datadicPanel.reveal(columnToShowIn);
      } else {
        datadicPanel = window.createWebviewPanel('Antd', '当前管理用户设置', ViewColumn.Active, {
          enableScripts: true,
          retainContextWhenHidden: true,
          localResourceRoots: [Uri.file(path.join(context.extensionPath, 'out'))]
        });
        datadicPanel.webview.html = getWebViewContent(context, 'datadic');
        datadicPanel.webview.onDidReceiveMessage(message => {

        }, undefined, context.subscriptions)
      }
      datadicPanel.onDidDispose(
        () => {
          datadicPanel = undefined;
        },
        null,
        context.subscriptions
      );
    })
  );

}
`