likes
comments
collection
share

如何开发一款方便快速查询数据的Google浏览器插件

作者站长头像
站长
· 阅读数 17
前言

事情是这样的,有一天我正在上班,突然有一天,领导前来买瓜,问我:“小赵啊,你这瓜保熟吗?” 我一猜就知道,突然找我肯定是没有啥好事

如何开发一款方便快速查询数据的Google浏览器插件 如何开发一款方便快速查询数据的Google浏览器插件

插件:Gitee地址 仓库中的Stdio项目为本文实例插件 (建议根据实例代码进行阅读)

分析

  1. 领导的想法是不想手动去复制Excel中的(姓名、身份证号)等用户信息,想让它们自动填充到输入框中,领导只需要点击查询和滑动验证就行
  2. 查询出结果后,要根据用户查询出来的状态进行标注,最后进行导出

构思

经过深思熟虑以后,我决定使用Google插件来实现这一个功能 整体的界面设计为如下 如何开发一款方便快速查询数据的Google浏览器插件

页面有一个table数据表格,用来展示Excel表格中的需要查询的一户数据,其中包括姓名、身份证号、标注状态、以及当前的学生索引位置等等(效果图如下)

如何开发一款方便快速查询数据的Google浏览器插件

开发准备

既然需要用到Google插件,那就需要对Google插件开发有一定的了解,下面我就简单的介绍一下本次案例用到的Google插件的一些功能和API(Google提供了很多API供我们选择,想了解更多可以去官网进行学习和使用)

Google插件开发模块介绍

Google插件开发主要分三个模块组成, 分别为 backgroundpopup以及content模块,这三个模块是相对独立的模块,他们不仅有不同的调试方式,还遵循着不同的通讯协议

background

background顾名思义就是后台模块,这个模块是用户看不见的模块,一般在此模块内进行处理数据,后台模块可以访问绝大部分Google提供的API,不能操作页面上的DOM元素,因为模块都是独立的,后台模块触碰不到DOM

popup

popup顾名思义就是弹出层模块,当然这个模块并不是依赖于DOM元素的弹出层,而是依赖于Chrome中的拓展程序中的插件,点击插件时弹出的模块,效果如图下 如何开发一款方便快速查询数据的Google浏览器插件

当然popup模块也是独立的,虽然用户看得见但是他不能够访问渲染页面上的DOM元素

content

content模块就是内容模块了,在这个模块里,可以随意操作DOM元素,对DOM元素进行控制、添加、删除或者修改,案例中插入了两个模块(按钮盒子、table表)到页面上,实际上就是在content中使用了DOM添加操作方法

介绍完以上三个模块以后,现在可能会有一些疑问,那既然这三个模块他们都是相对独立的,当在background后台模块或者popup弹出层模块获取到异步数据以后,怎么让他动态加载到页面DOM中去呢?

答案:因为backgroundpopup是不具备操作DOM的功能的,所以没有办法直接添加。这个时候,就需要用到content模块来进行加载到DOM中去。

那么这样就会有一个新的问题,就是怎么将background后台模块或者popup弹出层模块获取到的异步数据传递给background模块呢?

其实很简单,Google提供了一些API,便于backgroundpopupcontent之间进行通讯。

Google 模块之间的通讯

前面讲述了,既然每个模块都是独立的且每个模块的权限各不相同,那么各个模块之间的通讯也会有一些细微的差别,下面就来详细的讲解一下

在进入正式编写代码插件之前,可以暂时将backgroundpopupcontent理解为三个在不同地方执行的js文件

如何开发一款方便快速查询数据的Google浏览器插件

popup 通讯 background

方法一:使用长连接 popup.js

// 使用长连接 name 一定是唯一的
let port = chrome.runtime.connect({ name: 'popup-name' });

port.onMessage.addListener(function (message) {
    // 处理从 background 发来的消息
    console.log('background 发来了消息:', message);
});

// 发送消息给 background
port.postMessage('Hi~background, 我是popup');

background.js

let port = null;
// 监听Connect长连接
chrome.runtime.onConnect.addListener(function (externalPort) {
    // 监听连接name
    if (externalPort.name === 'popup-name') {
        port = externalPort;
        // 连接监听
        port.onMessage.addListener(function (message) {
            // 接收 popup 发来的消息
            console.log('popup 发来了消息:', message);
            // 接收到消息以后 发送响应消息给 popup
            port.postMessage('Hi~popup');
        });
    }
});

点击popup弹窗后,即可进行通信,出现以下状况,即可表示通信成功 如何开发一款方便快速查询数据的Google浏览器插件 方法二:API popup.js

// 向后台脚本发送消息
function sendMessageToBackground(message) {
  chrome.runtime.sendMessage(message);
}

// 监听来自后台脚本的消息
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
  console.log('Message from background:', message);
  // 这里可以进行处理或者发送响应消息给后台脚本
});

// 发送消息给后台脚本
sendMessageToBackground('Hello from popup!');

background.js

// 向 popup 发送消息
function sendMessageToPopup(message) {
  chrome.runtime.sendMessage(message);
}

// 监听来自 popup 的消息
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
  console.log('Message from popup:', message);
  // 这里可以进行处理或者发送响应消息给 popup
});

// 监听插件的安装事件
chrome.runtime.onInstalled.addListener(function(details) {
  // 发送消息给 popup
  sendMessageToPopup('Hello from background!');
});

popup 通讯 content

popup.js

// 向 content script 发送消息
function sendMessageToContentScript(message) {
  chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
    chrome.tabs.sendMessage(tabs[0].id, message);
  });
}

// 监听来自 content script 的消息
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
  console.log('Message from content script:', message);
  // 这里可以进行处理或者发送响应消息给 content script
});

// 发送消息给 content script
sendMessageToContentScript('Hello from popup!');

content.js

// 向 popup 发送消息
function sendMessageToPopup(message) {
  chrome.runtime.sendMessage(message);
}

// 监听来自 popup 的消息
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
  console.log('Message from popup:', message);
  // 这里可以进行处理或者发送响应消息给 popup
  sendMessageToPopup('Hello from content script!');
});

content 通讯 background

content.js

// 向后台脚本发送消息
function sendMessageToBackground(message) {
  chrome.runtime.sendMessage(message);
}

// 监听来自后台脚本的消息
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
  console.log('Message from background:', message);
  // 这里可以进行处理或者发送响应消息给后台脚本
});

// 发送消息给后台脚本
sendMessageToBackground('Hello from content script!');

background.js

// 向内容脚本发送消息
function sendMessageToContentScript(tabId, message) {
  chrome.tabs.sendMessage(tabId, message);
}

// 监听来自内容脚本的消息
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
  console.log('Message from content script:', message);
  // 这里可以进行处理或者发送响应消息给内容脚本
});

// 监听标签页的切换
chrome.tabs.onActivated.addListener(function(activeInfo) {
  // 获取当前活动标签页的信息
  chrome.tabs.get(activeInfo.tabId, function(tab) {
    // 发送消息给当前活动标签页的内容脚本
    sendMessageToContentScript(tab.id, 'Hello from background!');
  });
});

至此,常用模块的基本通讯方法已经介绍完了,下面就开始一步一步的去开发一个Google插件吧

创建项目

如何开发一款方便快速查询数据的Google浏览器插件

首先我们来看一下,配置文件

manifest.json 文件

{
    "name": "快速查询成绩",
    "manifest_version": 2,
    "version": "1.0.0",
    "description": "查询成绩插件1.0版本",
    "icons": {
        "16": "img/lookup.png",
        "48": "img/lookup.png",
        "128": "img/lookup.png"
    },
    "browser_action": {
        "default_icon": "img/lookup.png",
        "default_title": "成绩查询",
        "default_popup": "html/popup.html"
    },
    "background": {
        "scripts": [
            "js/background.js",
            "js/popup.js"
        ],
        "persistent": false
    },
    "content_scripts": [
        {
            "js": [
                "js/content.js",
                "js/contentMessaging.js",
                "js/contentHttp.js"
            ],
            "css": [
                "css/contentAllStyleContent.css",
                "css/bootstrap.css"
            ],
            "matches": [
                "http://*.zscx.osta.org.cn/"
            ]
        }
    ],
    "permissions": [
        "<all_urls>",
        "tabs",
        "storage",
        "bookmarks",
        "*://*/*",
        "http://*/*",
        "https://*/*"
    ]
}

manifest.json 是 Chrome 插件的清单文件,它描述了插件的元数据、功能和权限。它告诉 Chrome 浏览器如何加载和运行插件。以下是一些常见的参数及其用途:

  1. "manifest_version":指定插件清单文件的版本号,当前版本为 2。
  2. "name":插件的名称,将显示在 Chrome 浏览器的插件管理器中。
  3. "version":插件的版本号。
  4. "description":插件的描述信息,将显示在插件管理器中。
  5. "icons":定义插件在不同位置和尺寸的图标。
  6. "background":指定插件的后台脚本文件。
  7. "browser_action":定义插件的浏览器动作,通常是点击插件图标后弹出的浮窗。
  8. "page_action":定义插件的页面动作,可以在特定页面上显示插件图标和浮窗。
  9. "content_scripts":定义插件的内容脚本,用于向页面注入脚本或样式。
  10. "permissions":声明插件需要的权限,如访问特定网站、读取浏览历史等。
  11. "background":指定插件的后台脚本文件。

接着让我们一步一步的来分析这个配置文件的作用: browser_action配置项

"browser_action": {
        "default_icon": "img/lookup.png",
        "default_title": "成绩查询",
        "default_popup": "html/popup.html"
 },

根据配置我们可以看出,这一个配置文件,主要是配置popup弹出层, 弹出层内容信息为如下:

html/popup.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="../css/popup.css">
    <link rel="stylesheet" href="../css/bootstrap.css">
    <title>Document</title>
</head>


    <input id="uploadExcel" type="file" hidden>
    <div class="panels">
        <ul class="list-group">
            <li class="list-group-item" id="uploadExcelBtn">
                <img src="转存失败,建议直接上传图片文件 ../img/Upload.png" alt="转存失败,建议直接上传图片文件">
                上传信息表
            </li>
            <li class="list-group-item">
                <a href="../检索查询模板.xlsx">
                    <img src="转存失败,建议直接上传图片文件 ../img/Download.png" alt="转存失败,建议直接上传图片文件">
                    下载信息表模板
                </a>
            </li>
        </ul>
    </div>
    <script src="../js/xlsx.core.min.js"></script>
    <script src="../js/popup.js"></script>


</html>

正是我们点击右侧的图标,弹出的模板信息内容

如何开发一款方便快速查询数据的Google浏览器插件

我们在页面中,引入了脚本popup.jsxlsx操作excel表格的数据文件 其中popup.js脚本就是我们用于通讯的弹出层模块

background配置项

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

"background" 参数主要是指定了插件的后台脚本是谁,代码中指定了脚本文件为 "js/background.js",表示background.js就是运行在后台模块中的脚本文件,可以在这个文件内实现与其他模块的通信监听等逻辑

content_scripts配置项

 "content_scripts": [
        {
            "js": [
                "js/content.js"
            ],
            "css": [
                "css/contentAllStyleContent.css",
                "css/bootstrap.css"
            ],
            "matches": [
                "http://*.zscx.osta.org.cn/"
            ]
        }
    ],

顾名思义,这个配置项就是配置content模块的,上面我们说了,content模块是可以直接操作DOM元素的,所以可以定义一些Css样式来美化创建在页面上的DOM元素,以及定义一些脚本文件绑定到元素上,并且和其他模块进行通讯

matches就是匹配插件在那些网站下执行脚本,我这里使用了zscx.osta.org.cn/ 这个网站,所以我定义了如下配置

 "matches": [
    "http://*.zscx.osta.org.cn/"
 ]

可以根据自行修改

例如:如果想修改为只有打开掘金网站的时候启用插件可以配置为 https://*.juejin.cn/

popup.js

上述代码中,展示了popup.html页面,并且引入了一个popup.js的脚本文件用作popup的通讯脚本文件

如何开发一款方便快速查询数据的Google浏览器插件

这里我定义了两个按钮,一个是上传信息表,一个是下载信息表模板, 这样做的目的是为了定义一个标准,避免随便上传造成的解析出错

popup.js

window.onload = function () {
    // 点击上传
    const UplaodBtn = getDomById('uploadExcelBtn')
    // console.log('UplaodBtn ===> ', UplaodBtn)
    // 监听点击上传
    UplaodBtn.addEventListener('click', uploadExcelBtn)

    // 监听选择完文件
    const uploadExcelSuccess = getDomById('uploadExcel')
    uploadExcelSuccess.addEventListener('change', function (event) {
        const selectedFile = event.target.files[0];
        console.log('selectedFile ====> ', selectedFile)
        if (selectedFile) {
            // 文件已选择
            readWorkbookFromLocalFile(selectedFile, (data) => {
                const worksheet = data.Sheets[data.SheetNames[0]];
                const jsonData = window.XLSX.utils.sheet_to_json(worksheet, { header: 1 });
                console.log('jsonData ===> ', jsonData)
                // 处理json数据后 交互给页面
                formatingData(jsonData)
            })
            // 在这里可以执行你需要的操作,如上传文件等
        }
    });
}

// 点击上传文件按钮
function uploadExcelBtn() {
    const Upload = getDomById('uploadExcel')
    // 手动触发上传
    Upload.click()
}
// 
function getDomById(id) {
    return document.getElementById(id)
}

// 读取本地excel文件
function readWorkbookFromLocalFile(file, callback) {
    var reader = new FileReader();
    reader.onload = function (e) {
        var data = e.target.result;
        var workbook = window.XLSX.read(data, { type: 'binary' });
        if (callback) callback(workbook);
    };
    reader.readAsBinaryString(file);
}

// 处理数据
function formatingData(dataSource) {
    var header = dataSource[0];
    var result = [];

    for (var i = 1; i < dataSource.length; i++) {
        if (dataSource[i].length === 0) {
            continue; // 跳过空数组
        }
        var obj = {};
        for (var j = 0; j < header.length; j++) {
            var value = dataSource[i][j] || '';
            obj[header[j]] = value;
        }
        result.push(obj);
    }

    // Excel数据处理好了,通信给页面 result
    toContent(result)
}

function toContent(dresult) {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
        let message = { info: '来自popup的信息', dresult }
        chrome.tabs.sendMessage(tabs[0].id, message, res => {
            console.log('popup=>content')
            console.log(res)
        })
    })
}

因为在popup.html引用了XLSX处理Excel的第三方插件,所以直接使用window.XLSX来进行解析文件

当点击触发上传信息表按钮时,会执行uploadExcelBtn方法,打开文件选择器, 当文件选择完毕后,会被uploadExcelSuccess.addEventListener('change',xxx)监听到,进而执行解析Excel文件的readWorkbookFromLocalFile方法,数据解析完成后,如下图所示

如何开发一款方便快速查询数据的Google浏览器插件

此时还需要对数据进行进一步处理

// 处理数据
function formatingData(dataSource) {
    var header = dataSource[0];
    var result = [];

    for (var i = 1; i < dataSource.length; i++) {
        if (dataSource[i].length === 0) {
            continue; // 跳过空数组
        }
        var obj = {};
        for (var j = 0; j < header.length; j++) {
            var value = dataSource[i][j] || '';
            obj[header[j]] = value;
        }
        result.push(obj);
    }

    // Excel数据处理好了,通信给页面 result
    toContent(result)
}

function toContent(dresult) {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
        let message = { info: '来自popup的信息', dresult }
        chrome.tabs.sendMessage(tabs[0].id, message, res => {
            console.log('popup=>content')
            console.log(res)
        })
    })
}

首先通过formatingData方法,对数据进行转换,转换以后通过模块通讯将数据传递给content来渲染试图 \

解析后的数据为如下 如何开发一款方便快速查询数据的Google浏览器插件

content.js

popup.js中,将数据通过chrome.tabs.sendMessageAPI通讯方式传递给了content.js,那么就需要在content.js注册监听事件chrome.runtime.onMessage.addListener来接受通讯传递的数据

// 姓名
const Names = []
// 身份证号
const IDcards = []
// 初始数据对象
const UserObj = {}
// 监听导入的数据
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
    // console.log('message ===> ', message)
    for (const item of message.dresult) {
        const sfzh = '身份证号'
        const xm = '姓名'
        const remark = '备注'
        // 存储数据
        UserObj[item[sfzh]] = { sfzh: item[sfzh], xm: item[xm], remark: item[remark] }
        // 存储姓名和身份证号
        Names.push(item[xm])
        IDcards.push(item[sfzh])
    }
    // 数据面板
    initPanel()
    // 导入数据后,初始化
    initTable()
    // 同步面板
    syncPanelActive()
})

以上代码中,声明了三个变量,来分别存储和记录数据:姓名、身份证号以及对象形式的存储(根据身份证号为key的键值对存放数据,方便记录用户信息)

// 姓名
const Names = []
// 身份证号
const IDcards = []
// 初始数据对象
const UserObj = {}

如何开发一款方便快速查询数据的Google浏览器插件

现在就已经获取到了数据,就可以开始渲染DOM元素了

createRoot 生成底部按钮:上一个、下一个、查询、标记、导出等

function createRoot() {
    const Dom = document.getElementsByTagName('body')[0]
    const Button1 = cDom({
        domName: 'button',
        id: "last",
        textContent: '上一个',
        className: 'cDombtn btn btn-primary',
    })

    const Button2 = cDom({
        domName: 'button',
        id: "next",
        textContent: '下一个',
        className: 'cDombtn btn btn-primary',
    })
    // 查询
    const Button3 = cDom({
        domName: 'button',
        id: "query",
        textContent: '查询国家资格证书',
        className: 'cDombtn btn btn-success'
    })
    const Button6 = cDom({
        domName: 'button',
        id: "queryZydj",
        textContent: '查询职业技能等级证书',
        className: 'cDombtn btn btn-success'
    })

    // 标记该学生
    const Button4 = cDom({
        domName: 'button',
        id: "sign",
        textContent: '标记通过',
        className: 'cDombtn btn btn-success'
    })
    const Button5 = cDom({
        domName: 'button',
        id: "signLook",
        textContent: '取消标记',
        className: 'cDombtn btn btn-danger'
    })
    const Button7 = cDom({
        domName: 'button',
        id: "exportExcel",
        textContent: '标记文档导出',
        className: 'cDombtn btn btn-success'
    })

    // 父盒子
    const parentBox = cDom({
        domName: 'div',
        id: "parentBox",
    })
    // 按钮盒子
    const btnBox = cDom({
        domName: 'div',
        id: "btnBox",
    })

    const addEvent = {
        last: LastLook,
        next: NextLook,
        query: queryFun,
        queryZydj: queryZydjFun,
        sign: signFun,
        signLook: signLookFun,
        exportExcel: exportExcelFun
    }
    const Doms = [Button1, Button2, Button3, Button6, Button4, Button5, Button7]

    Doms.map((v, i) => {
        console.log('v.id ===> ', v.id)
        v.addEventListener('click', addEvent[v.id])
    })

    btnBox.prepend(...Doms)
    parentBox.prepend(btnBox)
    Dom.prepend(parentBox)
    // 初始化标记
    // initTable()
}

initPanel 生成数据展示面板

function initPanel() {
    const Dom = document.getElementsByTagName('body')[0]
    var table = document.createElement('table');
    table.id = 'table23Excel'
    var tbody = document.createElement('tbody');
    table.appendChild(tbody);
    // 表头
    var rowTh = document.createElement('tr');
    var nameCell = document.createElement('td');
    nameCell.classList = 'table_xm'
    nameCell.textContent = '姓名';
    rowTh.appendChild(nameCell);
    var sfzhCell = document.createElement('td');
    sfzhCell.classList = 'table_sfzh'
    sfzhCell.textContent = '身份证号';
    rowTh.appendChild(sfzhCell);
    var remarkCell = document.createElement('td');
    remarkCell.classList = 'table_remark'
    remarkCell.textContent = '备注';
    rowTh.appendChild(remarkCell);
    tbody.appendChild(rowTh);
    // 表单内容
    for (const liItem in UserObj) {
        const data = UserObj[liItem]
        var row = document.createElement('tr');
        row.classList = 'rowTrAll'
        var nameCell = document.createElement('td');
        nameCell.textContent = data.xm;
        row.appendChild(nameCell);
        var sfzhCell = document.createElement('td');
        sfzhCell.textContent = data.sfzh;
        row.appendChild(sfzhCell);
        var remarkCell = document.createElement('td');
        remarkCell.textContent = data.remark;
        remarkCell.classList = 'remarkCell'
        row.appendChild(remarkCell);
        tbody.appendChild(row);
    }
    Dom.prepend(table)
}

initTable 初始化数据,将数据动态添加到表单输入框中

function initTable() {
    // 查询国家级别
    const Index = getIndex()
    const CID = getDom("CID")
    const Name = getDom("Name")
    Name.html(Names[Index])
    CID.html(IDcards[Index])

    // 职业技能级别
    const D = document.getElementById('search_box')
    const inputArr = D.getElementsByTagName('input')
    inputArr[1].value = IDcards[Index]
    inputArr[2].value = Names[Index]
}

syncPanelActive 同步面板选择 在初始状态或者切换上一位、下一位的时候,同步右侧面板的选中状态,当然,为了保证选中的数据始终出现在视图中,我们需要判断,如果选中的数据的位置超出了可视区域,就让其滚动到盒子顶部,让选中的数据始终出现在视图中,实现方法为scrollView

function syncPanelActive() {
    // rowTrAll
    const rowTrAll = document.querySelectorAll('.rowTrAll')
    const index = getIndex()
    if (index >= 0 && index < rowTrAll.length) {
        for (var i = 0; i < rowTrAll.length; i++) {
            if (i === index) {
                rowTrAll[i].classList.add('rowActive');
                // 滚动元素到视图范围内的顶部
                scrollView(rowTrAll[i])
            } else {
                rowTrAll[i].classList.remove('rowActive');
            }
        }
    }
}

监测数据滚动

// 滚动到可视化范围内
function scrollView(Dom) {
    // 判断元素是否在可视化范围内
    var rect = Dom.getBoundingClientRect();
    const panelBox = document.getElementById('table23Excel')
    var viewportHeight = panelBox.clientHeight;
    // 鉴定滚动
    if (rect.top >= viewportHeight || rect.top < 100) {
        // 不在可视化范围内
        Dom.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }
}

导入后,插件展示效果如下 如何开发一款方便快速查询数据的Google浏览器插件

标记导出 标注学生是否通过,其实就是修改UserObj对象中的remark字段,然后渲染到对应的面板当中去

//  标记学生 通过
function signFun() {
    let i = getIndex()
    UserObj[IDcards[i]].remark = '通过'
    // 同步panel页面
    signSet()
}

//  标记学生 未通过
function signLookFun() {
    let i = getIndex()
    UserObj[IDcards[i]].remark = ''
    // 同步panel页面
    signSet()
}

导出数据为Excel

导出数据这一块没有用到XLSX,而是使用的原生js进行导出,逻辑也很简单,就是利用浏览器本身的功能进行导出

// 导出标记的学生信息
function exportExcelFun() {
    function dataAnalysis(obj) {
        // 将对象处理成数组
        const arr = []
        for (const key in obj) {
            const item = obj[key]
            arr.push({
                xm: item.xm,
                sfzh: item.sfzh,
                remark: item.remark
            })
        }
        return arr
    }
    const jsonData = dataAnalysis(UserObj)
    console.log('dataSource ===> ', jsonData)
    // 列标题,逗号隔开,每一个逗号就是隔开一个单元格
    let str = `姓名,身份证号,备注\n`;
    // 增加\t为了不让表格显示科学计数法或者其他格式
    for (let i = 0; i < jsonData.length; i++) {
        for (const key in jsonData[i]) {
            // console.log('jsonData ===> ', jsonData[i], key)
            str += `${jsonData[i][key] + '\t'},`;
        }
        str += '\n';
    }
    // encodeURIComponent解决中文乱码
    const uri = 'data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(str);
    // 通过创建a标签实现
    const link = document.createElement("a");
    link.href = uri;
    // 对下载的文件命名
    link.download = "标记文档导出.xlsx";
    link.click();
}

其他方法

// 获取dom
function getDom(id) {
    const Dom = document.getElementById(id)
    return {
        html: (v) => Dom.value = v
    }
}

// 上一个
function LastLook() {
    let I = getIndex()
    if (I == 0) {
        alert('已经到头了')
    } else {
        setIndex(I - 1)
        // 切换表单数据
        initTable()
        // 同步表单选中的
        syncPanelActive()
    }
}

// 下一个
function NextLook() {
    let I = getIndex()
    // console.log('Names ===> ', Names)
    if (I >= Names.length - 1) {
        alert('已经到底了')
    } else {
        setIndex(I + 1)
        // 切换表单数据
        initTable()
        // 同步表单选中的
        syncPanelActive()
    }
}

// 查询
const queryHistory = {}
function queryFun() {
    const btn = document.getElementById('bt1')
    btn.click()
}

// 查询职业
function queryZydjFun() {
    const D = document.getElementById('search_box')
    D.getElementsByTagName('input')[3].click()
}

// 创建一个dom
function cDom(args = {}) {
    if (!args.domName) {
        console.error('domName is undefined')
        return
    }
    const Dom = document.createElement(args.domName)
    for (const key in args) {
        if (Object.hasOwnProperty.call(args, key)) {
            Dom[key] = args[key];
        }
    }
    return Dom
}

// 存储查询到了哪一个?
function setIndex(index) {
    window.localStorage.setItem('CacleIndex', index)
}

function getIndex() {
    return +(window.localStorage.getItem('CacleIndex') || '0')
}

到这里是不是才发现 貌似少了一个 background 模块,事实上,本示例并没有用到这个模块........

基本到这里我们就实现了一个很简单的Google浏览器插件的开发,也满足了领导的需求,但是Google插件能做的还有很多,包括实现浏览器录屏、抓包等等等,这些功能大家可以自行探索,也可以一起交流。

交付

当我信心满满的交付给领导的时候, 幻想着自己不用多久,就会升职加薪,当上总经理,出任CEO,迎娶白富美,走上人生巅峰,但是领导却.....

如何开发一款方便快速查询数据的Google浏览器插件

结尾

本文涉及的Google插件开发深度比较浅,适合新手学习,如果你对google插件有一定的了解,可以直接跳出本文,直接阅读代码即可,当然本文涉及到的内容如果出现错误,劳烦各位指出,感谢