Chrome扩展与应用(一)
一、创建并加载一个应用
1.创建一个文本文件,命名为manifest.json
{
"name": "我的第一个扩展",
"version": "1.0",
"description": "这是一个小的示例.",
"browser_action": {
"default_icon": "img/icon.png",
"default_popup": "popup.html"
},
"manifest_version": 2
}
2.图标放到img目录中
3.编写html
<!doctype html>
<html>
<head>
<title>弹出扩展</title>
</head>
<body>
<img src="img/snow.png"/>
</body>
</html>
4.加载应用(扩展)
二、manifest.json属性
1、browser_action
2、page_action
3、background
4、content_scripts
Manifest的content_scripts属性值为数组类型,数组的每个元素可以包含matches、exclude_matches、css、js、run_at、all_frames、include_globs和exclude_globs等属性。其中matches属性定义了哪些页面会被注入脚本,exclude_matches则定义了哪些页面不会被注入脚本,css和js对应要注入的样式表和JavaScript,run_at定义了何时进行注入,all_frames定义脚本是否会注入到嵌入式框架中,include_globs和exclude_globs则是全局URL匹配,最终脚本是否会被注入由matches、exclude_matches、include_globs和exclude_globs的值共同决定。简单的说,如果URL匹配mathces值的同时也匹配include_globs的值,会被注入;如果URL匹配exclude_matches的值或者匹配exclude_globs的值,则不会被注入。
content_scripts中的脚本只是共享页面的DOM1,而并不共享页面内嵌JavaScript的命名空间。也就是说,如果当前页面中的JavaScript有一个全局变量a,content_scripts中注入的脚本也可以有一个全局变量a,两者不会相互干扰。当然你也无法通过content_scripts访问到页面本身内嵌JavaScript的变量和函数。
5、permissions
6、web_accessible_resources
7、options_page
三、跨域请求
跨域指的是JavaScript通过XMLHttpRequest请求数据时,调用JavaScript的页面所在的域和被请求页面的域不一致。对于网站来说,浏览器出于安全考虑是不允许跨域。另外,对于域相同,但端口或协议不同时,浏览器也是禁止的。
{
…
“permissions”: [
“://.xtwy.com/*”
]
}
示例:
manifest.json
{
"name": "我的第一个扩展",
"version": "1.0",
"description": "这是一个小的示例.",
"browser_action": {
"default_icon": "img/icon.png",
"default_popup": "popup.html"
},"permissions": [
"http://127.0.0.1:8020/*"
],
"manifest_version": 2
}
popup.html
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>数据交互</title>
</head>
<body>
<img src="img/snow.png" />
<p id="txt"></p>
<input type="button" id="btn" value="测试" />
<script src="js/GetContext.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>
GetContext.js
function httpRequest(url, callback) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
callback(xhr.responseText);
}
}
xhr.send();
}
document.querySelector("#btn").onclick = function() {
console.log("调用前");
httpRequest('http://127.0.0.1:8020/page/a.txt', function(txt) {
alert(txt+"test");
document.getElementById('txt').innerText = txt;
});
console.log("调用后");
};
四、常驻后台
有时我们希望扩展不仅在用户主动发起时(如开启特定页面或点击扩展图标等)才运行,而是希望扩展自动运行并常驻后台来实现一些特定的功能,比如实时提示未读邮件数量、后台播放音乐等等。
Chrome允许扩展应用在后台常驻一个页面以实现这样的功能。在一些典型的扩展中,UI页面,如popup页面或者options页面,在需要更新一些状态时,会向后台页面请求数据,而当后台页面检测到状态发生改变时,也会通知UI界面刷新。
在Manifest中指定background域可以使扩展常驻后台。background可以包含三种属性,分别是scripts、page和persistent。如果指定了scripts属性,则Chrome会在扩展启动时自动创建一个包含所有指定脚本的页面;如果指定了page属性,则Chrome会将指定的HTML文件作为后台页面运行。通常我们只需要使用scripts属性即可,除非在后台页面中需要构建特殊的HTML——但一般情况下后台页面的HTML我们是看不到的。persistent属性定义了常驻后台的方式——当其值为true时,表示扩展将一直在后台运行,无论其是否正在工作;当其值为false时,表示扩展在后台按需运行,这就是Chrome后来提出的Event Page。Event Page可以有效减小扩展对内存的消耗,如非必要,请将persistent设置为false。persistent的默认值为true。
五、带选项页面的扩展
指定options_page属性后,扩展图标上的右键菜单会包含“选项”链接。
通过声明unlimitedStorage权限,Chrome扩展和应用可以突破这一限制。
有很多网站提供天气预报的API,比如OpenWeatherMap的API。
1.扩展代码:
manifest.json
{
"manifest_version": 2,
"name": "天气预报",
"version": "1.0",
"description": "查看未来两周的天气情况",
"icons": {
"16": "img/icon16.png",
"48": "img/icon48.png",
"128": "img/icon128.png"
},
"browser_action": {
"default_icon": {
"19": "img/icon19.png",
"38": "img/icon38.png"
},
"default_title": "天气预报",
"default_popup": "popup.html"
},
"options_page": "options.html",
"permissions": [
"http://api.openweathermap.org/data/2.5/forecast?q=*"
]
}
weather.js
/**
* ajax请求
* @param {Object} url
* @param {Object} callback
*/
function httpRequest(url, callback){
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
callback(xhr.responseText);
}
}
xhr.send();
}
/**
* 显示天气
* @param {Object} result
*/
function showWeather(result){
result = JSON.parse(result);
var list = result.list;
var table = '<table><tr><th>日期</th><th>天气</th><th>最低温度</th><th>最高温度</th></tr>';
for(var i in list){
var d = new Date(list[i].dt*1000);
table += '<tr>';
table += '<td>'+d.getFullYear()+'-'+(d.getMonth()+1)+'-'+d.getDate()+'</td>';
table += '<td>'+list[i].weather[0].description+'</td>';
table += '<td>'+Math.round(list[i].temp.min-273.15)+' °C</td>';
table += '<td>'+Math.round(list[i].temp.max-273.15)+' °C</td>';
table += '</tr>';
}
table += '</table>';
document.getElementById('weather').innerHTML = table;
}
/**
* 读取本地存储
*/
var city = localStorage.city;
city = city?city:'beijing';
var url = 'http://api.openweathermap.org/data/2.5/forecast/daily?q='+city+',china&lang=zh_cn';
//ajax请求调用
httpRequest(url, showWeather);
popup.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
* {
margin: 0;
padding: 0;
}
body {
width: 520px;
height: 270px;
}
table {
font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
font-size: 12px;
width: 480px;
text-align: left;
border-collapse: collapse;
border: 1px solid #69c;
margin: 20px;
cursor: default;
}
table th {
font-weight: normal;
font-size: 14px;
color: #039;
border-bottom: 1px dashed #69c;
padding: 12px 17px;
white-space: nowrap;
}
table td {
color: #669;
padding: 7px 17px;
white-space: nowrap;
}
table tbody tr:hover td {
color: #339;
background: #d0dafd;
}
</style>
</head>
<body>
<div id="weather">载入中……</div>
<script src="js/weather.js"></script>
</body>
</html>
2.网页代码
options.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>设定城市</title>
</head>
<body>
<input type="text" id="city" />
<input type="button" id="save" value="保存" />
<script src="js/options.js"></script>
</body>
</html>
options.js
//存储本地数据
var city = localStorage.city;
city = city?city:'beijing';
document.getElementById('city').value = city;
document.getElementById('save').onclick = function(){
localStorage.city = document.getElementById('city').value;
alert('保存成功。');
}
六、window.postMessage实现跨域通信
以下必须在web服务器中设置:
X-Frame-Options是什么?
X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN
X-Frame-Options: ALLOW-FROM http://xtwy.com/
第一个例子告诉浏览器不要(DENY)把这个网页放在iFrame内,通常的目的就是要帮助用户对抗点击劫持。
第二个例子告诉浏览器只有当架设iFrame的网站与发出X-Frame-Options的网站相同,才能显示发出X-Frame-Options网页的内容。
第三个例子告诉浏览器这个网页只能放在http://xtwy.com//网页架设的iFrame内。
1.发送消息的”postMessage”方法
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<title>数据发送端</title>
<!--实现跨域通信-->
<iframe id="proxy" src="http://127.0.0.1:8020/postMessage/index.html" style="display: none"></iframe>
<script type="text/javascript">
var iframe = document.getElementById('proxy');
var win = iframe.contentWindow;
//周期性的发送消息
setInterval(function(){
var message = '现在的时间是: ' + (new Date().getTime());
console.log('发送消息: ' + message);
win.postMessage(message,'http://127.0.0.1:8020/');
},6000);
//监听消息反馈
window.addEventListener('message',function(event) {
if(event.origin !== 'http://127.0.0.1:8020') return;
console.log('接受响应: ',event.data);
},false);
</script>
</body>
</html>
向外界窗口发送消息:
otherWindow.postMessage(message, targetOrigin);
otherWindow: 指目标窗口,也就是给哪个window发消息,是 window.frames 属性的成员或者由 window.open 方法创建的窗口
参数说明:
message: 是要发送的消息,类型为 String、Object (IE8、9 不支持)
targetOrigin: 是限定消息接收范围,不限制请使用 ‘*’
2.接受信息的”message”事件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>数据接收端</title>
</head>
<body>
数据接收端。
<script>
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event) {
//data.msg 将是从另一个域发送来的
if(event.origin !== "http://localhost:63342")
return;
//输出内容
console.log('接受消息:' + event.data,event);
//回发
event.source.postMessage('消息返回!',event.origin);
}
</script>
</body>
</html>
结果: