1. 程式人生 > 程式設計 >vue開發chrome外掛,實現獲取介面資料和儲存到資料庫功能

vue開發chrome外掛,實現獲取介面資料和儲存到資料庫功能

前言

最近在評估專案時,要開啟評估平臺,檢視平臺和儲存平臺,感覺非常繁瑣,開發了一款可以獲取評估平臺數據,檢視專案排期和直接儲存資料到資料庫的chrome外掛,由於我需要使用之前vue封裝的一個日曆外掛,這裡就用vue來開發這個外掛。

開發前準備

要開發一個chrome外掛,我們首先需要了解chrome外掛的基本結構和對應的功能。
每個擴充套件的檔案型別和目錄數量有所不同,但都必須有 manifest。 一些基本但有用的擴充套件程式可能僅由 manifest 及其工具欄圖示組成。

manifest.json

 {
  "name": "My Extension",// "副檔名"
  "version": "2.1",// 當前建立擴充套件版本號
  "description": "Gets information from Google.",//"擴充套件描述"
  "icons": { // 擴充套件工具介面使用圖示
   "128": "icon_16.png","128": "icon_32.png","128": "icon_48.png","128": "icon_128.png"
  },"background": { // 擴充套件常常用一個單獨的長時間執行的指令碼來管理一些任務或者狀態
   "persistent": false,"scripts": ["background_script.js"] // 後臺常駐指令碼,自動執行,直到關閉瀏覽器。可根據需求自行設定
  },"permissions": ["https://*.google.com/","activeTab"],//開啟拓展許可權
  "browser_action": { 
   "default_icon": "icon_16.png",// 器右上角顯示
   "default_popup": "popup.html" /** 滑鼠移入,顯示簡短擴充套件文字描述 **/
  },"content_scripts": [{  // ontent scripts是在Web頁面內執行的javascript指令碼。通過使用標準的DOM,它們可以獲取瀏覽器所訪問頁面的詳細資訊,並可以修改這些資訊。
  "js": ["script/contentscript.js"],/** 需要注入的指令碼 **/
  "matches": [  /** 匹配網址(支援正則),成功即注入(其餘屬性自行查詢) **/
    "http://*/*","https://*/*"
   ]
  }]
  }

vue開發chrome外掛

我們需要使用vue來開發外掛,幾經搜尋,查到一款樣板,很方便我們進行vue開發外掛,便引入該樣板來進行開發。

引入vue-web-extension樣板來實現vue開發

 npm install -g @vue/cli
 npm install -g @vue/cli-init
 vue init kocal/vue-web-extension new-tab-page

然後切換到專案目錄安裝依賴項

 cd new-tab-page
 npm install

我們可以執行

 npm run watch:dev

在專案根目錄中會得到一個dist 資料夾,我們直接安裝解壓的擴充套件程式,選擇這個dist,就可以進行開發並監視更改。

樣板檔案的基本格式

├── 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進行打包,

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。

建立外掛介面

我們直接修改popup.html

popup.html

<!DOCTYPE html>
<html lang="zh">
<head>
 <meta charset="UTF-8">
 <title>Title</title>
</head>
<body>
 <link href="popup.css" rel="external nofollow" rel="stylesheet">
 <div id="app">
 </div>
 <script src="popup.js"></script>
</body>
</html>

這裡我們引入popup.css和popup.js 在popup.css放入我們需要用的樣式 在popup.js中,來引入我們的vue檔案

popup.js

 import Vue from 'vue'
 import { Tabs,TabPane,Dialog,Button,Form,FormItem,Input,DatePicker,Message,Alert,Tooltip,MessageBox } from 'element-ui';
 import 'element-ui/lib/theme-chalk/index.css';
 import App from './App'
 Vue.use(Tabs);
 Vue.use(TabPane);
 Vue.use(Dialog);
 Vue.use(Button);
 Vue.use(Form);
 Vue.use(FormItem);
 Vue.use(Input);
 Vue.use(DatePicker);
 Vue.use(Tooltip);
 Vue.use(Alert);
 Vue.prototype.$message = Message;
 Vue.prototype.$confirm = MessageBox.confirm;
 new Vue({
  el: '#app',render: h => h(App)
 })

這裡,我們主要按需引入element-ui中的控制元件,和app.vue元件

app.vue

 <template>
 <div id="app" style="height: 580px;overflow-y: hidden;width:680px;">
  <div>
   模板
  </div>
  <customPlan :projectData="projectData" :loginPerson="loginPerson"></customPlan>
 </div>
</template>

<script>
import customPlan from '../components/customPlan'
let { Pinyin } = require('../script/pinyin')
let pinyin = new Pinyin()
export default {
 components: { customPlan },data() {
  return {
   loginPerson: '',projectData: {
    departmentName: '',developer: '',endDate: '',evaluator: '',isDeprecated: false,isIncludeSaturday: false,isNewComponent: false,issureAdress: '',msg: '',name: '',startDate: '',workDay: '',year: 2020
   }
  }
 },created() {
  this.getUrl()
 },methods: { 
  getCaption(obj) {
   var index = obj.lastIndexOf(',')
   obj = obj.substring(index + 1,obj.length)
   return obj
  },/**  
  * @desc 獲取當前頁面的url
  */
  getUrl() {
   chrome.tabs.getSelected(null,tab => {
    console.log(tab,"tab")
    this.projectData.issureAdress = tab.url
    chrome.tabs.sendMessage(tab.id,{ greet: 'hello' },response => {
     if (response && response.developer && response.processName) {
      let developer = pinyin
       .getFullChars(this.getCaption(response.developer))
       .toLowerCase()
      this.projectData.evaluator = developer
      this.projectData.name = response.processName
     } else if (response && response.developer && !response.processName) {
      var index = response.developer.lastIndexOf('@')
      response.developer = response.developer.substring(
       index + 1,response.developer.length
      )
      this.loginPerson = response.loginPerson
      this.projectData.evaluator = response.developer
      this.projectData.name =response.peocessName
     }
    })
   })
  }
 }
}
</script>

在manifest.json中引入

  "browser_action": {
   "default_title": "測試","default_popup": "popup/popup.html"
  },

這裡我們主要引入了我們的日曆控制元件customPlan,大家可以按需引入自己需要的元件。到這裡,我們的外掛介面基本搭建完成了。

獲取當前介面資料,並在外掛中進行監聽

需要獲取當前介面資料,就需要在Web頁面內執行的javascript指令碼。通過使用標準的DOM,它們可以獲取瀏覽器所訪問頁面的詳細資訊,並可以修改這些資訊。就需要content_scripts裡面引入我們需要的contentscript.js檔案,在這個js檔案中,可以獲取瀏覽器所訪問頁面的詳細資訊

 "content_scripts": [{
  "js": ["script/contentscript.js"],"matches": [
   "http://*/*","https://*/*"
  ]
 }]

contentscript.js檔案配置如下

document.addEventListener('click',function (e) {
  let isCurrect = e.path.length > 3&&e.path[4].innerText&&e.path[4].innerText.indexOf('提交需求') != -1 && e.target.innerText === '確 定' && document.getElementsByClassName('layout-nav') && document.getElementsByClassName('layout-nav')[0].children
  if (isCurrect) {
    if (document.getElementsByClassName('user-table') && document.getElementsByClassName('user-table')[0] && document.getElementsByClassName('user-table')[0].getElementsByClassName('el-table__row').length > 0) {
      var port = chrome.runtime.connect({ name: "custommanage" });//通道名稱
      let loginPerson = document.getElementsByClassName('layout-nav') && document.getElementsByClassName('layout-nav')[0].children ? document.getElementsByClassName('layout-nav')[0].children[0].innerText : ''
      let partMentName = document.getElementsByClassName('layout-nav') && document.getElementsByClassName('layout-nav')[0].children ? document.getElementsByClassName('layout-nav')[0].children[3].innerText : ''
      let processName = document.getElementsByClassName('el-input__inner') && document.getElementsByClassName('layout-nav')[0].children ? document.getElementsByClassName('el-input__inner')[0].title : ''
      let tableElement = document.getElementsByClassName('user-table') ? document.getElementsByClassName('user-table')[0].getElementsByClassName('el-table__row') : []
      let choseSelect = []
      for (let value of tableElement) {
        if (value.innerText.indexOf(partMentName) !== -1) {
          choseSelect = value
        }
      }
      let developPerson = ''
      let startTime = ''
      let endTime = ''
      if (choseSelect && choseSelect.getElementsByTagName('td')) {
        developPerson = choseSelect.getElementsByTagName('td')[1].innerText
        startTime = choseSelect.getElementsByTagName('td')[3].getElementsByTagName('input')[0].title
        endTime = choseSelect.getElementsByTagName('td')[4].getElementsByTagName('input')[0].title
      }
      let item = {
        "loginPerson": loginPerson,"processName": processName,"developPerson": developPerson,"startTime": startTime,"endTime": endTime
      }
      port.postMessage(item);//傳送訊息  
    } else {
      alert('未查到該專案預排人員與預排時間,請點開外掛或開啟定製管理系統手動新增專案!')
    }
  }
});

這裡獲取元素就是js基本知識了。主要使用chrome外掛的api

chrome.runtime.connect

保持長期連線的模式,在content scripts與Chrome擴充套件程式頁面之間建立通道(可以為通道命名),可以處理多個訊息。在通道的兩端分別擁有一個chrome.runtime.Port物件,用以收發訊息。這裡主要在我們點選需要的按鈕時,就會向chrome外掛傳送訊息。
在content scripts主動建立通道如下:

 var port = chrome.runtime.connect({name: "custommanage"});//通道名稱
 port.postMessage({joke: "Knock knock"});//傳送訊息
 port.onMessage.addListener(function(msg) {//監聽訊息
   port.postMessage({answer: "custommanage"});
 });

獲取到介面資訊後,在content scripts發生請求訊息給Google Chrome擴充套件程式,我們在外掛中就需要獲取獲取的介面資訊了

chrome擴充套件獲取資訊

我們在background.js中建立通道,獲取web介面傳回的資訊

chrome.tabs.query(
 { active: true,currentWindow: true },function (tabs) {
  var port = chrome.tabs.connect(//建立通道
   tabs[0].id,{ name: "custommanage" }//通道名稱
  );
 });
chrome.runtime.onConnect.addListener((port) => {
 console.assert(port.name == "custommanage");
 port.onMessage.addListener((res) => {  
   addActon(res)
 });
});

addAction函式即是儲存我們獲取的資料到資料庫。

 /**
  * @desc 新增獲取資料到資料庫
  */
function addProject (params) {  
   let paramsObj = Object.assign({},params)
   let optsUpdata = {
    method: 'POST',//請求方法
    body: JSON.stringify(paramsObj),//請求體
    headers: {
     Accept: 'application/json','Content-Type': 'application/json'
    }
   }
   fetch('http://****/api/EditConfirmWork',optsUpdata)
    .then(response => {
     return response.json()
    })
    .then(data => {
     if (data.code === 0) {
      alert('更新成功!')
     }
    })
    .catch(error => {
     alert(error)
    })
}

這裡我們採用fetch函式來連線資料庫,和修改資料庫,後端介面也需要做一些跨域相關處理,才能正常連線,我這裡用的Node開發的後端,大致程式碼如下

//跨域
app.all('*',function (req,res,next) {
 res.header("Access-Control-Allow-Origin","*"); 
 res.header('Access-Control-Allow-Methods','PUT,GET,POST,DELETE,OPTIONS');
 res.header('Access-Control-Allow-Headers','Origin,X-Requested-With,Content-Type,Accept');
 res.header('Access-Control-Allow-Credentials',true)
 next();
});

到此,獲取介面資料,並自動儲存到資料庫功能已完成,background.js我們在manifest.json引用下。

"background": {
  "scripts": ["script/background.js"]
 },

我們需要將編輯好的外掛通過webpack打包,還需要在webpack.config.js配置一下,然後執行npm run watch:dev 就可以得到我們需要的dist,安裝到擴充套件程式就可使用了。

webpack.config.js配置如下

const webpack = require('webpack');
const ejs = require('ejs');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const WebpackShellPlugin = require('webpack-shell-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ChromeExtensionReloader = require('webpack-chrome-extension-reloader');
const { VueLoaderPlugin } = require('vue-loader');
const { version } = require('./package.json');

const config = {
 mode: process.env.NODE_ENV,context: __dirname + '/src',entry: {
  'popup/popup': './popup/popup.js','script/contentscript': './script/contentscript.js','script/background': './script/background.js'
 },output: {
  path: __dirname + '/dist',filename: '[name].js',},resolve: {
  extensions: ['.js','.vue'],module: {
  rules: [
   {
    test: /\.vue$/,loaders: 'vue-loader',{
    test: /\.js$/,loader: 'babel-loader',exclude: /node_modules/,{
    test: /\.css$/,use: [MiniCssExtractPlugin.loader,'css-loader'],{
    test: /\.scss$/,'css-loader','sass-loader'],{
    test: /\.sass$/,'sass-loader?indentedSyntax'],{
    test: /\.(png|jpg|gif|svg|ico)$/,loader: 'file-loader',options: {
     name: '[name].[ext]?emitFile=false',{
    test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/,loader: 'url-loader',options: {
     esModule: false,limin: 10000,name: "font/[name].[hash:8].[ext]"
    }
   }
  ],plugins: [  
  new VueLoaderPlugin(),new MiniCssExtractPlugin({
   filename: '[name].css',}),new CopyWebpackPlugin([
   { from: 'icons',to: 'icons',ignore: ['icon.xcf'] },{ from: 'popup/popup.html',to: 'popup/popup.html',transform: transformHtml },{
    from: 'manifest.json',to: 'manifest.json',transform: (content) => {
     const jsonContent = JSON.parse(content);
     jsonContent.version = version;

     if (config.mode === 'development') {
      jsonContent['content_security_policy'] = "script-src 'self' 'unsafe-eval'; object-src 'self'";
     }

     return JSON.stringify(jsonContent,null,2);
    },])
 ],};

if (config.mode === 'production') {
 config.plugins = (config.plugins || []).concat([
  new webpack.DefinePlugin({
   'process.env': {
    NODE_ENV: '"production"',]);
}

if (process.env.HMR === 'true') {
 config.plugins = (config.plugins || []).concat([
  new ChromeExtensionReloader(),]);
}

function transformHtml(content) {
 return ejs.render(content.toString(),{
  ...process.env,});
}

module.exports = config;

我們資料改變後,如果想點開外掛就檢視對應介面,這裡就按需引入我們需要的元件,來實現不同的介面展示。

最後附上manifest.json完整的配置

 {
 "name": "外掛","description": "描述","version": 2.0,"manifest_version": 2,"icons": {
  "48": "icons/icon_426.png","128": "icons/icon_426.png"
 },"browser_action": {
  "default_title": "外掛","default_popup": "popup/popup.html"
 },"permissions": [
  "tabs","<all_urls>"
 ],"background": {
  "scripts": ["script/background.js"]
 },"content_scripts": [{
  "js": ["script/contentscript.js"],"https://*/*"
  ]
 }]
}

以上就是vue開發chrome外掛,實現獲取介面資料和儲存到資料庫功能的詳細內容,更多關於vue開發chrome外掛的資料請關注我們其它相關文章!