用 Vue 開發本身的 Chrome 擴展程序

翻譯:瘋狂的技術宅javascript

原文:www.sitepoint.com/build-vue-c…css

未經容許嚴禁轉載html

瀏覽器擴展程序是能夠修改和加強 Web 瀏覽器功能的小程序。它們可用於各類任務,例如阻止廣告,管理密碼,組織標籤,改變網頁的外觀和行爲等等。前端

好消息是瀏覽器擴展並不難寫。能夠用你已經熟悉的 Web 技術(HTML、CSS 和 JavaScript)建立 —— 就像普通網頁同樣。可是與網頁不一樣的是,擴展程序能夠訪問許多特定於瀏覽器的 API,這纔是有趣的地方。vue

在本教程中,我將向你展現如何爲 Chrome 構建一個可以改變新標籤頁行爲的簡單擴展。這個擴展程序的 JavaScript 部分,我將使用 Vue.js 框架,由於它將容許咱們快速啓動並運行,並且用 vue 工做是頗有趣的。java

本教程的代碼能夠在GitHub上找到node

Chrome 擴展程序的基礎知識

Chrome擴展程序的核心部分是 manifest 文件後臺腳本。manifest 文件採用JSON格式,提供有關擴展的重要信息,例如其版本、資源或所需的權限。後臺腳本容許擴展對特定的瀏覽器事件作出反應,例如建立新選項卡。jquery

爲了演示這些概念,讓咱們先寫一個「Hello,World!」 Chrome 擴展。webpack

建立一個名爲 hello-world-chrome 的新文件夾和兩個文件:manifest.jsonbackground.jsios

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
  }
}
複製代碼

nameversionmanifest_version 都是必填字段。 nameversion 字段能夠是你想要的任何內容; 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 Extension

恭喜!你剛剛製做了一個 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。若是不是這樣,你能夠到 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.vuetab.htmltab.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,更新entryplugins鍵:

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 任務,則擴展程序會自動從新加載,而且每當你打開新標籤頁時都會看到一個笑話。

How does a French skeleton say hello? Bone-jour

接下來花點時間來了解一下本身都作了些什麼。

在模板中,咱們使用 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 name="thumbs-up"></icon></button>
        <button @click="logJokes" class="btn"><icon name="list"></icon></button>
        <button @click="clearStorage" class="btn"><icon name="trash"></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 擴展。

歡迎關注前端公衆號:前端先鋒,獲取更多前端乾貨。

相關文章
相關標籤/搜索