总共分为以下几个步骤:
- 初始化插件模板,生成一个插件项目
- 创建插件的视图容器和展示插件内容的视图
- 把插件运行起来,开始可视化的开发调试
- 为视图提供数据
- 发布插件
一、初始化插件模板
- 全局安装yo 和 generator-code
npm install -g yo generator-code
2.运行如下命令
yo code
3.各种配置项选择完毕之后,会生成一个项目
二、创建插件的视图容器和展示插件内容的视图
- 创建一个视图容器,通过修改package.json文件来创建
"contributes": {
// 自定义插件的icon,展示在VSCode侧边栏上
"viewsContainers": {
"activitybar": [
{
"id": "custom-plugin",
"title": "自定义插件",
"icon": "images/custom.svg"
}
]
},
}
效果如下图,我在https://www.iconfont.cn/上找了一个自行车的icon
2.在视图容器中添加一个视图,继续配置package.json文件
"contributes": {
// 自定义插件的icon,展示在VSCode侧边栏上
"viewsContainers": {
"activitybar": [
{
"id": "custom-plugin",
"title": "自定义插件",
"icon": "images/custom.svg"
}
]
},
"views": {
// 和viewsContainers的id相对应
"custom-plugin": [
{
"name": "我的插件",
"id": "plugin-list"
}
]
},
}
三、把插件运行起来,开始可视化的开发调试
四、往视图中添加内容
假如我们要做一个查看基金涨跌数据的插件,大概需要3个步骤
- 修改项目中的extension.ts文件,为视图提供数据
import { ExtensionContext, commands, window, workspace } from 'vscode';
import Provider from './Provider';
// 激活插件时调用
export function activate(context: ExtensionContext) {
// 基金类
const provider = new Provider();
// 数据注册,第一个参数是在package.json文件中配置的视图id
window.registerTreeDataProvider('custom-plugin', provider);
}
// 停用插件时调用
export function deactivate() {}
其中registerTreeDataProvider是VSCode提供的一个API,用于给视图注入数据。
要想active方法起作用,还需要配置什么时候激活触发这个函数的执行,继续配置package.json文件,
"activationEvents": [
"onView:plugin-list" // 配置在插件视图打开的时候激活插件
]
- provider文件如何写?
import { workspace, TreeDataProvider, TreeItem, Event, EventEmitter } from 'vscode';
import fundApi from './api';
import FundItem from './TreeItem';
export default class DataProvider implements TreeDataProvider<FundInfo> {
private refreshEvent: EventEmitter<FundInfo | null> = new EventEmitter<FundInfo | null>();
readonly onDidChangeTreeData: Event<FundInfo | null> = this.refreshEvent.event;
private order: number;
constructor() {
this.order = -1;
}
refresh() {
// 更新视图
this.refreshEvent.fire(null);
}
getTreeItem(info: FundInfo): TreeItem {
return new FundItem(info);
}
getChildren(): Promise<FundInfo[]> {
const { order } = this;
// 获取配置的基金代码
const favorites: string[] = workspace
.getConfiguration()
.get('fund.favorites', []);
// 获取基金数据
return fundApi([...favorites]).then((results: FundInfo[]) =>
results.sort((a, b) => (a.changeRate >= b.changeRate ? 1 : -1) * order)
);
}
}
2. TreeItem文件如何写?
import { TreeItem } from 'vscode';
export default class FundItem extends TreeItem {
info: FundInfo;
constructor (info: FundInfo) {
const rate = Number(info.changeRate);
const icon = rate >= 0 ? ' ' : ' ';
super(`${icon}${info.name} ${info.changeRate}%`);
this.info = info;
}
}
3.fundApi很简单,去基金网站上扒获取基金的接口出来用就行了,把参考代码贴出来
import * as https from 'https';
// 发送get请求
const request = async (url: string): Promise<string> => {
return new Promise((resolve, reject) => {
https.get(url, (res) => {
let chunks = '';
if (!res || res.statusCode !== 200) {
reject(new Error('网络请求失败'));
return;
}
// 绑定事件
res.on('data', chunk => chunks += chunk);
res.on('end', () => resolve(chunks));
});
});
};
interface FundInfo {
now: string
name: string
code: string
lastClose: string
changeRate: string
changeAmount: string
}
export default function fundApi(codes: string[]): Promise<FundInfo[]> {
const time = Date.now();
const promises: Promise<string>[] = codes.map(code => {
const url = `https://fundgz.1234567.com.cn/js/${code}.js?rt=${time}`;
return request(url);
});
return Promise.all(promises).then((resArr) => {
let fundInfo: FundInfo[] = [];
resArr.forEach((res: string) => {
const result = res.match(/jsonpgz((.+))/);
if (!result || !result[1]) {
return;
}
const resObj = JSON.parse(result[1]);
const obj: FundInfo= {
// 当前净值
now: resObj.gsz,
// 基金名称
name: resObj.name,
// 基金代码
code: resObj.fundcode,
// 昨天净值
lastClose: resObj.dwjz,
// 涨跌幅
changeRate: resObj.gszzl,
// 涨跌额
changeAmount: (resObj.gsz - resObj.dwjz).toFixed(4)
};
fundInfo.push(obj);
});
return fundInfo;
});
}
五、发布插件