本文将通过一个极其简单甚至简陋的样例,来展示谷歌浏览器插件(Chrome Extension)的基本实现方法。内容包括了popup、background、content_scripts等之间的通信以及发送http请求等。
一、需求
实现一个浏览器插件,支持用户通过鼠标选取网页中的文字内容,通过http调用接口,生成摘要并展示。
二、项目结构
css文件夹存放了2个css文件,common.css用于注入到网页中,popup.css用于插件弹出页样式。
js文件夹存放了4个js文件,background.js用于后台服务,content-script.js是注入到网页中执行的,jquery.js不说了,popup.js用于插件的弹出页。
icon.png是插件的图标。
manifest.json是配置文件。
popup.html是插件弹出页。
三、配置文件
配置文件是使得整个项目能被识别为浏览器插件的关键,内部内容如下:
{
"name": "chrome_demo",
"version": "1.0.0",
"manifest_version": 2,
"description": "阿蓝的插件",
"browser_action": {
"default_icon": "icon.png",
"default_title": "阿蓝的插件",
"default_popup": "popup.html"
},
"background" : {
"scripts": ["js/jquery.js", "js/background.js"]
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["js/jquery.js", "js/content-script.js"],
"css": ["css/common.css"],
"run_at": "document_start"
}]
}
里面定义了插件的名称、描述、版本、图标等基本信息,以及各个场景所要引用的js、css文件等配置。
四、功能实现
1、弹出页(popup)
我在popup.html里放了一个按钮和一段文字:
<!DOCTYPE html>
<html>
<head>
<title>Alan's demo</title>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="css/popup.css">
<script src="js/jquery.js"></script>
<script src="js/popup.js"></script>
</head>
<body>
<div class="container">
<p class="desc">请选中内容后点击“生成摘要”按钮。</p>
<button class="btn" id="generate_summary">生成摘要</button>
</div>
</body>
</html>
加载到浏览器,点击可以看到如下效果:
稍微在popup.css里增加了一些样式,但还是很丑,这不重要,略过。
重点在于popup.js这个文件:
function sendMessageToContentScript(message, callback){
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, message, function(response) {
if(callback) callback(response);
});
});
}
$(document).ready(function(){
$('#generate_summary').click(function() {
sendMessageToContentScript({cmd: 'GET_TEXT', value: null}, function(response) {
if (response != null) {
var bg = chrome.extension.getBackgroundPage();
bg.generateSummary(response);
}
});
})
});
这里实现了一个叫sendMessageToContentScript的方法,是用于通信的,会在各种场景都使用到。下面的方法用于当用户点击“生成摘要”按钮时,发送消息到网页(content-script.js)获取用户选取的文字内容并通过response返回,再调用background.js中的generateSummary(生成摘要)方法。
2、网页注入
这部分代码是注入到实际的网页中运行的,这里包括content-script.js和common.css两个文件。其中content-script.js内容如下:
function showDialog(text) {
$('.dialog-bg').remove();
$('body').append('<div class="dialog-bg"><div class="dialog"><p>' + text + '</p><button class="dialog-close">关闭</button></div></div>');
$('.dialog-close').click(function() {
$('.dialog-bg').remove();
});
}
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
let res = null;
if (request.cmd == 'GET_TEXT') {
res = window.getSelection().toString();
showDialog('请稍后……');
} else if (request.cmd == 'SHOW_SUMMARY') {
let summary = request.value;
showDialog(summary)
}
sendResponse(res);
return true;
});
上面showDialog方法用于最后在网页内展示结果,弹出框的样式在common.css文件里实现,此处略过。
下面的方法是添加一个监听,也就是用来接收其他页面sendMessageToContentScript方法发来的内容并返回的。这里实现了两个监听,GET_TEXT用于接收处理popup发来的获取用户选取内容的请求,SHOW_SUMMARY用于接收background发来的摘要并展示。
3、背景页(background.js)
因为要通过http调用接口,这里放在background.js里实现,在这里可以回避跨域问题。
function sendMessageToContentScript(message, callback){
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, message, function(response) {
if(callback) callback(response);
});
});
}
function generateSummary(content) {
$.post('http://接口地址/……', // 这里我是用了某度的接口并做了一些封装,不做展示
{
content: content
},
function(res) {
// 一些处理逻辑,判断请求结果、判空等等……,按个人实际情况,略过
let result = res.summary;
sendMessageToContentScript({cmd: 'SHOW_SUMMARY', value: result}, null);
}
)
}
这里就是一个朴素的ajax请求的写法,因为用了jquery,写起来省力一点。通过请求接口,把文字内容上传并获得摘要,通过调用sendMessageToContentScript把摘要发送到content-script.js进行展示。
4、逻辑串连
首先,用户在网页中选中一段文字,点击插件图标呼出popup,点击“生成摘要”按钮,popup.js通过sendMessageToContentScript方法,发送消息到content-script.js的GET_TEXT监听中获取用户选中的文字。
然后,popup.js调用了background.js中的generateSummary方法,该方法会通过http请求把文字发送到接口,从而生成摘要。摘要到手后,background.js再次通过sendMessageToContentScript方法把摘要内容发送到content-script.js的SHOW_SUMMARY监听中。
最后,content-script.js取得摘要内容,并调用showDialog方法展示。
五、效果演示
六、关于调试
可以在浏览器的扩展程序页(chrome://extensions/),打开“开发者模式”,然后使用“加载已解压的扩展程序”来引入项目,这样可以方便边改边调。有些js改了不生效,可能要点一下插件的刷新按钮。