谷歌浏览器开发
一、创建myPlugin
文件夹以及manifest.json
文件
1、在manifest.json
文件写入这段代码
如果你对
manifest.json
里面的字段描述不清楚,建议先看完此文章,先照猫画虎,在阅读manifest.json
字段解析文章 网上最全谷歌浏览器插件manifest.json文件字段解析
{
"name": "my Plugin",
"description": "this is my plugin",
"version": "0.0.1",
"manifest_version": 2
}
2、在谷歌浏览器中打开管理扩展程序
1. 如图打开
2. 或者在浏览器中输入chrome://extensions
打开拓展程序
3、加载已解压的拓展程序
然后选择到你的 myPlugin
文件夹确定即可
就会在扩展程序中看到你的插件了
在这边的插件信息中可以看到在你的 manifest.json
中的name
、description
和version
此时点击右上角插件icon
如下展示
如果你的插件icon
没有展示出来,可以进行如下操作,把它固定在右上角
4、到此一个简单的插件完成了,剩下的就是往里面添加东西了
二、添加点击插件的弹出页面
例如谷歌翻译插件点击之后会有一个弹出页面
1、添加东西之前首先把自己插件的icon
加一下
- 创建一个
icons
文件夹 - 找三张图片尺寸 16 * 16、48 * 48、128 * 128
- 添加到
manifest.json
文件中
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
在扩展程序中刷新下我们的插件(我这边选的图片是网上找的chrome
图标)
此时浏览器右上角icon
也换成了我们的图片,只是此时是灰色的
2、添加 browser_action
- 在
myPlugin
文件夹中创建index.html
文件,内容如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>my plugin</title>
</head>
<body>
this is my plugin
browser_action html
</body>
</html>
- 在
manifest.json
中添加browser_action
字段
"browser_action": {
"default_title": "plugin title",
"default_icon": "icons/icon128.png",
"default_popup": "index.html"
}
- 拓展程序中刷新插件
- 点击右上角插件
icon
3、此时一个插件弹出页面就出来了
三、仿着谷歌翻译插件的弹出页面修改
此时就相当于web
页面开发,需要引入css
、js
myPlugin
文件夹下创建css
文件夹和js
wen jian j文件夹css
中创建index.css
,并在index.html
中引入js
中创建index.js
,并在index.html
中引入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>my plugin</title>
<link rel="stylesheet" href="css/index.css">
</head>
<body>
<div class="plugin_search">
<div class="plugin_search_bar">
<input id="plugin_search_inp" />
<input id="plugin_search_but" type="button" value="翻译" />
</div>
<div class="plugin_span">
<span>翻译此页面</span>
</div>
</div>
<div class="plugin_footer">
<span>© 2015 Google -</span>
<a target="_blank" href="https://google.com/">扩展程序选项</a>
<a target="_blank" href="https://translate.google.com/?source=gtx">Google 翻译</a>
</div>
</body>
<script src="js/index.js"></script>
</html>
*{
padding: 0;
margin: 0;
list-style: none;
text-decoration: none;
}
.plugin_search{
margin: 15px 30px 15px 30px;
}
.plugin_search_bar{
margin: 8px 0 16px 0;
}
#plugin_search_inp{
font-size: 14px;
margin: 2px;
height: 23px;
width: 70%;
}
#plugin_search_but{
box-shadow: none;
background-color: #4d90fe;
background-image: -webkit-linear-gradient(top,#4d90fe,#4787ed);
border: 1px solid #3079ed;
color: #fff;
border-radius: 2px;
cursor: default;
font-size: 11px;
font-weight: bold;
text-align: center;
white-space: nowrap;
margin-right: 16px;
height: 27px;
line-height: 27px;
width: 54px;
outline: 0px;
padding: 0 8px;
box-sizing: content-box;
}
.plugin_span{
color: #4285f4;
}
.plugin_footer{
background-color: #f0f0f0;
color: #636363;
font-family: 'Roboto',sans-serif;
font-size: 11px;
margin-top: 9px;
padding: 10px;
text-align: center;
width: 400px;
}
.plugin_footer a{
color: #4285f4;
}
const plugin_search_but = document.getElementById('plugin_search_but')
const plugin_search_inp = document.getElementById('plugin_search_inp')
plugin_search_but.onclick = function () {
alert('plugin_search_inp的值为:' + plugin_search_inp.value.trim())
}
- 扩展程序中刷新
- 点击右上角插件
icon
- 在输入框中输入文案,并点击按钮
- 如果想有其他操作和样式,直接在
js
和css
文件中写入即可
四、background
如果我在 index.js
中添加如下一段js
setInterval(() => {
alert('alert')
}, 5000);
每隔五秒 alert
一下
当我刷新插件后,点击icon
,每隔五秒就会 弹出一次,但是当我把 弹出框 取消掉之后,发现就不会在弹了,只有再次打开才会每隔五秒执行一次。
这个可以满足一些插件需求,只要当我点击插件的时候,才会执行插件的某些操作,不点击的话不会执行,但是某些需求是,不点击的时候也要执行我插件的某些操作
这个时候就需要 background
来实现了
- 在
myPlugin
中 建一个background.js
的文件 - 在
background.js
的文件添加如下代码
setInterval(() => {
alert('background')
}, 5000);
- 然后在
manifest.json
中把background.js
加入进来
"background": {
"scripts": ["background.js"]
}
如果你需要在background
中添加多个js
,只需要在scripts
数组中按照顺序添加,先后顺序影响着加载顺序
此时会发现,不需要点击icon
就会每隔五秒弹出一个弹框
此时你的插件就可以在 点击 插件icon
进行你插件的需求,和不点击运行你的插件需求(后台运行你的插件需求)
五、content_scripts 能够操作当前页面(dom
、document
、window
、location
…)
不知道你有没有发现,如果你在index.js
/background.js
中 console.log(document)/window
都和你当前打开的网页无关…一个是你的插件页面,一个是你的背景页面
而此时,产品站在你旁边,碎碎念,我想通过插件操作当前页面dom
的需求,那这个时候index.js
和background.js
就不行了。
此时就需要 content_scripts
先把 background.js
的alert
注释掉,在刷新下插件(一直弹,挺烦)
- 在
myPlugin
文件夹中新建一个contentJs
文件夹 - 在
contentJs
中新建一个index.js
文件,在从网上找一个jquery.js
文件,需要用到(Jquery) - 在
manifest.json
文件中把content_scripts
引入进来
"content_scripts": [
{
"matches": ["https://*.taobao.com/*"],
"js": ["contentJs/jquery.js", "contentJs/index.js"],
"run_at": "document_idle"
}
]
- matches:意思是要在哪些页面引入这些
js
- js:要引入的
js
,按照数组顺序加载 - run_at:
js
引入的运行时间
在上面的代码中,我想注入的是 https://*.taobao.com/*
这个淘宝域名下的页面
- 在
index.js
里面输入下面一段代码
console.log("this is index.js")
console.log(document)
console.log(location)
- 刷新插件,打开
https://www.taobao.com/
,打开控制台
此时你代码里面的 console.log
的内容就出现在控制台中,就可以操作当前页面了
六、在当前页面中加入我的 html
代码
此时产品看到你可以操作当前页面了,又来需求了。
在当前页面加入一个dialog
框,可以操作XXXXXXX,我还想在当前页面表格的每一行里面加一个按钮XXXX…等
通过 content_scripts
我们可以正常操作页面,那加一个弹框,那就是html
和css
了
- 在
myPlugin
中创建contentCss
文件夹,里面创建index.css
文件 - 在
manifest.json
中引入
"content_scripts": [
{
"matches": ["https://*.taobao.com/*"],
"css": ["contentCss/index.css"],
"js": ["contentJs/jquery.js", "contentJs/index.js"],
"run_at": "document_idle"
}
]
把 css
引入
index.css
内容
#cj_move_page{
width: 400px;
user-select: none;
background: white;
border: 1px solid;
height: 400px;
position: fixed;
right: 0;
bottom: 0;
z-index: 1000001;
}
#cj_move_h3{
text-align: center;
line-height: 40px;
cursor: move;
}
contentJs/index.js
文件内容
console.log("this is index.js")
console.log(document)
console.log(location)
//创建页面函数
function createPage () {
const page = $('<div id="cj_move_page"></div>')
const h3 = $('<h3 id="cj_move_h3">my Plugin</h3>')
page.append(h3)
$('body').append(page)
//拖拽
drag(cj_move_h3)
}
createPage()
//拖拽
function drag(ele) {
let oldX, oldY, newX, newY
ele.onmousedown = function (e) {
if (!cj_move_page.style.right && !cj_move_page.style.bottom) {
cj_move_page.style.right = 0
cj_move_page.style.bottom = 0
}
oldX = e.clientX
oldY = e.clientY
document.onmousemove = function (e) {
newX = e.clientX
newY = e.clientY
cj_move_page.style.right = parseInt(cj_move_page.style.right) - newX + oldX + 'px'
cj_move_page.style.bottom = parseInt(cj_move_page.style.bottom) - newY + oldY + 'px'
oldX = newX
oldY = newY
}
document.onmouseup = function () {
document.onmousemove = null
document.onmouseup = null
}
}
}
在js
中创建页面,并加载到页面的body
中
- 刷新插件
- 刷新淘宝页面
此时就可以在content_scripts
中matches
所匹配的页面里面插入你所写的dom
元素了
七、ajax请求
页面当然离不开 ajax
请求了
1、content_scripts
中ajax
请求
由于我们之前在content_scripts
中引入了jquery
,那我们就可以直接用$.ajax
- 首先我们先在
manifest.json
中在添加一个域名:豆瓣(www.douban.com)
"content_scripts": [
{
"matches": ["https://*.taobao.com/*", "https://*.douban.com/*"],
"css": ["contentCss/index.css"],
"js": ["contentJs/jquery.js", "contentJs/index.js"],
"run_at": "document_idle"
}
]
- 在我们的
contentJs/index.js
中加入一个button
function createPage() {
const page = $('<div id="cj_move_page"></div>')
const h3 = $('<h3 id="cj_move_h3">my Plugin</h3>')
const but1 = $('<button id="cj_but1">加载更多</button>')
page.append(h3)
page.append(but1)
$('body').append(page)
$('#cj_but1').click(function (e) {
$.ajax({
url: "https://www.douban.com/j/search",
type: "GET",
data: {
q: '电影',
start: 10,
cat: 1002,
},
success: function (res) {
console.log(res)
},
error: function (e) {
console.log(e.responseText)
}
})
})
//拖拽
drag(cj_move_h3)
}
- 刷新插件、刷新豆瓣页面
- 点击加载更多
2、background
调用ajax
- 首先先把
jquery.js
引入
"background": {
"scripts": ["contentJs/jquery.js", "background.js"]
},
注意顺序
background.js
页面
$.ajax({
url: "https://www.douban.com/j/search",
type: "GET",
data: {
q: '电影',
start: 10,
cat: 1002,
},
success: function (res) {
console.log(res)
},
error: function (e) {
console.log(e.responseText)
}
})
- 刷新插件
- 点击插件背景页按钮
- 点击
console
,ajax
请求内容如下
3、插件弹出页面调用ajax
插件弹出页面调用ajax
,这个就不用再说了,就和普通页面一样,引入jquery
,然后在js
页面直接调用即可
八、js之间的消息通讯
现在有我们有content_scripts
和background scripts
和弹出框页面的scripts
可能需要js之间的消息通信
1、content_scripts
和background
的通信
- 接收消息:
chrome.runtime.onMessage.addListener
- 发送消息:
chrome.runtime.sendMessage
- 我们先在
content_scripts
里面加一个按钮,用来触发事件
contentJs/index.js
//contentJs/index.js
const but2 = $('<button id="cj_but2">向background发送消息</button>')
// 添加一个 button 按钮
page.append(but2)
$('body').append(page)
// 点击事件
$('#cj_but2').click(function (e) {
// 点击按钮发送消息
chrome.runtime.sendMessage({
info: "我是 content.js, 我在发送消息"
}, res => {
console.log('我是 content.js ,我收到消息:', res)
})
})
// 接收消息
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
console.log(request, sender, sendResponse)
sendResponse('我收到了你的消息!');
});
- 在
background.js
页面接收和发送消息
background.js
//background.js
//接收消息
chrome.runtime.onMessage.addListener(async (req, sender, sendResponse) => {
console.log('我是background,我接收了来自 content.js的消息:', req.info)
sendResponse('哈哈哈')
const tabId = await getCurrentTabId()
// 在背景页面发送消息,需要当前 tabID
chrome.tabs.sendMessage(tabId, '我是background,我在发送消息', function (res) {
console.log('background:', res)
});
})
/**
* 获取当前 tab ID
*/
function getCurrentTabId() {
return new Promise((resolve, reject) => {
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
resolve(tabs.length ? tabs[0].id : null)
});
})
}
- 刷新插件、刷新页面
此时是有一个 button
按钮
-
点击按钮,触发事件
-
在 页面的控制台中输出的信息
- 在背景页的控制台中输出的信息
2、background.js
和右上角弹出框的
通信
- 在background中:
chrome.extension.getViews()
获取当前插件内每个运行页面的窗口数组([window, window]) - 在右上角弹出框中:
chrome.extension.getBackgroundPage()
获取背景页面的窗口对象(window)
background.js
中加入下面一段代码
//background.js
/**
* 通信函数
*/
function backFun () {
console.log('arguments:', arguments)
const allViews = chrome.extension.getViews()
console.log('chrome.extension.getViews():', allViews)
}
index.js
中把我们之前的定时器注释掉,alert影响流程,然后把按钮点击事件改一下,获取background页面的window对象,并调用
// index.js
const background = chrome.extension.getBackgroundPage();
console.log(background)
plugin_search_but.onclick = function () {
// alert('plugin_search_inp的值为:' + plugin_search_inp.value.trim())
background.backFun('这个是参数1', '这个是参数2')
}
- 刷新插件
- 点击右上角
icon
- 右键查看元素,打开弹出页面的控制台**和背景页面的控制台不是一个**
- 点击按钮
在插件控制台显示如下
在背景页面的控制台显示
显示一个函数调用 console
值 和一个 window
对象数组
3、右上角弹出框
和content_scripts
之间的通信
- 右上角弹出框:
chrome.tabs.connect
,链接content_scripts
的脚本通信 - content_scripts:
chrome.runtime.onConnect
- 先在
content_scripts
添加chrome.runtime.onConnect
用了监听链接:
contentJs/index.js
// `contentJs/index.js`
chrome.runtime.onConnect.addListener((res) => {
console.log('contentjs中的 chrome.runtime.onConnect:',res)
if (res.name === 'myConnect') {
res.onMessage.addListener(mess => {
console.log('contentjs中的 res.onMessage.addListener:', mess)
res.postMessage('哈哈哈,我是contentjs')
})
}
})
- 再在
右上角弹出框index.js
中建立链接:
index.js
把我们的按钮事件改掉,改成我们的消息触发事件
// index.js
plugin_search_but.onclick = function () {
// alert('plugin_search_inp的值为:' + plugin_search_inp.value.trim())
// background.backFun('这个是参数1', '这个是参数2')
mess()
}
async function mess () {
const tabId = await getCurrentTabId()
const connect = chrome.tabs.connect(tabId, {name: 'myConnect'});
console.log(connect)
connect.postMessage('这里是弹出框页面,你是谁?')
connect.onMessage.addListener((mess) => {
console.log(mess)
})
}
/**
* 获取当前 tab ID
*/
function getCurrentTabId() {
return new Promise((resolve, reject) => {
chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
resolve(tabs.length ? tabs[0].id : null)
});
})
}
- 刷新插件
- 点击插件右上角
icon
- 在插件弹出框中右键打开控制台
- 点击按钮执行操作
插件弹出框控制台显示:
页面中的控制台显示:
此时有人想问了,这个是右上角弹出框向content_scripts
通信,那content_scripts
向右上角弹出框通信呢?
弹出框只要点击插件才能弹出,而当你操作页面的时候,插件弹框又会消失…消失之后,弹框的.js等都会销毁…所以,可以向background
通信,然后点击弹出之后,弹出框和background
通信,或者弹出之后直接向content_scripts
通信
九、打包插件
到这一步了,我们所以的插件需求基本完成了,各种通信也都实现了,各种需求也差不多了,该打包了
- 打开你的扩展程序
- 点击打包扩展程序按钮
- 选择你的文件夹
- 点击打包就行
打包之后会提示生成的文件
- 点击确定即可
十、总结
到此,你从0到1完成了一个谷歌浏览器插件的开发与打包,你已经完美了。
但是谷歌插件里面的东西还很多,这个只是浅显的开发一个插件,涉及到的API
等在后面的文章在一步步的完善,不积硅步,无以至千里。