上一篇文章 經過「content-scripts」的方式向頁面注入js和css來美化頁面,可是有一個弊端:一旦配置好須要注入的頁面,以後若是這個頁面地址之後發生變化,或者要新加一些URL進來,那麼得修改manifest.json這個文件。試想若是一個Chrome插件已經打包好,再去改代碼是不可能的。javascript
本文經過另外一種方式來實現相同的功能,同時作到頁面地址動態可配置。下圖是本次要處理的頁面:https://jiacrontab.iwannay.cn/download/css
每一行都是一個文件的基本信息,包括文件名、日期和文件大小,文件名格式統一爲:項目名-版本-操做系統-平臺(分類要大於等於三個,用 「-」 分隔,這是使用本插件的前提)。如今文件還少,查看不是很困難,若是之後文件多了,那麼找一個文件是比較困難的。html
這裏又不太可能在服務端讀取download目錄下的文件,而後分類、分頁展現,那隻能在客戶端瀏覽器上想辦法了,Chrome插件能夠實現這個功能。java
開發Chrome插件第一步,新建一個manifest.json文件,並按官方文檔的要求配置一些必要參數node
{ "name": "WebFileFilterPro", "version": "1.0.0", "description": "fast sort your webpage files", "icons": { "16": "images/16.png", "48": "images/48.png", "128": "images/128.png" }, "browser_action": { "default_icon": "images/16.png", "default_title": "WebFileFilterPro" }, "manifest_version": 2 }
name:插件名稱react
version:版本號jquery
description:插件描述git
icons:圖標,不一樣尺寸用於不一樣地方github
browser_action:右上角插件欄的圖標信息,包括:圖標的圖片路徑、鼠標劃上去提示的文字web
manifest_version:固定爲2
注:更多manifest.json的配置參考:官方文檔 看看如今的項目結構
一個簡單的沒有任何功能的Chrome插件就完成了,去Chrome瀏覽器裏安裝下試試:打開Chrome瀏覽器 - 更多工具 - 擴展程序,打開「開發者模式」 - 加載已解壓的擴展程序 - 選擇src目錄 - 肯定
由圖可見,manifest.json裏配置的插件名稱、版本號、插件描述等信息都體現了
本插件的目的就是向特定頁面注入一些js和css文件,達到美化頁面的效果。如今來新建一個配置頁面
把須要美化的頁面地址經過配置頁面保存到Local Storage瀏覽器緩存裏面,這樣作的好處是:須要美化的地址隨時可變,同時發現須要美化的頁面直接加進去就能夠了,不用修改代碼。
這個時候大殺器「background」就要出場了,官方描述是這樣的
Extensions are event based programs used to modify or enhance the Chrome browsing experience. Events are browser triggers, such as navigating to a new page, removing a bookmark, or closing a tab. Extensions monitor these events in their background script, then react with specified instructions.
大體意思是,「background」是常駐Chrome瀏覽器後臺運行的,能夠捕獲到不少行爲:頁面跳轉、移除書籤、關閉一個tab頁等等。這裏不須要那麼強大的功能,只須要獲取用戶打開的頁面地址,是否是在配置頁面配置的地址便可。
如今改下「manifest.json」文件,加入新的配置
{ "name": "WebFileFilterPro", "version": "1.0.0", "description": "fast sort your webpage files", "icons": { "16": "images/16.png", "48": "images/48.png", "128": "images/128.png" }, "browser_action": { "default_icon": "images/16.png", "default_title": "WebFileFilterPro" }, "options_page": "settings.html", "permissions": [ "tabs", "http://*/*", "https://*/*" ], "background": { "scripts": [ "js/background.js" ], "persistent": false }, "manifest_version": 2 }
options_page:配置頁面地址(右鍵右上角插件圖標,能夠經過「選項」進入配置頁面)
background:後臺配置,包括js文件名和持久性設置
permissions:申請權限列表
1)tabs:獲取用戶訪問頁面得URL地址,必須得有tabs權限
2)http/https:向目標頁面裏注入css和js文件須要的權限
注:完整權限api請訪問:Declare Permissions
如今來看下官方說的能夠常駐後臺運行的「background.js」到底能夠獲取到哪些東西
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { if (changeInfo.status == "complete") { var url = tab.url; console.log("用戶訪問:" + url); console.log("緩存裏設置的頁面:" + localStorage.url); }; });
在頁面首次打開或者刷新事件(onUpdated)裏獲取「用戶訪問的頁面地址」和「配置頁面裏面配置的地址」,看看控制檯輸出
兩個地址都正確的獲取到了,若是用戶訪問的地址和配置的地址吻合,那麼向這個頁面注入css和js文件
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) { if (changeInfo.status == "complete") { var url = tab.url; console.log(url); if (localStorage.url != undefined && localStorage.url != '') { var urlList = localStorage.url.split("\n"); if (urlList.indexOf(url) != -1) { chrome.tabs.insertCSS(tabId, { file: "css/bootstrap.min.css" }); chrome.tabs.executeScript(tabId, { file: "js/jquery.min.js" }); chrome.tabs.executeScript(tabId, { file: "js/bootstrap.min.js" }); chrome.tabs.executeScript(tabId, { file: "js/filelist.js" }); } } }; });
使用「chrome.tabs.insertCSS」和「chrome.tabs.executeScript」這兩個api完成css和js的注入。有了jQuery和Bootstrap的注入,頁面就能夠隨意美化了。「filelist.js"代碼以下
//console.log("filelist.js"); var fileList = []; var preList = document.getElementsByTagName("pre"); if (preList.length == 1) { var lineList = preList[0].innerHTML.split("\n"); //console.log(lineList); if (lineList.length > 0) { var splitLinetext = []; var splitFileName = []; var fileName = ''; $.each(lineList, function (i, v) { //console.log(v); if (i == 0) { return true;//continue; } if (v == undefined || v == "") { var line = parseInt(i); line += 1; console.log("line:" + line + " is empty"); return true; } splitLinetext = v.split(/\s+/); if (splitLinetext.length != 5) { console.log(splitLinetext); return true; } fileName = splitLinetext[1].match(/>(\S*)</)[1]; //console.log(fileName); if (fileName == null || fileName == '') { console.log("fileName is or empty"); return true; } splitFileName = fileName.split('-'); if (splitFileName.length < 3) { console.log(splitFileName); return true; } fileList.push({ PartA: splitFileName[0], PartB: splitFileName[1], FileTime: formatDate(splitLinetext[2] + ' ' + splitLinetext[3]), FileSize: splitLinetext[4], FileName: fileName }); }); //console.log(fileList); var nodeDoctype = document.implementation.createDocumentType('html', '', ''); if (document.doctype) { document.replaceChild(nodeDoctype, document.doctype); } else { document.insertBefore(nodeDoctype, document.childNodes[0]); } $("html").attr("lang", "en"); $("head").html('<head><meta charset="UTF-8"><link rel="shortcut icon" href="" /><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>FileList</title></head>'); $("[rel='shortcut icon']").attr("href", chrome.extension.getURL("images/16.png")); $("body").removeAttr("bgcolor").html('<nav class="navbar navbar-default navbar-static-top"><div class="container"><div class="row"><div class="col-sm-2 col-md-2 col-lg-2"></div><div class="col-sm-10 col-md-10 col-lg-10"><div class="navbar-header"><button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"><span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span></button></div><div id="navbar" class="collapse navbar-collapse"><ul class="nav navbar-nav"></ul></div></div></div></div></nav><div class="container"><div class="row"><div id="nav" class="col-sm-2 col-md-2 col-lg-2"><ul class="nav nav-pills nav-stacked"></ul></div><div class="col-sm-10 col-md-10 col-lg-10"><table id="table" class="table table-bordered"></table><ul class="pager"><span id="pageIndexSpan"></span> / <span id="pageSizeSpan"></span> / <span id="totalCountSpan"></span> <li id="previousPageLi"><a href="javascript:;">Prev</a></li> <li id="nextPageLi"><a href="javascript:;">Next</a></li></ul></div></div></div>'); var partAs = getDistinctPartA(); $.each(partAs, function (idx, val) { $("#navbar ul").append("<li data-value=\"" + val + "\"><a href='javascript:;'><strong>" + val + "</strong></a></li>"); }); if (partAs.length > 0) { if (localStorage.partA != undefined && $.inArray(localStorage.partA, partAs) != -1) navBarLiClick(localStorage.partA); else navBarLiClick(partAs[0]); } else { $("body").html('<div class="container"><div class="row"><div class="col-sm-12 col-md-12 col-lg-12"><h3>no data, pls wait and refresh this page :)</h3></div></div></div>'); } } else { console.log("can't find any line in <pre> tag"); } } else { console.log("page's <pre> tag count illegal:" + preList.length); } $("body").on("click", "#navbar ul li", function () { navBarLiClick($(this).attr("data-value")); }); $("body").on("click", "#nav ul li", function () { navLiClick($(this).attr("data-parta"), $(this).attr("data-partb")); }); $("body").on("click", "#table tbody tr", function () { $(this).css("background", "#DCDCDC").siblings().css("background", ""); }); $("body").on("click", "#previousPageLi", function () { if (localStorage.pageIndex != 1) { localStorage.pageIndex = parseInt(localStorage.pageIndex) - 1; initFileList(localStorage.partA, localStorage.partB); } }); $("body").on("click", "#nextPageLi", function () { var totalPageCount = localStorage.totalCount % localStorage.pageSize == 0 ? localStorage.totalCount / localStorage.pageSize : Math.ceil(localStorage.totalCount / localStorage.pageSize); if (localStorage.pageIndex != totalPageCount) { localStorage.pageIndex = parseInt(localStorage.pageIndex) + 1; initFileList(localStorage.partA, localStorage.partB); } }); function formatDate(dt) { var date = new Date(dt); var aaaa = date.getFullYear(); var gg = date.getDate(); var mm = (date.getMonth() + 1); if (gg < 10) gg = "0" + gg; if (mm < 10) mm = "0" + mm; var cur_day = aaaa + "-" + mm + "-" + gg; var hours = date.getHours() var minutes = date.getMinutes() //var seconds = date.getSeconds(); if (hours < 10) hours = "0" + hours; if (minutes < 10) minutes = "0" + minutes; //if (seconds < 10) seconds = "0" + seconds; //return cur_day + " " + hours + ":" + minutes + ":" + seconds; return cur_day + " " + hours + ":" + minutes; } function getDistinctPartA() { return JSLINQ(fileList).Distinct(function () { return this.PartA; }).items; } function getDistinctPartB(partA) { return JSLINQ(fileList).Where(function () { return this.PartA == partA; }).Distinct(function () { return this.PartB; }).items; } function getFileListPage(partA, partB) { var totalPageCount = localStorage.totalCount % localStorage.pageSize == 0 ? localStorage.totalCount / localStorage.pageSize : Math.ceil(localStorage.totalCount / localStorage.pageSize); if (localStorage.pageIndex == 1) { $("#previousPageLi").addClass("disabled"); } else { $("#previousPageLi").removeClass("disabled"); } if (localStorage.pageIndex == totalPageCount) { $("#nextPageLi").addClass("disabled"); } else { $("#nextPageLi").removeClass("disabled"); } $("#pageIndexSpan").text(localStorage.pageIndex); $("#pageSizeSpan").text(localStorage.pageSize); $("#totalCountSpan").text(localStorage.totalCount); if (partB == 'all') { return JSLINQ(fileList).Reverse().Where(function () { return this.PartA == partA; }).Skip(parseInt(localStorage.pageSize) * (parseInt(localStorage.pageIndex) - 1)).Take(parseInt(localStorage.pageSize)).Select("PartB,FileTime,FileSize,FileName").items; } else { return JSLINQ(fileList).Reverse().Where(function () { return this.PartA == partA && this.PartB == partB; }).Skip(parseInt(localStorage.pageSize) * (parseInt(localStorage.pageIndex) - 1)).Take(parseInt(localStorage.pageSize)).Select("PartB,FileTime,FileSize,FileName").items; } } function getFileListTotalCount(partA, partB) { if (partB == 'all') { return JSLINQ(fileList).Count(function () { return this.PartA == partA; }); } else { return JSLINQ(fileList).Count(function () { return this.PartA == partA && this.PartB == partB; }); } } function navBarLiClick(partA) { $("#navbar ul li[data-value=\"" + partA + "\"]").addClass("active").siblings().removeClass("active"); $("#nav ul").empty(); $("#nav ul").append("<li data-parta=\"" + partA + "\" data-partb=\"all\"><a href='javascript:;'>all</a></li>"); var partB = ''; var list = getDistinctPartB(partA); //list.sort(); list.reverse(); $.each(list, function (i, v) { if (localStorage.partB != undefined && localStorage.partA != undefined && localStorage.partA == partA && localStorage.partB == v) { partB = localStorage.partB; $("#nav ul").append("<li class='active' data-parta=\"" + partA + "\" data-partb=\"" + v + "\"><a href='javascript:;'>" + v + "</a></li>"); } else { $("#nav ul").append("<li data-parta=\"" + partA + "\" data-partb=\"" + v + "\"><a href='javascript:;'>" + v + "</a></li>"); } }); if (partB == '') { partB = 'all'; $("#nav ul li:first").addClass("active"); } initFileList(partA, partB); } function navLiClick(partA, partB) { $("#nav ul li[data-partb=\"" + partB + "\"]").addClass("active").siblings().removeClass("active"); initFileList(partA, partB); } function initFileList(partA, partB) { if (localStorage.partA != partA || localStorage.partB != partB) { localStorage.pageIndex = 1; localStorage.pageSize = 10; } if (localStorage.partA != partA) { localStorage.partA = partA; } if (localStorage.partB != partB) { localStorage.partB = partB; } var totalCount = getFileListTotalCount(partA, partB); if (localStorage.totalCount != totalCount) { localStorage.totalCount = totalCount; } var fileList = getFileListPage(partA, partB); $("#table").empty(); // $("#table").append("<thead><tr><th>FileName</th><th>Time</th><th>FileSize</th><th>Operate</th></tr></thead><tbody>"); if (fileList.length > 0) { $.each(fileList, function (i, v) { $("#table").append("<tr><td>" + v.FileName + "</td><td>" + v.FileTime + "</td><td>" + v.FileSize + "</td><td><a href='" + v.FileName + "' target='_blank'>Link</a></td></tr>"); }); } else { $("#table").append("<tr><td colspan='4'><center>no data</center></td></tr>"); } $("#table").append("</tbody>"); }
獲取原頁面裏面的全部文件信息,項目名去重放在頂部,用Bootstrap的navBar插件展現,版本號由上到下依次放在左側的nav插件上,右側則用Bootstrap的table展現文件詳細信息。效果以下
至此,分類、翻頁展現功能完美實現,之後就算文件再多也能夠快速找到了。
經過「background」的方式注入,優勢是頁面隨時能夠配置,很方便,缺點是用戶訪問的每一個頁面都須要在「background.js」裏面挨個過濾,感受效率不行。我的仍是比較喜歡「content_scripts」這種方式注入。
Chrome插件本地源碼路徑,方便學習其餘優秀插件的代碼:
1)windows xp:C:\Documents and Settings\用戶名\Local Settings\Application Data\Google\Chrome\User Data\Default\Extensions
2)windows xp+:C:\Users\用戶名\AppData\Local\Google\Chrome\User Data\Default\Extensions
3)MAC:~/Library/Application Support/Google/Chrome/Default/Extensions
4)Ubuntu:~/.config/google-chrome/Default/Extensions
Chrome插件開發有不少的api,功能很是強大。這裏僅拋磚引玉,更多使用場景你們本身去發揮。源碼地址 Chrome商店 開發文檔