chrome/browser

这两个是浏览器为插件开发提供的API,Chrome浏览器的变量名叫chrome,火狐浏览器的变量名叫browser

代码提示

我用的编辑器是vscode,之前一直不明白怎么给这两个变量添加代码提示

最早尝试

最开始我想的是加一个全局变量,搜到可以在.eslintrc配置中添加一个globals,把变量名加进去,但后来发现这个东西跟代码提示没半毛钱关系。这是ESLint的配置文件,它的功能只是代码检查。

问过插件开发的大佬,大佬只说导入Library啥的,当时的我亿脸懵逼。

typings

看了github上的各种插件,发现有一个@types/chrometypings是TypeScript的定义管理器,描述命名空间、接口、变量等各种东西,@types/chrome呢也就是别人写好的一个描述文件,去告诉编辑器我这里有个chrome变量,它下面有哪些方法之类的。

使用npm安装

1
npm install --save-dev @types/chrome

安装好后发现chrome的代码提示有了,但只有chrome,火狐浏览器的browser依然没有。

自定义typings

前几天突发奇想,因为vue是可以自定义全局和实例变量的代码提示的,那么browser也许能自定义,于是照着这个思路,搜了一下怎么新建一个描述,去“继承”chrome

其实非常简单,只需要创建个文件,比如我在src/typings/下创建了一个browser.d.ts。这里具体在哪个文件夹下无所谓,读取这个文件是在tsconfig.json中配置的

1
2
3
4
5
6
/* 前略 */
"include": [
"src/**/*.ts",
"src/**/*.d.ts",
/* 略 */
],

意思就是,加载src目录下的包括所有文件夹中的.ts.d.ts文件,所以只是创建在src目录下就行

然后在这个文件里添加

1
declare const browser : typeof chrome;

这样就有browser变量了

添加vue变量

再新建一个vue.d.ts,在里面添加

1
2
3
4
5
6
7
8
9
import Vue from 'vue'
declare module 'vue/types/vue' {
interface Vue {
$chrome: typeof chrome
}
interface VueConstructor {
chrome: typeof chrome
}
}

更多详情可参考vue官网的说明:《TypeScript 支持》

以上,代码提示添加完成

使用示例

然后你就可以给Vue的chrome赋值,以background.ts为例,里面封装了一个网络请求

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
import axios from 'axios';
import Vue from 'vue';

Vue.chrome = Vue.prototype.$chrome = chrome || browser;

Vue.chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
const headers = typeof request.headers !== 'undefined' ? request.headers : {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36'
};

switch (request.type) {
case 'get':
axios.get(request.url, headers)
.then(response => {
sendResponse(response.data);
});
break;
case 'post':
axios.post(request.url, request.data, headers)
.then(response => {
sendResponse(response.data);
});
break;
}

return true;
});

然后popup.ts中,也需要加入

1
2
3
4
5
6
7
8
9
10
11
12
import Vue from 'vue';
import Popup from '@components/popup';
import '@styles/popup';

Vue.chrome = Vue.prototype.$chrome = chrome || browser;

export default new Vue({
components: {
Popup
},
render: h => h(Popup)
}).$mount('#app');

popup.vue中使用

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
<template>
<div>
<h1>{{ title }}</h1>
<span>{{ message }}</span>
<input type="text" v-model="uid" value="" placeholder="输入UID">
<button @click="btn">请求数据测试</button>
</div>
</template>

<script lang="ts">

import { Vue, Component } from 'vue-property-decorator';

@Component
export default class Popup extends Vue {

title = 'Popup';
message = '';
uid = '';

public btn() {
if (this.uid === '') {
this.message = '未输入UID';
return;
}

this.$chrome.runtime.sendMessage({
type: 'get',
url: `https://api.bilibili.com/x/web-interface/card?mid=${this.uid}&photo=1&jsonp=jsonp`
}, (json) => {
console.log(json);
if (typeof json.data !== 'undefined') { this.message = `获取成功!昵称:${json.data.card.name},当前粉丝数:${json.data.card.fans}`; }
});
}
}
</script>

其他细节可查看Github项目:Btools-vue

总结

  1. 如果typescript项目用到的某变量没有代码提示可在npm搜索@types/xxx查找

  2. typings完全可以手写,只是比较麻烦

  3. 为一个变量声明类型可以用typeof xxx

    之前想到了在typings文件中声明,但不知道得用typeof,一直报错:namespace不能作为类型使用

更新

2021-07-06 更新,发现有一个插件API的包webextension-polyfill-ts,直接引入就可以用