使用時機
當你需要更動當前頁面的 DOM 時,就須以內文執行緒來達成。
例如:
例如:
- 在網頁中找出未鏈接的 URL,並將他們轉換為超鏈接。
- 增加字體大小,使文本更具有可讀性。
然而,內文執行緒有一些限制,它們不能:
- 調用 chrome.* API (除了 chrome.extension 中的一部分)
- 使用所屬擴充工具頁面中定義的變數或函數
- 使用網頁或其他內文執行緒中定義的變數或函數
Extension 設定檔 (manifest.json) 設定
如果內文執行緒每一次都需要在當前頁面執行,就在設定檔中使用 content_scripts 字段注册它,如以下例子所示:
{
"name": "My extension",
...
"content_scripts": [
{
"matches": ["http://www.google.com/*"],
"css": ["mystyles.css"],
"js": ["jquery.js", "myscript.js"]
}
],
...
}
如果只是有時需要執行,可以使用 permissions 字段,如以编程方式插入部分所述。
{
"name": "My extension",
...
"permissions": [
"tabs", "http://www.google.com/*"
],
...
}
以編程方式插入
如果您的 JavaScript 或 CSS 不需要插入匹配的每一个頁面時,例如,如果您希望當使用者單擊瀏覽器按鈕的圖示時才執行內文執行緒,以编程方式插入代碼就十分有用。
要向頁面中插入代碼,您的擴充工具必须擁有該頁面的主機權限,並且還需要用到 chrome.tabs 模組。您可以使用設定檔 (manifest.json) 中的 permissions 字段獲得這些權限。
一旦您擁有了相應的權限,您可以通過調用 tabs.executeScript 向頁面插入 JavaScript 代碼。要插入 CSS 代碼,請使用 tabs.insertCSS。
下列代碼(来自 make_page_red 例子)當使用者單擊瀏覽器按鈕時向當前標籤頁插入並執行 JavaScript 代碼。
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript({
code: 'document.body.style.backgroundColor="red"'
});
});
"permissions": [
"activeTab"
],
通常不會直接插入代碼 (如前面的例子所示) ,而是將代碼放在一個文件中。您可以像這樣插入文件的內容:
chrome.tabs.executeScript(null, {file: "content_script.js"});
執行環境
內文執行緒在一個稱為隔離環境的特殊環境中執行。它們可以訪問所在頁面的 DOM,但是不能訪問當前頁面創建的任何 JavaScript 變數或函數。對於每個內文執行緒來說,就像没有其他 JavaScript 在當前頁面上執行。反過來也是如此:在當前頁面執行的 JavaScript 不能調用或訪問任何內文執行緒定義的變數或函數。
例如,考慮如下簡單頁面:
<html>
<button id="mybutton">click me</button>
<script>
var greeting = "hello, ";
var button = document.getElementById("mybutton");
button.person_name = "Bob";
button.addEventListener("click", function() {
alert(greeting + button.person_name + ".");
}, false);
</script>
</html>
假設如下內文執行緒插入到了 hello.html 中:
var greeting = "hola, ";
var button = document.getElementById("mybutton");
button.person_name = "Roberto";
button.addEventListener("click", function() {
alert(greeting + button.person_name + ".");
}, false);
現在,如果按鈕按下,您將會看到兩條問候。
隔離環境允許每一個內文執行緒更改自己的 JavaScript 環境,而不用擔心是否會與頁面或其他內文執行緒發生衝突。例如,一個內文執行緒可以包含 JQuery v1 而頁面可以包含 JQuery v2,並且他們互不影響。
隔離環境的另一個重要好處是將頁面上的 JavaScript 和擴充工具中的 JavaScript 完全區分開來,這樣我們就可以為內文執行緒提供額外的功能,而這些額外功能不應該從網頁中訪問,我們也不用擔心訪問他們的網頁。
網頁與擴充工具之間共享的 JavaScript 對象值得注意,例如 window.onload 事件。每一個隔離環境擁有該對象自己的副本,對該對象賦值只影響這一獨立的副本。例如,網頁和擴充工具都可以給 window.onload 賦值,但是都不能讀取另外一方的事件處理器。事件處理器將按照它們賦值的順序調用。
與嵌入的頁面通信
儘管內文執行緒執行環境和所在頁面是互相隔離的,但是它們都可以訪問頁面的 DOM。如果頁面想要和內文執行緒通信 (或者通過內文執行緒與擴充工具通信) ,必須通過共享的 DOM 進行。
可以使用 window.postMessage(或者 window.webkitPostMessage 用於可傳輸(Transferable)的對象):
var port = chrome.runtime.connect();
window.addEventListener("message", function(event) {
// We only accept messages from ourselves
if (event.source != window)
return;
if (event.data.type && (event.data.type == "FROM_PAGE")) {
console.log("Content script received: " + event.data.text);
port.postMessage(event.data.text);
}
}, false);
document.getElementById("theButton").addEventListener("click",
function() {
window.postMessage({ type: "FROM_PAGE", text: "Hello from the webpage!" }, "*");
}, false);
在上面的例子中,example.html(不是擴充工具的一部分)向自己發送消息,由內文執行緒截獲並檢查,然後發送至擴充工具進程。通過這種方式,頁面建立了與擴充工具之間的通信,通過類似的方式反過来也是可能的。
安全性考慮
當編寫內文執行緒時,應該注意兩個安全問題。首先,注意不要向插入內文執行緒的網站引入安全隱患。例如,如果內文執行緒從另一個網站接收內容 (例如通過發出 XMLHttpRequest) ,一定要注意把內容插入當前頁面前過濾可能的跨站腳本攻擊。例如,首選 innerText 而不是 innerHTML 插入內容。當在 HTTPS 頁面上獲取來自 HTTP 的內容時要特別小心,因為如果使用者在不安全的網路環境中,HTTP 內容可能會因為網路中的中間人攻擊而遭到破壞。
再者,儘管在隔離環境中運行內文執行緒提供了某些保護,但是如果不加區分地使用來自網頁的內容,惡意網頁仍然可能攻擊您的內文執行緒。例如,以下形式是危險的:
var data = document.getElementById("json-data")
// WARNING! Might be evaluating an evil script!
var parsed = eval("(" + data + ")")
var elmt_id = ...
// WARNING! elmt_id might be "); ... evil script ... //"!
window.setTimeout("animate(" + elmt_id + ")", 200);
因此,改用更安全的不執行代碼的 API:
var data = document.getElementById("json-data")
// JSON.parse does not evaluate the attacker's scripts.
var parsed = JSON.parse(data);
var elmt_id = ...
// The closure form of setTimeout does not evaluate scripts.
window.setTimeout(function() {
animate(elmt_id);
}, 200);
引用擴充工具的文件
使用 extension.getURL 獲得擴充工具的文件 URL,您可以像任何其他 URL 一樣使用獲得的结果,如以下代碼所示。
//Code for displaying <extensionDir>/images/myimage.png:
var imgURL = chrome.extension.getURL("images/myimage.png");
document.getElementById("someImage").src = imgURL;
總結:
看完這篇,可以瞭解內文執行緒在 Extension 中經常是扮演處理有關當前頁面的 DOM 的角色。
沒有留言:
張貼留言