到現如今最流行的瀏覽器,那么一定是chrome,無論是它的速度,還是它的穩定性,還是它的簡潔,都讓人愛不釋手,此外,更多的人選擇它的理由是它有著豐富的擴展插件,這些擴展插件讓你的瀏覽器變得異常強大,讓你的瀏覽器不僅僅是瀏覽器。
chrome的擴展是以.crx結尾的安裝包,如果你把它下載下來,并把它重命名為.rar壓縮包文件,然后你就可以使用壓縮軟件對它進行解壓,加壓之后,就會發現其實chrome的擴展包里面就是一些js,css,html文件,可以說你只要會寫前端,那么開發一個chrome擴展插件將會非常容易。
在這些文件中,有一個manifest.json文件,它是擴展的描述文件,定義了擴展的名稱和版本號等信息。
{
"name": "BrowserActionExtension",
"version": "0.0.1"
"manifest_version": 2,
"browser_action": {
"default_title": "That's the tool tip",
"default_popup": "popup.html"
}
}
在這個配置文件中,你還可以添加其它屬性,只要你的擴展需要的屬性,你都可以在這里添加配置。
每一個擴展都有一個被瀏覽器運行的背景頁,此外還有事件頁面,背景頁面一直都是激活狀態,而事件頁面只是在觸發事件的時候才會激活,因此為了節省內存和提高瀏覽器的性能,盡可能選擇事件頁面。兩者通過persistent屬性進行區分。
"background": {
"scripts": ["background.js"],
"persistent": false/true
}
當我們的擴展想要訪問瀏覽器當前頁面的dom樹的時候,我們需要使用內容腳本,這些腳本會在頁面刷新的時候執行。
"content_scripts": [
{
"matches": ["https://*/*", "https://*/*"],
"js": ["content.js"]
}
]
對于擴展的UI界面,我們可以通過browser_action屬性進行配置,通過此屬性,我們可以設置擴展的圖標,設置點擊彈出的頁面。
"browser_action": {
"default_icon": {
"19": "icons/19x19.png",
"38": "icons/38x38.png"
},
"default_title": "That's the tool tip",
"default_popup": "popup.html"
}
除了browser_action可以配置擴展圖標之外,page_action可以配置圖標,兩者的區別是,browser_action總是顯示在擴展欄,而page_action則是滿足一定條件才會顯示,比如頁面有vue腳本時候才會顯示vue調試圖標。
"page_action": {
"default_icon": {
"19": "images/icon19.png",
"38": "images/icon38.png"
},
"default_title": "Google Mail",
"default_popup": "popup.html"
}
chrome被開發人員所喜愛的另一個原因是它提供了非常強大的調試工具欄,而我們的擴展也是可以加入到調試工具欄的。
通過使用devtools_page屬性,我們就可以將我們的擴展加入到調試工具欄的一個tab中。
"devtools_page": "devtools.html"
我們在devtools.html中只需要添加一個js引入語句就可以。
<script src="devtools.js"></script>
在devtools.js文件里,我可以可以放入我們實際的擴展內容。
chrome.devtools.panels.create(
"MyExtension",
"img/icon16.png",
"index.html",
function() {
}
);
擴展能夠做什么主要取決于瀏覽器為我們提供了哪些API,慶幸的是,chrome為我們提供了足夠多好用的API。
總之,chrome幾乎為我們提供了完整控制瀏覽器的擴展api,正是有了這些api,才誕生了幾十萬的擴展插件。
在我們本地開發好擴展之后,我們可以通過本地瀏覽器進行調試。
首先,我們需要先進入擴展程序頁面,打開開發者模式
然后,我們可以通過選擇加載已解壓的擴展程序加載我們的擴展。
最后,我們通過在控制臺輸出調試信息來調試我們的擴展。
manifest.json
{
"name": "BrowserExtension",
"version": "0.0.1",
"manifest_version": 2,
"description" : "Description ...",
"icons": { "16": "icons/16x16.png", "48": "icons/48x48.png", "128": "icons/128x128.png" },
"omnibox": { "keyword" : "yeah" },
"browser_action": {
"default_icon": { "19": "icons/19x19.png", "38": "icons/38x38.png" },
"default_title": "That's the tool tip",
"default_popup": "browseraction/popup.html"
},
"background": {
"scripts": ["background.js"],
"persistent": false
},
"chrome_url_overrides" : {
"newtab": "newtab/newtab.html"
},
"content_scripts": [{
"matches": ["http://*/*", "https://*/*"],
"js": ["content.js"]
}],
"devtools_page": "devtools/devtools.html"
}
background.js
// omnibox
chrome.omnibox.onInputChanged.addListener(function(text, suggest) {
suggest([
{content: "color-divs", description: "Make everything red"}
]);
});
chrome.omnibox.onInputEntered.addListener(function(text) {
if(text=="color-divs") colorDivs();
});
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
switch(request.type) {
case "color-divs":
colorDivs();
break;
}
return true;
});
chrome.extension.onConnect.addListener(function (port) {
port.onMessage.addListener(function (message) {
switch(port.name) {
case "color-divs-port":
colorDivs();
break;
}
});
});
// send a message to the content script
var colorDivs=function() {
chrome.tabs.getSelected(null, function(tab){
chrome.tabs.sendMessage(tab.id, {type: "colors-div", color: "#F00"});
// setting a badge
chrome.browserAction.setBadgeText({text: "red!"});
});
}
popup.html
<script type="text/javascript" src="popup.js"></script>
<div style="width:200px">
<button id="button">Color all the divs</button>
</div>
popup.js
window.onload=function() {
document.getElementById("button").onclick=function() {
chrome.extension.sendMessage({
type: "color-divs"
});
}
}
devtools.html
window.onload=function() {
var port=chrome.extension.connect({ name: "color-divs-port" });
document.getElementById("button").onclick=function() {
port.postMessage({ type: "color-divs"});
}
}
content.js
chrome.extension.onMessage.addListener(function(message, sender, sendResponse) {
switch(message.type) {
case "colors-div":
var divs=document.querySelectorAll("div");
if(divs.length===0) {
alert("There are no any divs in the page.");
} else {
for(var i=0; i<divs.length; i++) {
divs[i].style.backgroundColor=message.color;
}
}
break;
}
});
chrome瀏覽器的擴展開發其實并不難,用到的知識都是基礎的js,html,css,我們只需要知道一些和瀏覽器交互的屬性和操作的api,就可以開發出一個屬于自己的瀏覽器擴展。
技術者寫文章,基本少不了Markdown了,但是很多自媒體平臺(大而全那種),往往都是坑爹的富文本編輯器(還很多是魔改UEditor,人家官方三年沒更新了喂)。
小白學邏輯,內行看門道。
類似這種:
這是很麻煩的一件事,尤其是那些沒有代碼塊的編輯器,沒錯,說的就是你,頭條!這種坑爹玩意兒,就得讓程序員手動粘貼代碼過來,然后遇到排版不友好的,呵呵,對,說的還是你,頭條! 于是吧,我就想著,奶奶個熊,沒有我就自己寫個插件來搞吧。
事實上,我自己的網站上有自己依賴marked做的一套編輯器,還挺好用,但是由于圖床問題,還是得每次把富文本粘貼到頭條后,刪除圖片,重新上傳,沒辦法,窮是本命。 咳咳,最后做出來了,但是發現,沒卵用……喵的,Markdown有代碼塊,人家富文本還是不支持啊……總之寫出來分享下方案與思路。
manifest.json 配置
這要是看下content_scripts,這個說是scripts,你也可以看到,是可以塞一些css進去的,不過這里就看js。 util.js主要提供一個編輯時候使用的函數,作用是避免每次編輯觸發input都轉義Markdown2HTML,也就是debounce消抖了。
核心如下(附帶throttle節流):
然后是turndown.js,這個是marked.js的反向。marked是把Markdown2HTML,那么turndown就是把HTML2Markdown了。這種東西當然是輪子了,安全好用(npm)。
至于content/index.js,就是核心頁面插入的js(不是注入inject,這倆有差,這里不細說),就是document有了就運行的函數,一般都是document_start。這個等下結合插件的js說。
這個文件最后就是看popup.html,這個文件名隨意區,作用是點擊插件顯示的那個小窗戶,拿FeHelper看就是這樣的:
看下內容:
常規內容,長這樣:
就一個輸入框和header,沒了,監聽這個輸入框變化。
然后引入js,marked.js就不用說了,popup.js就是這個頁面核心js了,下面細說。
到這里,功能頁面與資源齊全了(不算icon什么的)。
一共上面4個核心問題處理,這個簡易版插件就完成了(雖然沒什么卵用)。
問題1
popup.js
具體都是chrome插件的api,主要看邏輯即可。
問題2,3,4
content/index.js
沒錯,靈魂是哪個alert,YES!
bug是有的,因為我也沒去優化,反正也沒用。而且頭條這富文本標簽挺奇葩的,得去魔改下marked.js才行。
主要是分享下邏輯,以及熟悉下chrome的api。
簡單的知識點搭配合適的業務場景,往往能起到意想不到的效果。這篇文章會用三個最基礎人人都知道的前端知識來說明如何助力運營小姐姐、公司48+前端開發同學的日常工作,讓他們的工作效率得到極大地提升。
看完您可以會收獲
因為接下來的兩個小工具都是基于油猴腳本來實現的,所以我們提前先了解一下它
油猴腳本(Tampermonkey)是一個流行的瀏覽器擴展,可以運行用戶編寫的擴展腳本,來實現各式各樣的功能,比如去廣告、修改樣式、下載視頻等。
1. 安裝油猴
以chrome瀏覽器擴展為例,點擊這里先安裝
安裝完成之后可以看到右上角多了這個
2. 新增示例腳本 hello world
//==UserScript==// @name hello world // 腳本名稱
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match https://juejin.cn/* // 表示怎樣的url才執行下面的代碼
// @icon https://www.google.com/s2/favicons?domain=juejin.cn
// @grant none
//==/UserScript==(function() {
'use strict';
alert('hello world')
// Your code here...
})();
復制代碼
沒錯當打開任意一個https://juejin.cn/*掘金的頁面時,都會彈出hello world,而其他的網頁如https://baidu.com則不會。
到此你就完成了一個最簡單的油猴腳本,接下來我們看一下用同樣簡單的代碼,來解決一個實際問題吧!O(∩_∩)O
1. 有一天運營小姐姐要在幾個系統之間配置點東西
一頓操作,終于把事情搞定了,心情美美的。
但是她心想,為啥每個系統都要我登錄一次,不開心 o( ̄ヘ ̄o#)
2. 下午一覺醒來,領導讓把上午的配置重新改一下(盡職的小姐姐馬上開始操作)
但是讓她沒想到的是:上午的登錄頁面仿佛許久沒有見到她一樣,又和小姐姐來了一次親密接觸
此時,她的內心已經開始崩潰了
3. 但是這不是結束,以后的每一天她都是這種狀態
看完上面的動圖,我猜你已經在替小姐姐一起罵娘了,這做的什么玩意,太垃圾了。SSO是統一登錄,你們這搞的是什么東西。
是的,我的內心和你一樣憤憤不平, 一樣有一萬個草泥馬在奔騰,這是哪個sb設計的方案,簡直不配做人,一天啥事也不干,盡是跳登錄頁,輸入用戶名密碼點登錄按鈕了,久而久之,朋友間見面說的第一句話不是“你吃了嗎?”,而是“你登錄了嗎?”。
不過吐槽完,我們還是要想想如何通過技術手段解決這兩個痛點,達到只需要登錄一次的目的。
1. 在A系統登錄之后,跑到其他系統需要重新登錄。
2. 登錄時效只有2小時,2小時后,需要重新登錄
根本原因還是公司的SSO統一登錄方案設計的有問題,所以需要推動他們修改,但是這是一個相對長期的過程,短期內有沒有什么辦法能讓我們愉快的登錄呢?
痛點1: 1. 在A系統登錄之后,跑到其他系統需要重新登錄。已無力回天
痛點2: 2. 登錄時效只有2小時,2小時后,需要重新登錄已無力回天
我們不好直接侵入各個系統去改造登錄邏輯,改造其登錄時效,但是卻可以對登錄頁面(示例)做點手腳
最關鍵的是:
所以可以借助油猴腳本,在DOMContentLoaded的時候,插入一下代碼,來實現自動登錄,減少手動操作的過程,大概原理如下。
//==UserScript==// @name SSO自動登錄
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match https://*.xxx.com/login* // 這里是SSO登錄頁面地址,表示只有符合這個規則的才注入這段代碼
// @grant none
//==/UserScript==document.querySelector('#username').value='xxx' // 用戶名
document.querySelector('#password').value='yyy' // 密碼
document.querySelector('#login-submit').click() // 自動提交登錄
復制代碼
是不是太簡單了,簡單到令人發指,令人痛恨,令人想吐口水!!!,沒有一點技術含量
是不是太簡單了,簡單到令人發指,令人痛恨,令人想吐口水!!!,沒有一點技術含量
是不是太簡單了,簡單到令人發指,令人痛恨,令人想吐口水!!!,沒有一點技術含量
是的,就這 ,第一次幫小姐姐解決了困擾她許久的問題,晚上就請我吃了麻辣燙,還夸我"技術"好(此處不是開車)
gif中前半部分沒有開啟自動登錄的腳本需要手動登錄,后半部開啟了就可以自動登錄了。
前端常見的調試方式
這些方式都有各自的優缺點,比如chrome inspect第一次需要翻墻才能使用,只適用于安卓; vconsole不方便直接調試樣式; weinre只適用于調試樣式等。
基于這些原因,公司很久之前搞了一個遠程調試工具,可以很方便的增刪DOM結構、調試樣式、查看請求、查看application 修改后手機上立即生效。
遠程調試平臺使用流程
他的使用流程大概是這樣的
看完流程你應該大概知道問題在哪里了, 遠程調試頁面列表不僅僅包含我自己的頁面,還包括很多其他人的,導致很難快速找到自己想要調試的頁面
問題解析
有什么辦法能讓我快速找到自己想要調試的頁面呢?其實觀察解析這個頁面會發現列表是
攔截請求
所以聰明的你已經猜到了,我們可以通過Object.defineProperty攔截fetch請求,過濾設備讓列表中只存在我們指定的設備(畢竟平時開發時調試的設備基本是固定的,而設備完全相同的概率是很低的,所以指定了設備其實就是唯一標識了自己)頁面。
具體如何做呢?
//==UserScript==// @name 前端遠程調試設備過濾
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match https://chii-fe.xxx.com/ // 指定腳本生效的頁面
// @grant none
// @run-at document-start // 注意這里,腳本注入的時機是document-start
//==/UserScript==;(()=> {
const replaceRe=/\s*/g
// 在這里設置設備白名單
const DEVICE_WHITE_LIST=[
'Xiaomi MI 8',
'iPhone9,2',
].map((it)=> it.replace(replaceRe, '').toLowerCase())
const originFetch=window.fetch
const recordListUrl='record-list'
const filterData=(source)=> {
// 數據過濾,返回DEVICE_WHITE_LIST指定的設備的數據
// 詳細過程省略
return data
}
// 攔截fetch請求
Object.defineProperty(window, 'fetch', {
configurable: true,
enumerable: true,
get () {
return function (url, options) {
return originFetch(url, options).then((response)=> {
// 只處理指定的url
if (url.includes(recordListUrl)) {
if (response.clone) {
const cloneRes=response.clone()
return new Promise((resolve, reject)=> {
resolve({
text: ()=> {
return cloneRes.json().then(json=> {
return filterData(JSON.stringify(json))
});
}
})
})
}
}
return response
})
}
}
})
})()
復制代碼
通過下圖可以看出,過濾前有37個頁面,過濾后只剩3個,瞬間就找到你要調試頁面,再也不用從幾百個頁面中尋找你自己的那個啦!
通過插件一鍵設置ua,模擬用戶登錄狀態,提高開發效率。
插件使用方式
插件使用結果
團隊48+小伙伴也使用起來了
日常c端業務中有很多場景都需要用戶登錄后才能正常進行,而開發階段基本都是通過chrome模擬手機設備來開發,所以往往會涉及到在chrome瀏覽器中模擬用戶登錄,其涉及以下三步(這個步驟比較繁瑣)。
備注:保持用戶的登錄態一般是通過cookie,但也有通過header來做,比如我們公司是改寫ua來做的
來看一段對話
隔壁98年剛畢業妹子:
又過期了,誰又把我擠下去了嘛
好的,稍等一會哈,我換個賬號測測
好麻煩哎!模擬一個用戶信息,要這么多步驟,好煩呀!!!
我,好奇的大叔:
“細心”了解下,她正在做一個h5活動項目,場景復雜,涉及的狀態很多,需要用不同的賬號來做測試。
模擬一兩個用戶還好,但是此刻小姐姐測這么多場景,已經模擬了好多個(誰都會煩啊)
公司的登錄體系是單點登錄,一個好不容易模擬的賬號,有可能別人也在用,結果又被頂掉了,得重新生成,我TM
看著她快氣哭的小眼神,作為隔壁桌友好的鄰居,此刻我心里只想著一件事...!幫她解決這個惱人的問題。
通過上面的介紹您應該可以感覺到我們開發階段遇到需要頻繁切換賬號做測試時的煩惱,相對繁瑣的ua生成過程導致了它一定是個費時費力的麻煩事。
有沒有什么辦法讓我們的開發效率得到提升,別浪費在這種事情上呢?一起一步步做起來
需求有哪些
提供一種便捷地模擬ua的方式,助力開發效率提升。
如何解決
為什么是chrome插件
篇幅原因,這里只做示例級別的簡單介紹,如果您希望詳細了解chrome插件的編寫可以參考這里
接下來我們會以下頁面為例,說明用vue如何寫出來。
基本功能
content部分
借助chrome瀏覽器可以向網頁插入腳本的特性,我們會演示如何插入腳本并且在網頁加載的時候彈一個hello world
popup與background通信部分
popup完成用戶的主要交互,在viewA頁面點擊獲取自定義的ua信息
修改ajax請求ua部分
會演示如果通過chrome插件修改請求header
1. manifest.json
幾乎所有的東西都要在這里進行聲明、權限、資源、頁面等等
{
"manifest_version": 2, // 清單文件的版本,這個必須寫
"name": "hello vue extend", // 插件的名稱,等會我們寫的插件名字就叫hello vue extend
"description": "hello vue extend", // 插件描述
"version": "0.0.1", // 插件的版本
// 圖標,寫一個也行
"icons": {
"48": "img/logo.png"
},
// 瀏覽器右上角圖標設置,browser_action、page_action、app必須三選一
"browser_action": {
"default_icon": "img/logo.png",
"default_title": "hello vue extend",
"default_popup": "popup.html"
},
// 一些常駐的后臺JS或后臺頁面
"background": {
"scripts": [
"js/hot-reload.js",
"js/background.js"
]
},
// 需要直接注入頁面的JS
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["js/content.js"],
"run_at": "document_start"
}],
// devtools頁面入口,注意只能指向一個HTML文件
"devtools_page": "devcreate.html",
// Chrome40以前的插件配置頁寫法
"options_page": "options.html",
// 權限申請
"permissions": [
"storage",
"webRequest",
"tabs",
"webRequestBlocking",
"<all_urls>"
]
}
復制代碼
2. background script
后臺,可以認為是一個常駐的頁面,權限很高,幾乎可以調用所有的API,可以與popup、content script等通信
3. content script
chrome插件向頁面注入腳本的一種形式(js和css都可以)
4. popup
popup是點擊browser_action或者page_action圖標時打開的一個小窗口網頁,焦點離開網頁就立即關閉。
比如我們要用vue做的頁面。
manifest.json對文件引用的結構基本決定了打包后的文件路徑
打包后的路徑
// dist目錄用來chrome擴展導入
├── dist
│ ├── favicon.ico
│ ├── img
│ │ └── logo.png
│ ├── js
│ │ ├── background.js
│ │ ├── chunk-vendors.js
│ │ ├── content.js
│ │ ├── hot-reload.js
│ │ └── popup.js
│ ├── manifest.json
│ └── popup.html
復制代碼
源碼目錄
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ └── js
│ └── hot-reload.js
├── src
│ ├── assets
│ │ ├── 01.png
│ │ ├── disabled.png
│ │ └── logo.png
│ ├── background
│ │ └── background.js
│ ├── content
│ │ └── content.js
│ ├── manifest.json
│ ├── popup
│ │ ├── App.vue
│ │ ├── main.js
│ │ ├── router.js
│ │ └── views
│ │ ├── viewA.vue
│ │ ├── viewB.vue
│ │ └── viewC.vue
│ └── utils
│ ├── base.js
│ ├── fixCaton.js
│ └── storage.js
└── vue.config.js
復制代碼
修改vue.config.js
主需要稍微改造變成可以多頁打包,注意輸出的目錄結構就可以了
const CopyWebpackPlugin=require('copy-webpack-plugin')
const path=require('path')
// 這里考慮可以添加多頁
const pagesObj={}
const chromeName=['popup']
const plugins=[
{
from: path.resolve('src/manifest.json'),
to: `${path.resolve('dist')}/manifest.json`
},
{
from: path.resolve('src/assets/logo.png'),
to: `${path.resolve('dist')}/img/logo.png`
},
{
from: path.resolve('src/background/background.js'),
to: `${path.resolve('dist')}/js/background.js`
},
{
from: path.resolve('src/content/content.js'),
to: `${path.resolve('dist')}/js/content.js`
},
]
chromeName.forEach(name=> {
pagesObj[name]={
css: {
loaderOptions: {
less: {
modifyVars: {},
javascriptEnabled: true
}
}
},
entry: `src/${name}/main.js`,
filename: `${name}.html`
}
})
const vueConfig={
lintOnSave:false, //關閉eslint檢查
pages: pagesObj,
configureWebpack: {
entry: {},
output: {
filename: 'js/[name].js'
},
plugins: [new CopyWebpackPlugin(plugins)]
},
filenameHashing: false,
productionSourceMap: false
}
module.exports=vueConfig
復制代碼
我們希望修改插件源代碼進行打包之后,chrome插件對應的頁面能主動更新。為什么叫熱刷新而不是熱更新呢?因為它其實是全局刷新頁面,并不會保存狀態。
這里推薦一個github上的解決方案crx-hotreload
文件目錄結構
├── popup
│ ├── App.vue
│ ├── main.js
│ ├── router.js
│ └── views
│ ├── viewA.vue
│ ├── viewB.vue
│ └── viewC.vue
復制代碼
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip=false
new Vue({
router,
render: h=> h(App)
}).$mount('#app')
復制代碼
router.js
import Vue from 'vue'
import Router from 'vue-router'
import ViewA from './views/viewA.vue'
import ViewB from './views/viewB.vue'
import ViewC from './views/viewC.vue'
Vue.use(Router)
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'home',
redirect: '/view/a'
},
{
path: '/view/a',
name: 'viewA',
component: ViewA,
},
{
path: '/view/b',
name: 'viewB',
component: ViewB,
},
{
path: '/view/c',
name: 'viewC',
component: ViewC,
},
]
})
復制代碼
App.vue
<template>
<div id="app">
<div class="app-router">
<router-view />
</div>
<div class="app-tab">
<div class="app-tab-item" v-for="(tabName, i) in tabs" :key="i" @click="onToView(tabName)">
{{ tabName }}
</div>
</div>
</div>
</template>
<script>
export default {
name: 'App',
data () {
return {
tabs: [
'viewA',
'viewB',
'viewC',
]
}
},
methods: {
onToView (name) {
this.$router.push({
name
})
}
}
}
</script>
<style lang="less">
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
width: 375px;
height: 200px;
padding: 15px;
box-sizing: border-box;
display: flex;
justify-content: space-between;
flex-direction: column;
.app-router{
flex: 1;
}
.app-tab{
display: flex;
align-items: center;
justify-content: space-between;
.app-tab-item{
font-size: 16px;
color: coral;
cursor: pointer;
}
}
}
</style>
復制代碼
viewA、viewB、viewC
三個頁面基本長得是一樣的,只有背景色和文案內容不一樣,這里我就只貼viewA的代碼了。
需要注意的是這里會演示popup與background,通過sendMessage方法獲取background后臺數據
<template>
<div class="view-a">我是A頁面
<button @click="onGetCUstomUa">獲取自定義ua</button>
</div>
</template>
<script>
export default {
name: 'viewA',
methods: {
onGetCUstomUa () {
chrome.runtime.sendMessage({type: 'getCustomUserAgent'}, function(response) {
alert(JSON.stringify(response))
})
}
}
}
</script>
<style lang="less">
.view-a{
background-color: cadetblue;
height: 100%;
font-size: 60px;
}
</style>
復制代碼
background.js
const customUa='hello world ua'
// 請求發送前攔截
const onBeforeSendCallback=(details)=> {
for (var i=0; i < details.requestHeaders.length; ++i) {
if (details.requestHeaders[i].name==='User-Agent') {
details.requestHeaders.splice(i, 1);
break;
}
}
// 修改請求UA為hello world ua
details.requestHeaders.push({
name: 'User-Agent',
value: customUa
});
return { requestHeaders: details.requestHeaders };
}
// 前面的sendMessage獲取getCustomUserAgent,會被這里監聽
const onRuntimeMessageListener=()=> {
chrome.runtime.onMessage.addListener(function (msg, sender, callback) {
if (msg.type==='getCustomUserAgent') {
callback({
customUa
});
}
});
}
const init=()=> {
onRuntimeMessageListener()
onBeforeSendHeadersListener()
}
init()
復制代碼
content.js
演示如何往網頁中插入代碼
function setScript({ code='', needRemove=true }=params) {
let textNode=document.createTextNode(code)
let script=document.createElement('script')
script.appendChild(textNode)
script.remove()
let parentNode=document.head || document.documentElement
parentNode.appendChild(script)
needRemove && parentNode.removeChild(script)
}
setScript({
code: `alert ('hello world')`,
})
復制代碼
大體上和小例子差不都,只是功能相對復雜一些,會涉及到
這里就不貼詳細的代碼實現了。
工作中咱們時長會遇到一些阻礙我們提高工作效率的問題,這些問題或許是因為老方案設計不合理、或許是因為流程又臭又長,又或許是現有功能不滿足新的需求。等等,如果能做到這幾點,不僅對自己的成長有所幫助,對團隊也會有所貢獻。
以上就是這篇文章的全部內容啦!愿大家晚安,下次再見。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。