用 Vue 開發自己的 Chrome 擴展
瀏覽器擴展程序是可以修改和增強 Web 瀏覽器功能的小程序。它們可用於各種任務,例如阻止廣告,管理密碼,組織標籤,改變網頁的外觀和行爲等等。
好消息是瀏覽器擴展並不難寫。可以用你已經熟悉的 Web 技術(HTML、CSS 和 JavaScript)創建 —— 就像普通網頁一樣。但是與網頁不同的是,擴展程序可以訪問許多特定於瀏覽器的 API,這纔是有趣的地方。
在本教程中,我將向你展示如何爲 Chrome 構建一個能夠改變新標籤頁行爲的簡單擴展。這個擴展程序的 JavaScript 部分,我將使用 Vue.js 框架,因爲它將允許我們快速啓動並運行,而且用 vue 工作是很有趣的。
Chrome 擴展程序的基礎知識
Chrome 擴展程序的核心部分是 manifest 文件 和後臺腳本。manifest 文件採用 JSON 格式,提供有關擴展的重要信息,例如其版本、資源或所需的權限。後臺腳本允許擴展對特定的瀏覽器事件做出反應,例如創建新選項卡。
爲了演示這些概念,讓我們先寫一個 “Hello,World!” Chrome 擴展。
創建一個名爲 hello-world-chrome
的新文件夾和兩個文件:manifest.json
和 background.js
:
mkdir hello-world-chrome
cd hello-world-chrome
touch manifest.json background.js
打開 manifest.json
並添加以下代碼:
{
"name": "Hello World Extension",
"version": "0.0.1",
"manifest_version": 2,
"background": {
"scripts": ["background.js"],
"persistent": false
}
}
name
、version
和 manifest_version
都是必填字段。name
和 version
字段可以是你想要的任何內容; manifest version 應設置爲 2(從 Chrome 18 開始)。
background
允許我們註冊一個後臺腳本, 在scripts
後面的數組中列出。除非擴展需要用 chrome.webRequest API 來阻止或修改網絡請求,否則 persistent
鍵應設置爲 false
。
將以下代碼添加到 background.js
,使瀏覽器在安裝擴展時彈出出 hello 對話框:
chrome.runtime.onInstalled.addListener(() => {
alert('Hello, World!');
});
最後安裝擴展程序。打開 Chrome 並在地址欄中輸入 chrome://extensions/
。你應該看到一個顯示已安裝擴展程序的頁面。
由於我們要從文件(而不是 Chrome 網上應用店)安裝自己的擴展程序,因此需要使用頁面右上角的切換按鈕來激活開發者模式。這應該添加一個額外的菜單欄,其中包含 Load unpacked 選項。單擊此按鈕並選擇你之前創建的 hello-world-chrome
文件夾。單擊打開,應該能夠看到已安裝的擴展,並彈出 “Hello,World!” 窗口。
Hello World
恭喜!你剛剛製作了一個 Chrome 擴展程序。
覆蓋 Chrome 的新標籤頁
爲了在打開新選項卡時迎接我們的是自己的擴展程序。可以通過使用 Override Pages API 來完成此操作。
注意:在你取得進展之前,請務必停用其他能夠覆蓋 Chrome 新標籤頁的擴展程序。一次只允許一個擴展改變這種行爲。
首先創建一個要顯示的頁面,而不是新的標籤頁。我們稱之爲 tab.html
。它應該與清單文件和後臺腳本位於同一文件夾中:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>My New Tab Page!</title>
</head>
<body>
<h1>My New Tab Page!</h1>
<p>You can put any content here you like</p>
</body>
</html>
接下來需要讓擴展知道頁面的存在。可以通過在清單文件中指定 chrome_url_overrides
來實現,如下所示:
"chrome_url_overrides": {
"newtab": "tab.html"
}
最後,你需要重新加載擴展才能使更改生效。你可以通過在 Chrome 的擴展程序頁面上單擊 Hello World 擴展程序的 reload 圖標來執行此操作。
重新加載擴展
現在,當你打開新標籤頁時,你的自定義消息會出現。
將 Vue 添加到擴展
現在我們有一個非常基本的擴展,接下來要實現剩下的需功能了。當用戶打開新標籤頁時,我希望擴展能夠:
-
從精彩的笑話網站 icanhazdadjoke.com 獲取一個笑話。
-
以良好的格式向用戶顯示該笑話。
-
顯示用戶喜歡該笑話的按鈕。這樣可以把笑話保存到
chrome.storage
。 -
顯示一個按鈕,供用戶查看已收藏的笑話。
當然你也可以用純 JavaScript 或像 jQuery 這樣的庫來完成所有這些 —— 你開心就好!
但是出於本教程的目的,我將用 Vue 和令人敬畏的 vue-web-extension 樣板來實現此功能。
用 Vue 可以讓我又快又好地編寫更有條理的代碼。正如我們所看到的,樣板文件提供了幾個腳本,可以在構建 Chrome 擴展程序時解決一些痛苦的常見任務(例如:每當你進行更改時都必須重新加載擴展程序)。
vue-web-extension-boilerplate
本節假定你的計算機上安裝了 Node 和 npm。如果不是這樣,你可以到 https://nodejs.org/en/ 獲取相關二進制文件,或者你可以使用版本管理器。我建議使用版本管理器。
我們還需要安裝 Vue CLI 和 @vue/cli-init package:
npm install -g @vue/cli
npm install -g @vue/cli-init
完成後,讓我們得到樣板的副本:
vue init kocal/vue-web-extension new-tab-page
這將打開一個嚮導,詢問你一堆問題。爲了保證本教程的重點,我把回答列出來:
? Project name new-tab-page
? Project description A Vue.js web extension
? Author James Hibbard <jim@example.com>
? License MIT
? Use Mozilla's web-extension polyfill? No
? Provide an options page? No
? Install vue-router? No
? Install vuex? No
? Install axios? Yes
? Install ESLint? No
? Install Prettier? No
? Automatically install dependencies? npm
你可以根據自己的喜好調整答案,但是你一定要安裝 axios。我們會用它來獲取笑話。
接下來,切換到項目目錄並安裝依賴項:
cd new-tab-page
npm install
然後就可以用樣板提供的腳本構建我們的新擴展了:
npm run watch:dev
這會將擴展構建到項目根目錄中的 dist
文件夾中,來進行開發並監視更改。
要將擴展程序添加到 Chrome,請執行上述相同的步驟,要選擇 dist
文件夾作爲擴展程序目錄。如果一切按計劃進行,那麼當擴展程序初始化時,你應該看到 “Hello world!” 消息。
項目設置
讓我們花一點時間來看看樣板給了我們些什麼。當前文件夾結構應如下所示:
.
├── dist
│ └── <the built extension>
├── node_modules
│ └── <one or two files and folders>
├── package.json
├── package-lock.json
├── scripts
│ ├── build-zip.js
│ └── remove-evals.js
├── src
│ ├── background.js
│ ├── icons
│ │ ├── icon_128.png
│ │ ├── icon_48.png
│ │ └── icon.xcf
│ ├── manifest.json
│ └── popup
│ ├── App.vue
│ ├── popup.html
│ └── popup.js
└── webpack.config.js
在項目根目錄中可以看到,樣板文件正在使用 webpack。這很好,因爲這爲我們的後臺腳本提供了 Hot Module Reloading。
src
文件夾包含我們將用於擴展的所有文件。manifest 文件和 background.js
對於我們來說是熟悉的,但也要注意包含 Vue 組件的 popup
文件夾。當樣板文件將擴展構建到 dist
文件夾中時,它將通過 vue-loader 管理所有 .vue
文件並輸出一個瀏覽器可以理解的 JavaScript 包。
在 src
文件夾中還有一個 icons
文件夾。如果你看一眼 Chrome 的工具欄,會看到我們的擴展程序的新圖標(也被稱爲 browser action)。這就是從此文件夾中拿到的。如果單擊它,你應該會看到一個彈出窗口,顯示 “Hello world!” 這是由 popup/App.vue
創建的。
最後,請注 scripts
文件夾的兩個腳本:一個用於刪除 eval
用法以符合 Chrome Web Store 的內容安全策略,另一個用於當你要把擴展上傳到 Chrome Web Store 時將其打包到 .zip 文件中,。
在 package.json
文件中還聲明瞭各種腳本。我們將用 npm run watch:dev
來開發擴展,然後使用 npm run build-zip
生成一個 ZIP 文件以上傳到 Chrome Web Store。
在新標籤頁中使用 Vue 組件
首先從 background.js
中刪除煩人的 alert
語句。
在 src
文件夾中創建一個新的 tab
文件夾來存放新標籤頁的代碼。我們將在這個新文件夾中添加三個文件 —— App.vue
,tab.html
, tab.js
:
mkdir src/tab
touch src/tab/{App.vue,tab.html,tab.js}
打開 tab.html
並添加以下內容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>New Tab Page</title>
<link rel="stylesheet" href="tab.css">
</head>
<body>
<div id="app"></div>
<script src="tab.js"></script>
</body>
</html>
這裏沒什麼特別的。這是一個簡單的 HTML 頁面,它將保存我們的 Vue 實例。
接下來在 tab.js
中添加:
import Vue from 'vue';
import App from './App';
new Vue({
el: '#app',
render: h => h(App)
});
在這裏導入 Vue,用它爲元素傳遞一個選擇器,然後告訴它渲染 App
組件。
最後在 App.vue
中寫如下代碼:
<template>
<p>{{ message }}</p>
</template>
<script>
export default {
data () {
return {
message: "My new tab page"
}
}
}
</script>
<style scoped>
p {
font-size: 20px;
}
</style>
在使用這個新標籤頁之前,我們需要更新 manifest 文件:
{
"name":"new-tab-page",
...
"chrome_url_overrides": {
"newtab": "tab/tab.html"
}
}
爲了使它們可用於擴展,我們還需要讓樣板編譯我們的文件並複製到 dist
文件夾。
像下面這樣修改 webpack.config.js
,更新entry
和plugins
鍵:
entry: {
'background': './background.js',
'popup/popup': './popup/popup.js',
'tab/tab': './tab/tab.js'
}
plugins: [
...
new CopyWebpackPlugin([
{ from: 'icons', to: 'icons', ignore: ['icon.xcf'] },
{ from: 'popup/popup.html', to: 'popup/popup.html', transform: transformHtml },
{ from: 'tab/tab.html', to: 'tab/tab.html', transform: transformHtml },
...
})
你需要重新啓動 npm run watch:dev
任務才能使這些更改生效。完成此操作後,重新加載擴展程序並打開新選項卡。你應該會看到 “My new tab page”。
My new tab page
獲取並顯示笑話
好的,我們已經覆蓋了 Chrome 的新標籤頁,並且將其替換爲了 mini Vue app。但是我們要做的不僅僅是顯示一條消息。
更改 src/tab/App.vue
中的模板部分如下:
<template>
<div>
<div v-if="loading">
<p>Loading...</p>
</div>
<div v-else>
<p class="joke">{{ joke }}</p>
</div>
</div>
</template>
將 <script>
部分更改爲如下代碼:
<script>
import axios from 'axios';
export default {
data () {
return {
loading: true,
joke: "",
}
},
mounted() {
axios.get(
"https://icanhazdadjoke.com/",
{ 'headers': { 'Accept': 'application/json' } }
)
.then(res => {
this.joke = res.data.joke
this.loading = false;
});
}
}
</script>
最後,將 <style>
部分更改爲如下代碼:
<style>
body {
height: 98vh;
text-align: center;
color: #353638;
font-size: 22px;
line-height: 30px;
font-family: Merriweather,Georgia,serif;
background-size: 200px;
display: flex;
align-items: center;
justify-content: center;
}
.joke {
max-width: 800px;
}
</style>
如果你正在運行 npm run watch:dev
任務,則擴展程序會自動重新加載,並且每當你打開新標籤頁時都會看到一個笑話。
一個英文笑話
接下來花點時間來了解一下自己都做了些什麼。
在模板中,我們使用 v-if 塊來顯示加載消息或笑話,具體取決於 loading
的狀態。最初它被設置爲 true
(顯示加載消息),然後我們的腳本將觸發 Ajax 請求來檢索笑話。一旦 Ajax 請求完成,loading
屬性將被設置爲 false
,導致組件被重新渲染並顯示笑話。
在 <script>
部分,我們導入了 axios,然後聲明瞭幾個數據屬性——前面提到的 loading
屬性和一個 joke
屬性來保存這個笑話。然後使用了 mount
生命週期鉤子,一旦我們的 Vue 實例被掛載就會觸發,向 joke API 發出 Ajax 請求。請求完成後,更新兩個數據屬性使組件重新渲染。
到目前爲止還挺好。
將笑話持持久化到 Chrome Storage
接下來,添加一些能夠讓用戶喜歡一個笑話和列出喜歡的笑話列表的按鈕。由於我們將使用 Chrome’s storage API 來保存這些笑話,所以可能需要添加第三個按鈕來刪除 storage 中的笑話。
將按鈕添加到 v-else 塊:
<div v-else>
<p class="joke">{{ joke }}</p>
<button @click="likeJoke" :disabled="likeButtonDisabled">Like Joke</button>
<button @click="logJokes" class="btn">Log Jokes</button>
<button @click="clearStorage" class="btn">Clear Storage</button>
</div>
沒有什麼令人興奮的東西了。請注意我們將類似按鈕的 disabled
屬性綁定到 Vue 實例上的數據屬性來確定其狀態。這是因爲用戶不應該多次喜歡一個笑話。
接下來,將 click handler 和 Like Button Disabled
添加到腳本部分:
export default {
data () {
return {
loading: true,
joke: "",
likeButtonDisabled: false
}
},
methods: {
likeJoke(){
chrome.storage.local.get("jokes", (res) => {
if(!res.jokes) res.jokes = [];
res.jokes.push(this.joke)
chrome.storage.local.set(res);
this.likeButtonDisabled = true;
});
},
logJokes(){
chrome.storage.local.get("jokes", (res) => {
if(res.jokes) res.jokes.map(joke => console.log(joke))
});
},
clearStorage(){
chrome.storage.local.clear();
}
},
mounted() { ... }
}
在這裏,我們聲明瞭三個新方法來處理這三個新按鈕。
likeJoke
方法在 Chrome 的存儲中查找 jokes
屬性。如果它不存在(也就是說,用戶尚未喜歡一個笑話),會將其初始化爲空數組。然後它將當前的笑話推送到此數組並將其保存到 storage。最後,將 likeButtonDisabled
數據屬性設置爲 true
,並禁用 like 按鈕。
logJokes
方法還在 Chrome storage 中查找 jokes
屬性。如果找到了,會遍歷其所有條目並將它們輸出到控制檯。
clearStorage
方法負責清除數據。
繼續在擴展中調整這個新功能,直到自己滿意。
將笑話輸出到控制檯
爲擴展做一些美化
它能夠工作了,但是按鈕是很醜,頁面也有點簡單。下面就要給擴展做一些潤色。
下一步,安裝 vue-awesome 庫。它能夠使我們在頁面上使用 Font Awesome 圖標,並使這些按鈕看起來更漂亮一些:
npm install vue-awesome
在 src/tab/tab.js
中對庫進行註冊:
import Vue from 'vue';
import App from './App';
import "vue-awesome/icons";
import Icon from "vue-awesome/components/Icon";
Vue.component("icon", Icon);
new Vue({
el: '#app',
render: h => h(App)
});
修改模板:
<template>
<div>
<div v-if="loading" class="centered">
<p>Loading...</p>
</div>
<div v-else>
<p class="joke">{{ joke }}</p>
<div class="button-container">
<button @click="likeJoke" :disabled="likeButtonDisabled" class="btn"><icon ></icon></button>
<button @click="logJokes" class="btn"><icon ></icon></button>
<button @click="clearStorage" class="btn"><icon ></icon></button>
</div>
</div>
</div>
</template>
最後,讓我們爲按鈕添加更多樣式,並添加一張圖片:
<style>
body {
height: 98vh;
text-align: center;
color: #353638;
font-size: 22px;
line-height: 30px;
font-family: Merriweather,Georgia,serif;
background: url("https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2018/12/1544189726troll-dad.png") no-repeat 1% 99%;
background-size: 200px;
display: flex;
align-items: center;
justify-content: center;
}
.joke {
max-width: 800px;
}
.button-container {
position: absolute;
right: 0px;
top: calc(50% - 74px);
}
.btn {
background-color: #D8D8D8;
border: none;
color: white;
padding: 12px 16px;
font-size: 16px;
cursor: pointer;
display: block;
margin-bottom: 5px;
width: 50px;
}
.btn:hover {
background-color: #C8C8C8;
}
.btn:disabled {
background-color: #909090;
}
</style>
重新加載擴展並打開一個新標籤,你應該看到這樣的東西。
成果
將擴展程序上傳到 Chrome Web Store
如果想讓其他人也可以使用你的擴展程序,可以通過 Chrome Web Store 做到。
首先你需要有一個 Google 帳戶,可以用該帳戶登錄 Developer Dashboard 。系統會提示你輸入開發人員詳細信息,在發佈第一個應用程序之前,你必須支付 5 美元的開發人員註冊費(通過信用卡)。
接下來,你需要爲自己的應用創建一個 ZIP 文件。你可以通過 npm run build-zip
在本地執行這項操作。這會在項目根目錄中創建一個名爲 dist-zip
的文件夾,其中包含準備上傳到 Web Store 的 ZIP 文件。
對於簡單的小擴展,這就夠了。但是,在你上傳自己的擴展之前,請務必閱讀官方 Publish in the Chrome Web Store 指南。
總結
在本教程中,我重點介紹了 Chrome 擴展程序的主要部分,並展示瞭如何用在 Vue.js 中 vue-web-extension 樣板構建擴展程序,最後講解了如何將擴展上傳到 Web Store。
希望你喜歡本教程,並用它指導你始構建自己的 Chrome 擴展。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/rNW7GVoEc5xak8mNoq5d-w