前言
VSCode这款开发工具相信大家是非常熟悉的了,那么VSCode仅仅是一款代码编辑工具吗?非也,在VSCode上有非常多的工(mo)作(yu)的插件,比如看股票呀,玩玩小游戏呀,看看小说呀,听听音乐呀,本文就不在过多说明了,感兴趣的朋友可以去搜一下。
VSCode上有非常多的插件供你选择,那么问题就来了,自己如何开发一个插件呢?来实现自己想要的功能,如果你感兴趣的话,请继续看吧,本文是拿作者自己开发的一个插件做示例,简单讲述一下VSCode插件开发的过程,以及我如何从0到1开发一个插件的心路历程,并非专业的教程,还请酌情观看。
专业的教程请移步https://code.visualstudio.com/api/references/vscode-api
先睹为快
首先先看一下我做好的VSCode插件,在VSCode中搜索movie-news
即可。第一个应该就是了。全名是movie-news-for-vscode
嗯,有点长,还不如直接起个中文名。
直接点击安装即可,这里有两点需要注意下,由于这个插件没有采用第三方的接口,而是采用python爬虫的方式获取的数据,所以除了需要安装Node.js
之外,还需要安装Python3
,以及Python下的beautifulsoup4
和requests
模块,Python安装不做过多介绍了,注意Python和Node.js安装之后需要加入环境变量。
#python下用pip安装模块
pip install beautifulsoup4
pip install requests
安装好之后,就可以去打开插件了,如图。
左边是正在热映和即将上映的电影列表,点击电影名称会打开一个标签页,可以查看海报、导演、时长、类型等信息。功能还是比较简单的。
确定需求
现在知道要开发一个VSCode插件了,那么具体做一个什么样的插件呢?本人呢非常喜欢看电影,于是就想做一个可以查看正在热映和即将上映的电影的信息的插件。页面布局就如上面的图片所示了,需要一个图标去点击,进入到插件中,然后显示正在热映和即将上映的电影的列表,点击列表中的电影名称可以查看影片信息,嗯,暂时就想到这些简单的功能。
有哪些难点
- 去哪里获取正在热映和即将上映的电影的信息?
- JS如何获取python的执行结果?
还有一些问题,比如如何在VSCode侧边栏显示插件图标?如何显示正在热映和即将上映的折叠面板?如何打开一个webview?这些不作为考虑范围,这些东西在官方文档里已经写的很清楚了,不算难点。
找呀找呀找接口
去哪里找电影的相关的免费的接口呢?说实话光这一步就花费了两天的时间,而且结果还是没找到,很气人,既然找不到免费好用的接口,那就只能自己动手了,获取电影信息的话,我首先找的是猫眼电影,但是发现猫眼电影分类很多,确实很专业,但是页面也比较复杂,于是又找到了淘票票,页面如下。
看到淘票票的页面,嘴角微微上扬,果断F12查看下页面元素。
多么直白,多么简单,还不用分页,正在热映和即将上映也都是分类好并且在一个页面中。这对我这个python小菜鸟来说,简直是舒服极了。写代码过程就不说了,直接上源码。
Python淘票票正在热映和即将上映的电影信息。
import io
import sys
from bs4 import BeautifulSoup
import requests
import json
#伪装浏览器请求
headers={
'User-Agent':'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;',
'Referer':'https://www.taopiaopiao.com/showList.htm?spm=a1z21.3046609.header.4.1d69112aGq86y0&n_s=new'
}
#获取网页信息
def getPage(url):
try:
response=requests.get(url)
if response.status_code==200: #http状态码,200表示请求成功
return response.text
else:
return None
except Exception:
return None
#解析html标签内容
def getInfo(html):
soup=BeautifulSoup(html,'html.parser') #创建bs对象 解析器为html.parser
items=soup.select('div .movie-card-wrap') #查询所有的电影卡片里的信息
i=1
result = [] #创建一个空的数组
for item in items:
name=item.find(name='div',class_='movie-card-name').get_text().strip() #这个是找你要内容的标签和它的类
if '\n' in name:
name = name[:name.index('\n')] #若包含评分,则去掉评分,因为有些电影没有评分
obj={}
obj['movie_name'] = name
poster = item.find(name='img').get("src") #获取海报图片地址
obj['poster'] = poster
info=item.find(name='div',class_='movie-card-list').get_text().strip() #这里包含 主演 类型 时长等信息
infoArr = info.split('\n')
for index in range(len(infoArr)):
obj[index] = infoArr[index]
#获取的包括正在热映以及即将上映
soon = item.find(name='a',class_='movie-card-soon')
if(soon==None): #正在热映
obj["bool_showed"] = True
else: #即将上映
obj["bool_showed"] = False
result.append(obj) #向集合中添加元素
i=i+1
return result
sys.stdout = io.TextIOWrapper(sys.stdout.detach(),encoding='utf-8')
url='https://www.taopiaopiao.com/showList.htm?spm=a1z21.3046609.header.4.20c5112aFDxxzq&n_s=new'
html=getPage(url)
data=getInfo(html)
print(json.dumps(data,ensure_ascii=False)) #转成json
接着可以打印下结果
这里是已经转成json格式的数据,OK到目前,问题已经解决了一个,还差一个问题解决了就可以正式开始写VSCode插件了。
Node.js中神奇的child_process
数据我们可以获取到了,但是由于是用python获取的数据,如何在JS中用呢,换句话说就是如何在用JS调用python脚本并执行,然后获取执行结果,首先我们需要知道一点,VSCode插件可以用JS和TS两种方式进行开发,且TS为JS的超集,所以都肯定是支持JS语法的。
那么神奇的child_process就要登场啦,官网在这里http://nodejs.cn/api/child_process.html
在child_process里可以创建一个子进程,在子进程里可以执行一些自己想要执行的命令,然后我们可以这样写。
const { spawn } = require('child_process');
const ls = spawn('python', ["D:\\MyProject\\python-shell\\api.py']);
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
ls.on('close', (code) => {
console.log(`子进程退出,退出码 ${code}`);
});
首先我们需要把Python加入环境变量哈,然后上面就是用python命令来执行python脚本。
OK难点都解决了,接下来可以正式开始我们的VSCode插件开发之旅了。
生成项目
首先需要安装一个代码生成器
npm install -g yo generator-code
安装好之后用yo code
命令来创建一个默认的项目。这里会让选择开发的插件类型,项目名称,开发者等信息。按自己的要求输入就好了。
yo code
# ? What type of extension do you want to create? New Extension (TypeScript)
# ? What's the name of your extension? HelloWorld
### Press <Enter> to choose default for all options below ###
# ? What's the identifier of your extension? helloworld
# ? What's the description of your extension? LEAVE BLANK
# ? Initialize a git repository? Yes
# ? Bundle the source code with webpack? No
# ? Which package manager to use? npm
然后一个项目就创建好了,用VScode打开,还原下npm包,就可以直接F5运行了,
配置项目
接下来需要配置下侧边栏的图标,以及显示正在热映和即将上映的折叠面板。打开项目的下的package.json文件,修改如下。
"contributes": {
"commands": [
{
"command": "limeng.helloWorld",
"title": "Hello World"
}
],
"viewsContainers": {
"activitybar": [
{
"id": "sidebar",
"title": "电影资讯",
"icon": "resources/movie.png"
}
]
},
"views": {
"sidebar": [
{
"id": "sidebar_hot",
"name": "正在热映"
},
{
"id": "sidebar_soon",
"name": "即将上映"
}
]
}
},
其中的activitybar
便是显示在侧边栏的图标,sidebar
是显示在侧边栏右边的可折叠面板。
正在热映和即将上映的区域有了,接下来就需要的把电影列表填充到相应的区域。在src目录下新建一个名为sidebar.ts的文件
//执行py文件,获取正在热映和即将上映电影列表
function getMovieData() {
let json = {};
const { spawnSync } = require('child_process'); //同步
let pyPath = path.join(__dirname, '../api/api.py');
const ls = spawnSync('python', [pyPath]);
json = ls.stdout;
console.log(ls.stderr + ''); //输出错误信息
return json;
}
//正在热映
export class SidebarHot implements vscode.TreeDataProvider<EntryItem>
{
onDidChangeTreeData?: vscode.Event<void | EntryItem | null | undefined> | undefined;
getTreeItem(element: EntryItem): vscode.TreeItem | Thenable<vscode.TreeItem> {
return element;
}
getChildren(element?: EntryItem): vscode.ProviderResult<EntryItem[]> {
if (!element) {
return getMovieList(true);
}
}
}
//返回电影列表
function getMovieList(this: any, flag: boolean) {
let json = getMovieData() + ""; //buffer转字符串
let obj = JSON.parse(json); //解析json
let movies: any[] = [];
for (let item of obj) {
if (item["bool_showed"] === flag) { //正在热映
let movieName = new EntryItem(item["movie_name"]);
movieName.command = {
command: "sidebar_item.openWebview", //命令id
title: "标题",
arguments: [item] //命令接收的参数
};
movies.push(movieName);
}
};
return movies;
}
现在还没完成,刚上面只是把数据绑定到TreeItem
中,就接下来的才是重点。找到src目录下的extension.ts
文件,里面有一个activate
方法,修改如下。
export function activate(context: vscode.ExtensionContext) {
//注册侧边栏面板的实现
const sidebarHot = new sidebar.SidebarHot();
const sidebarSoon = new sidebar.SidebarSoon();
vscode.window.registerTreeDataProvider("sidebar_hot",sidebarHot);
vscode.window.registerTreeDataProvider("sidebar_soon",sidebarSoon);
//注册命令
vscode.commands.registerCommand("sidebar_item.openWebview",args=>{
//vscode.window.showInformationMessage(args);
const panel = vscode.window.createWebviewPanel(
'webview', // viewType
args["movie_name"], // 视图标题,为电影名称
vscode.ViewColumn.One,
{
enableScripts: true, // 启用JS,默认禁用
retainContextWhenHidden: true // webview被隐藏时保持状态,避免被重置
}
);
//这里只能输入html内容
let content = getContentHtml(args);
panel.webview.html = showWebviewContent(args,content);
});
// The command has been defined in the package.json file
// Now provide the implementation of the command with registerCommand
// The commandId parameter must match the command field in package.json
let disposable = vscode.commands.registerCommand('movienews.helloWorld', () => {
// The code you place here will be executed every time your command is executed
// Display a message box to the user
vscode.window.showInformationMessage('Hello World from 电影资讯!');
});
context.subscriptions.push(disposable);
}
这里还注册了一个openWebview
的命令,用于点击电影名称,打开新的标签页。标签页中的内容就是简单的html,方法如下。
function showWebviewContent(args:any,content:string){
let result = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div style="height:500px;width: 500px; margin: 50px auto 0;">
<div><img src="`+args["poster"]+`" style="width: 160px;height: 240px;">
</div>
<div style="position: relative;top: -265px;left: 180px;">
<p>
<h2>`+args["movie_name"]+`</h2>
</p>
`+content+`
</div>
</div>
</body>
</html>`;
return result;
}
function getContentHtml(args:any){
let content = '';
for(var i in args) {
if(!isNaN(Number(i))){
content+="<p>"+args[i]+"</p>";
}
}
return content;
}
项目地址我会放到最后,感兴趣的可以clone到本地运行查看,注意还是需要先配置环境哦。
发布项目
在本地运行没问题的话,接下来就是把我们的项目发布到应用商店了。地址参考:https://code.visualstudio.com/api/working-with-extensions/publishing-extension
- 首先需要注册Microsoft账号,
- 然后登录dev.azure,创建组织和项目。
- 创建Personal Access Tokens。
- 登录https://marketplace.visualstudio.com/VSCode创建发布者。
然后就可以发布你的项目了。发布的方式有两种,一种是用命令直接发布,还有一种可以打包成vsix,手动上传到应用商店。
打包需要安装vsce工具,常用命令如下。
//安装工具
npm install -g vsce
//打包成vsix安装包
vsce package
//登录
vsce login <publisher name>
//发布
vsce publish
登录的时候需要Personal Access Token,这个需要提前创建好并复制下来。
注意一点,在创建Publisher的时候,需要在网页创建,传统的命令创建已经不行了。去下面提示的网址进行创建就好了。
写在最后
这款插件是兴趣使然,并没有花费很多精力在上面,功能也比较简单,以后有想法了在完善吧,就这样。
项目地址:https://gitee.com/limeng66/movie-news-for-vscode
转载请保留出处。