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>
結果: