Chrome插件开发,美化网页上的文件列表。chrome-extension,background

上一篇文章 通过“content-scripts”的方式向页面注入js和css来美化页面,但是有一个弊端:一旦配置好需要注入的页面,之后如果这个页面地址以后发生变化,或者要新加一些URL进来,那么得修改manifest.json这个文件。试想如果一个Chrome插件已经打包好,再去改代码是不可能的。

本文通过另一种方式来实现相同的功能,同时做到页面地址动态可配置。下图是本次要处理的页面:https://jiacrontab.iwannay.cn/download/

Chrome插件开发,美化网页上的文件列表。chrome-extension,background_第1张图片

每一行都是一个文件的基本信息,包括文件名、日期和文件大小,文件名格式统一为:项目名-版本-操作系统-平台(分类要大于等于三个,用 “-” 分隔,这是使用本插件的前提)。现在文件还少,查看不是很困难,如果以后文件多了,那么找一个文件是比较困难的。

这里又不太可能在服务端读取download目录下的文件,然后分类、分页展示,那只能在客户端浏览器上想办法了,Chrome插件可以实现这个功能。

一、小试牛刀

开发Chrome插件第一步,新建一个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"
  },
  "manifest_version": 2
}

name:插件名称

version:版本号

description:插件描述

icons:图标,不同尺寸用于不同地方

browser_action:右上角插件栏的图标信息,包括:图标的图片路径、鼠标划上去提示的文字

manifest_version:固定为2

注:更多manifest.json的配置参考:官方文档  看看现在的项目结构

Chrome插件开发,美化网页上的文件列表。chrome-extension,background_第2张图片

一个简单的没有任何功能的Chrome插件就完成了,去Chrome浏览器里安装下试试:打开Chrome浏览器 - 更多工具 - 扩展程序,打开“开发者模式” - 加载已解压的扩展程序 - 选择src目录 - 确定

Chrome插件开发,美化网页上的文件列表。chrome-extension,background_第3张图片

由图可见,manifest.json里配置的插件名称、版本号、插件描述等信息都体现了

二、加大难度

本插件的目的就是向特定页面注入一些js和css文件,达到美化页面的效果。现在来新建一个配置页面

Chrome插件开发,美化网页上的文件列表。chrome-extension,background_第4张图片

 

把需要美化的页面地址通过配置页面保存到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)里获取“用户访问的页面地址”和“配置页面里面配置的地址”,看看控制台输出

Chrome插件开发,美化网页上的文件列表。chrome-extension,background_第5张图片

 

两个地址都正确的获取到了,如果用户访问的地址和配置的地址吻合,那么向这个页面注入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*)];
            //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('FileList');

        $("[rel='shortcut icon']").attr("href", chrome.extension.getURL("images/16.png"));

        $("body").removeAttr("bgcolor").html('
'); var partAs = getDistinctPartA(); $.each(partAs, function (idx, val) { $("#navbar ul").append("
  • " + val + "
  • "); }); if (partAs.length > 0) { if (localStorage.partA != undefined && $.inArray(localStorage.partA, partAs) != -1) navBarLiClick(localStorage.partA); else navBarLiClick(partAs[0]); } else { $("body").html('

    no data, pls wait and refresh this page :)

    '); } } else { console.log("can't find any line in
     tag");
        }
    }
    else {
        console.log("page's 
     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("
  • all
  • "); 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("
  • " + v + "
  • "); } else { $("#nav ul").append("
  • " + v + "
  • "); } }); 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("FileNameTimeFileSizeOperate"); if (fileList.length > 0) { $.each(fileList, function (i, v) { $("#table").append("" + v.FileName + "" + v.FileTime + "" + v.FileSize + "Link"); }); } else { $("#table").append("
    no data
    "); } $("#table").append(""); }
    View Code

    获取原页面里面的所有文件信息,项目名去重放在顶部,用Bootstrap的navBar插件展示,版本号由上到下依次放在左侧的nav插件上,右侧则用Bootstrap的table展示文件详细信息。效果如下

    Chrome插件开发,美化网页上的文件列表。chrome-extension,background_第6张图片

    至此,分类、翻页展示功能完美实现,以后就算文件再多也可以快速找到了。

    三、总结

    通过“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商店  开发文档

     

    你可能感兴趣的:(Chrome插件开发,美化网页上的文件列表。chrome-extension,background)