將一個前端專案改寫為chromo外掛(一)

saltfish666發表於2018-05-27

編寫第一個chrome外掛?

編寫chrome外掛完全就是前端知識加上一些專門的知識。 假設pj1資料夾下有檔案index.html

<!DOCTYPE html>
<html>
<head>
    <title>Hi</title>
    <meta charset="utf-8"/>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
    <div id="main">
    	hello,world
    </div>
   <script type="text/javascript">
        setTimeout(()=>{
            document.getElementById("main").innerText = "hi,saltfish"
        },1000)
   </script>
</body>
</html>
複製程式碼

嗯,現在看來他只是普通的html,其實,你只要在當前資料夾下加上manifest.json檔案,chrome瀏覽器就可以把它識別為外掛,成為瀏覽器右上角的小圖示。

將一個前端專案改寫為chromo外掛(一)

如何什麼是manifest.json,如何編寫?

manifest 是貨單的意思,這個檔案就是chrome規定的的外掛配置檔案的名稱

{
	"name": "My Extension",
    "version": "1.0",
    "manifest_version": 2,
    "browser_action": {
        "default_popup": "index.html"
    }
}
複製程式碼

name、version不用解釋,manifest_version類似與XML的schema檔案,用來約束manifest_version自身的格式,目前,它的值永遠是2。

default_popup作用:當使用者點選外掛的小圖示後,顯示的畫面,就是把它所引用的HTML渲染後得到的。

如何釋出?

在chrome瀏覽器訪問 chrome://extensions/ 就會看到

將一個前端專案改寫為chromo外掛(一)
點選 LOAD UNPACKED 再選取存放檔案的資料夾即可。你會立刻在瀏覽器又上角看到自己的外掛。 點選後會顯示index.html對應的內容

將一個前端專案改寫為chromo外掛(一)

為了統一規範,我們可以把index.html改名為popup.html,同時記得修改"default_popup"的值

關於popup.html

我們可以看到,chrome外掛的UI是用HTML編寫的(相應的指令碼也是js寫得),所以chrome外掛對我們前端開發者來說非常好學。

每當我們點選小圖示時,chrome就會讀取配置檔案中定義的HTML檔案。

在chrome外掛的UI中,沒有title等的概念,所以我們可以吧一些沒用的標籤給刪除掉。

css檔案和一般前端一模一樣

在`style.css``新增

body{
    width: 300px;
    height: 300px;
    background-color: antiquewhite;
}
複製程式碼

(記得在popup.html中引用哦) 在重新整理外掛,可以看到

將一個前端專案改寫為chromo外掛(一)

js指令碼

細心的同學可能注意到,在之前的popup.html中明明有指令碼

<script type="text/javascript">
    setTimeout(()=>{
        document.getElementById("main").innerText = "hi,saltfish"
    },1000)
</script>
複製程式碼

為什麼頁面一直不重新整理? 因為chrome官方規定js指令碼只能引入,不能嵌入HTML(我也不知道為什麼這樣規定) 新增標籤<script src="script.js"></script>並將指令碼移動到對應位置,再重新整理外掛,你就可以看到正確的結果了。

這裡的js指令碼和一般的js環境相同,不過console.log 不能用,因為chrome也不知往哪裡列印結果,不過你可以使用alert函式來除錯程式碼。

popup.html的生命週期

該檔案在使用者點選小圖示後載入,和你開啟一般的網頁一模一樣,只不過對應的UI顯示在瀏覽器的右上角,每當你點選其他地方chrome就會關閉這個視窗,對應的js環境也會被銷燬,也就是說,你每次點選小圖示,就會重新渲染HTML和css,並重新執行js程式碼。

正是因為這個特性,popup.html以及他引入的js指令碼,只處理UI相關。一些業務邏輯放在其他地方,下面來介紹

確認下目錄結構

$ tree
.
├── manifest.json
├── popup.html
├── script.js
└── style.css
複製程式碼
$ cat manifest.json
{
    "name": "My Extension",
    "version": "1.0",
    "manifest_version": 2,
    "browser_action": {
        "default_popup": "popup.html"
    }
}
複製程式碼

background.js

將manifest.json修改為:

{
	"name": "My Extension",
    "version": "1.0",
    "manifest_version": 2,
    "browser_action": {
        "default_icon": {
            "19": "images/icon19.png"
        },
        "default_popup": "popup.html"
    },
    "background": {
        "scripts": [
            "background/bg.js"
        ]
    }
}
複製程式碼

並新增background/bg.js檔案, background欄位定義的js程式碼在開啟瀏覽器時執行,知道瀏覽器關閉。

setInterval(()=>{
    alert((new Date()).toDateString())
},2000)
複製程式碼

在bg.js新增上述程式碼,發現瀏覽器一經載入,就不停彈出對話方塊,不管是否點選了小圖示,不管你做了什麼操作,他都是一直執行。

現在註釋上述程式碼

content_scripts

有時候我們的外掛希望做到: 當使用者開啟某個網頁後,再進行操作。比如使用者開啟github.com後,彈出“hi,it is github”。如何實現呢 再manifest.json新增:

"content_scripts": [
        {
            "matches": ["*://github.com/*"],
            "js": ["content/github.com.js"]
        }
    ]
複製程式碼

並新增相應檔案,在js程式碼中寫上

alert("hi,it is github")
複製程式碼

content_script是個陣列,定義了一些url與script的聯絡,噹噹使用者訪問相應的網址的時候,chrome會等待頁面載入完成後,執行相應的js程式碼。

content_script可以訪問當前頁面的dom和localstorage,但是無法訪問當前頁面的js變數

content_script在每次載入相匹配的頁面後執行,頁面被重新整理後對應的content_script也會被重行執行。

三種js環境

我們看到,我們之前提及了三種js環境、background.js,content_script,popup.html引用的,現在來捋一捋他們的關係和區別

內容 background.js content_script popup.js
生命週期 瀏覽器載入後一直執行 開啟相應url後執行 每次點選圖示後執行
dom 沒有能操作的dom 能讀取當前頁面dom popup.html的dom
js變數 如果有多個bg.js,並列指令碼間不共享js變數 與原生頁面的js變數隔絕,如果多個content_script匹配到同一個url,他們的一直執行,js變數依舊隔絕
localstorage 每一個外掛對應一個localstorage,被不同的bg.js共享 和當前url的localstorage共享 和當前外掛共享(這是bg.js和popup.js一種通訊方式)

這幾點是我自己在學習中,不斷測試,得到這幾點結論(測試過程就不寫了,很容易想到)。

確認下目錄

$ tree
.
├── background
│   └── bg.js
├── content
│   └── github.com.js
├── manifest.json
├── popup.html
├── script.js
└── style.css
複製程式碼

頁面間通訊

之前,說過,各中js程式碼中的變數是不共享的,那麼我們如何讓他們通訊呢? 比如,當使用者訪問github.com時,讓content_script向bg.js 說一聲hello? chrome設計了一個介面api: 在github.com.js:

let message = "hello"
chrome.runtime.sendMessage(message, function(response){
    console.log(response)
});
複製程式碼

bg.js

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse){
    alert(message)
    sendResponse({content:"hi,it is bg.js"})
});
複製程式碼

重新整理外掛並開啟github,發現彈出“hello",對應github頁面控制檯也列印出{content:"hi,it is bg.js"}

可以看到:整個過程類似於HTTP請求,content_script發起一個請求,bg.js迴應。 而且執行直接傳遞js變數

結語

好了這幾點是前置知識,下一篇文章來改造一個前端專案。

相關文章