VS Code插件开发教程--树视图+网页视图--完整demo+图--2

3,589 阅读7分钟

简介

你好!

本文定位为初次接触vs code插件开发的小伙伴,开始有详细的教程如何一步一步的运用基础的插件开发

接下来会用完成的 demo 教大家 treeView 和 webView 的初级完成开发流程。小伙伴耐心跟着代码敲一遍能学会的哈。

先给小伙伴们看一下本文的目录架构:

  • 一、介绍
  • 二、安装
  • 三、初识 VS code 插件 demo
  • 四、treeView: 重识 package.json
  • 五、treeView: 在视图中显示想要的 item
  • 六、创建 webView 并嵌入百度页面
  • 七、不同 item 显示不同的页面(数据传递: VS code -> html)
  • 八、iframe 页面的数据传递指 VS code(iframe -> html -> vscode)

此文章为第二部分,如需从头开始阅读,请移步第一部分

四、treeView: 在视图中显示想要的 item

首先,我们先在 src 下创建 TreeViewProvider.ts 文件。重要的代码都展示在这里了。

import { TreeItem, TreeItemCollapsibleState, TreeDataProvider, Uri, window } from 'vscode';
import { join } from 'path';

这里重点讲解一下上面这两句代码:

vscode 提供了很多的 API 让我们使用,我们可以打开官网 VS code API

我讲解一下上面需要用到的几个项:

TreeItem:

在这里插入图片描述

创建 TreeItem 类型的构造函数,传递参数 labelcollapsibleState.

label: tree 该项的标题。

collapsibleState: 该项是否折叠状态。参数有三: Collapsed(折叠状态)、Expanded(展开状态)、None(无状态)。

?: 代表参数为非必填项,可不传。注意:非必填项,必须放在最后面

TreeItemCollapsibleState: 就是 collapsibleState 的类型。

TreeDataProvider: 为树数据的数据提供程序(如果不理解,可以先放着,一会看代码)。

Uri: 通用资源标识符,表示磁盘上的文件或其他资源(用来读取文件路径)。

join: 用来拼接文件路径。

import { TreeItem, TreeItemCollapsibleState, TreeDataProvider, Uri, window } from 'vscode';
import { join } from 'path';

// 创建每一项 label 对应的图片名称
// 其实就是一个Map集合,用 ts 的写法
const ITEM_ICON_MAP = new Map<string, string>([
    ['pig1', 'pig1.svg'],
    ['pig2', 'pig2.svg'],
    ['pig3', 'pig3.svg']
]);

// 第一步:创建单项的节点(item)的类
export class TreeItemNode extends TreeItem {

    constructor(
        // readonly 只可读
        public readonly label: string,
        public readonly collapsibleState: TreeItemCollapsibleState,
    ){
        super(label, collapsibleState);
    }

    // command: 为每项添加点击事件的命令
    command = {
        title: this.label,          // 标题
        command: 'itemClick',       // 命令 ID
        tooltip: this.label,        // 鼠标覆盖时的小小提示框
        arguments: [                // 向 registerCommand 传递的参数。
            this.label,             // 目前这里我们只传递一个 label
        ]
    }
    
    // iconPath: 为该项的图标因为我们是通过上面的 Map 获取的,所以我额外写了一个方法,放在下面
    iconPath = TreeItemNode.getIconUriForLabel(this.label);

    // __filename:当前文件的路径
    // 重点讲解 Uri.file(join(__filename,'..', '..') 算是一种固定写法
    // Uri.file(join(__filename,'..','assert', ITEM_ICON_MAP.get(label)+''));   写成这样图标出不来
    // 所以小伙伴们就以下面这种写法编写
    static getIconUriForLabel(label: string):Uri {
        return Uri.file(join(__filename,'..', '..' ,'src' ,'assert', ITEM_ICON_MAP.get(label)+''));
    }
}

在这里插入图片描述

接下来我们就会用到 TreeDataProvider: 为树数据的数据提供程序。

在这里插入图片描述

当我们编写完上面的代码时,我们命名的 class 会报错,但是没关系鼠标覆盖报错的地方,选中 快速修复,就会弹出如上的标签。确认即可。

来看看完整的代码,继续在 TreeViewProvider.ts 上编写:

export class TreeItemNode extends TreeItem {
    ...
}

export class TreeViewProvider implements TreeDataProvider<TreeItemNode>{
    // 自动弹出的可以暂不理会
    onDidChangeTreeData?: import("vscode").Event<TreeItemNode | null | undefined> | undefined;    
    
    // 自动弹出
    // 获取树视图中的每一项 item,所以要返回 element
    getTreeItem(element: TreeItemNode): TreeItem | Thenable<TreeItem> {
        return element;
    }

    // 自动弹出,但是我们要对内容做修改
    // 给每一项都创建一个 TreeItemNode
    getChildren(element?: TreeItemNode | undefined): import("vscode").ProviderResult<TreeItemNode[]> {
    
        return ['pig1','pig2','pig3'].map(
        
            item => new TreeItemNode(
                item as string,
                TreeItemCollapsibleState.None as TreeItemCollapsibleState,
            )
        )
    }

    // 这个静态方法时自己写的,你要写到 extension.ts 也可以
    public static initTreeViewItem(){
    
        // 实例化 TreeViewProvider
        const treeViewProvider = new TreeViewProvider();
        
        // registerTreeDataProvider:注册树视图
        // 你可以类比 registerCommand(上面注册 Hello World)
        window.registerTreeDataProvider('treeView-item',treeViewProvider);
    }
}

最后一步: 完善 extension.ts

import * as vscode from 'vscode';

// 引入 TreeViewProvider 的类
import { TreeViewProvider } from './TreeViewProvider';

export function activate(context: vscode.ExtensionContext) {

	context.subscriptions.push(vscode.commands.registerCommand('extension.helloWorld', () => {
		vscode.window.showInformationMessage('Hello World!');
	}));
	
    // 实现树视图的初始化
	TreeViewProvider.initTreeViewItem();
    
    // 还记得我们在 TreeViewProvider.ts 文件下 TreeItemNode 下创建的 command 吗?
    // 创建了 command 就需要注册才能使用
    // label 就是 TreeItemNode->command 里 arguments 传递过来的
    context.subscriptions.push(vscode.commands.registerCommand('itemClick', (label) => {
		vscode.window.showInformationMessage(label);
	}));
}
export function deactivate() {}

好了完成到这里如果小伙伴们启动插件的话,会出现报错。为什么呢?

因为 命令:itemClick 没有激活。

打开 package.json 找到 activationEvents 补上: "onCommand:itemClick" 即可。

去验证一下吧。

在这里插入图片描述

因为这里量比较大:给小伙伴们分个步骤好一步一步测试和检查:

1、创建 TreeItem 的类,并带上构造函数,命令,图标

2、创建 TreeDataProvider 的类,并写好 getTreeItemgetChildreninitTreeViewItem

3、完善 extension.js 给树视图初始化,并加上每项的点击事件

4、重要的一步: package.json -> activationEvents

五、创建 webView 并嵌入百度页面

src 目录下创建 WebView.ts 文件,那么现在在 src 下的 .ts 文件就有三个,

分别是: extension.tsTreeViewProvider.tsWebView.ts。接下来我们来看 WebView.ts

import { ExtensionContext, ViewColumn, WebviewPanel, window, commands } from 'vscode';

上面这行代码不难理解,从 vscode 中导入我们需要的 API。

ExtensionContext: 插件上下文是扩展的私有实用程序的集合。这个类型小伙伴们可以看 extension.ts 下的 activate 方法,就是这个传递过来的。目前没有什么用,只是为了以防万一就存下来。

ViewColumn: 表示窗口中编辑器的位置,就是如下图的位置

在这里插入图片描述

WebviewPanel: 包含webview的面板,就是接下来要创建的网页视图面板。

这里重点 window 下的 createWebviewPanel() 方法

这里重点 window 下的 createWebviewPanel() 方法

window.createWebviewPanel:

在这里插入图片描述

传递的参数有四:

viewType: 标识Webview面板的类型(可随意命名)。

title: 面板展示在 ViewColumn 上的标题。

showOptions: 类型为 ViewColumn, 即我们要展示在哪个面板上

options: 设置项,下面会说,如果为空就传 {} 即可

好了,我们来看代码吧~

import { ExtensionContext, ViewColumn, WebviewPanel, window, commands } from 'vscode';
// 创建一个全局变量,类型为:WebviewPanel 或者 undefined
let webviewPanel : WebviewPanel | undefined;

// 创建一个可导出的方法,并且带上参数
export function createWebView(

    context: ExtensionContext,      // 上面的代码刚介绍过,可忽略
    viewColumn: ViewColumn,         // 窗口编辑器
    label: string                   // 传递进来的一个 label 值,就是点击树视图项 showInformationMessage 的值
    
) {

    if(webviewPanel === undefined) {
    
        // 上面重点讲解了 createWebviewPanel 传递4个参数
        webviewPanel = window.createWebviewPanel(
        
            'webView',                          // 标识,随意命名
            label,                              // 面板标题
            viewColumn,                         // 展示在哪个面板上
            {
                retainContextWhenHidden: true,  // 控制是否保持webview面板的内容(iframe),即使面板不再可见。
                enableScripts: true             // 下面的 html 页可以使用 Scripts
            }
            
        )
        
        // 面板嵌入 html getIframeHtml() 方法在下面
        webviewPanel.webview.html = getIframeHtml(label);
        
    } else {
    
        // 如果面板已经存在,重新设置标题
        webviewPanel.title = label;
        webviewPanel.reveal();  // Webview面板一次只能显示在一列中。如果它已经显示,则此方法将其移动到新列。
    }

    // onDidDispose: 如果关闭该面板,将 webviewPanel 置 undefined
    webviewPanel.onDidDispose(() => {
        webviewPanel = undefined;
    });

    return webviewPanel;
}

// 这个方法没什么了,就是一个 最简单的嵌入 iframe 的 html 页面
export function getIframeHtml(label: string) {
    return `
    <!DOCTYPE html>
    <html lang="en">
        <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <style>
            html,
            body {
                margin: 0 !important;
                padding: 0 !important;
                width: 100%;
                height: 100%;
            }
            .iframeDiv {
                width: 100%;
                height: 100%;
            }
        </style>
        </head>

        <body>
        <iframe id='iframe1' class="iframeDiv" src="http://www.baidu.com/" scrolling="auto"></iframe>
        </body>
    </html>
    `;
}

那么至此,我们的 WebView.ts 就完成了,现在我们来 extension.ts 页面注册激活它。

import * as vscode from 'vscode';
import { TreeViewProvider } from './TreeViewProvider';

// 导入 WebView.ts 下的 createWebView 方法
import { createWebView } from './WebView';

export function activate(context: vscode.ExtensionContext) {

    ...
    
    TreeViewProvider.initTreeViewItem();
    
	context.subscriptions.push(vscode.commands.registerCommand('itemClick', (label) => {
	
		vscode.window.showInformationMessage(label);
		
        // 将 context, vscode.ViewColumn.Active, label 传递进去
        // vscode.ViewColumn.Active: 表示当前选中的面板
		const webView = createWebView(context, vscode.ViewColumn.Active, label);
		context.subscriptions.push(webView);
	}));
}

那么注册完毕,运行插件看看效果吧~

在这里插入图片描述

这里我也给小伙伴们补充上步骤:

1、创建 createWebView 方法,面板存在与否的代码,面板销毁的代码,面板嵌入 html 的代码

2、完善 extension.ts 文件,当点击项时创建面板

好啦。那么至此已经完成了树视图和网页视图的创建,现在我们移步第三部分来阅读下vscode-网页视图之间的数据传递