JavaScript实现谷歌浏览器插件开发的方法详解
作者:Csharp 小记
对于浏览器插件相信大家都不陌生,谁的浏览器不装几个好用的插件呢,更是有油猴这个强大的神器。但是大家有没有尝试自己去写一个插件呢?对于这个问题,其实很长时间以来我是一直有想法但从来没有付出行动,直到前一段时间有朋友找我写一些关于浏览器自动化的程序,当然如果简单的话,直接在控制台运行js脚本就可以了(但是真的不好用),转念一想,浏览器插件也许也是一个不错的选择,感觉应该不会太难,就去稍微了解了一下,有这个想法另一方面原因之前是有看到关于用c#来直接写浏览器插件的,嗯,没错,就是Blazor。还是花了点时间去研究这个东西,最后发现,极为难用。。。
随后简单看了下开发浏览器插件的原生写法——这不是稍微会一点前端技术就能搞么,恰好,我就懂这么一点。。。
不过最后我并没有用插件去实现这个需求,因为我发现了另外一个简单且好用的东西:Selenium。但是刚刚学会这个东西,总得写个东西来记录一下吧,后面用到的时候也比较好找。
现在的浏览器基本都自带密码记住的功能。但是对于有些网站却并不能做很好的识别,要么输入的位置错乱,要么账号密码错乱。所以最终写了这个插件出来。暂且叫做"密码箱"吧,我们可以自己定义捕获输入框的标识然后赋值进去,来解决上面提到的问题。
这里我们使用到的开发工具是 Visual Studio Code,然后整体看下我们的框架,其实跟我们写前端一样的,只是多了一个manifest.json文件,这也是最重要的一个文件;不过现在大家都用Vue了,一套命令下来应有尽有。
1.先来看下manifest.json文件的配置,因为我们做的比较简单,所以配置的也并不多,关于每项配置的含义已经在文件中注释了。
{ "name": "密码箱",//插件名称 "description": "密码箱",//插件描述 "version": "1.0.0",//插件版本 "manifest_version": 3,//文件版本2或者3,2目前是主流,3是趋势,谷歌浏览器目前是使用3版本的 "background": { //常驻后台服务 "service_worker": "/js/background.js" }, "permissions": ["storage", "activeTab", "scripting", "contextMenus", "tabs"], //需要的权限 "homepage_url": "https://www.baidu.com",//插件主页地址 "action": { "default_popup": "html/popup.html",//可交互页面 "default_icon": { "16": "/img/icon.png", "32": "/img/icon.png", "48": "/img/icon.png", "128": "/img/icon.png" } }, "options_ui": {//插件选项配置 "page": "/html/options.html", "open_in_tab": true }, "icons": {//图标 "16": "/img/icon.png", "32": "/img/icon.png", "48": "/img/icon.png", "128": "/img/icon.png" }, "host_permissions": ["*://*/*"]//主机权限 }
2.然后我们需要一个配置页面,来设置我们需要保存的账号信息以及表单元素即options.html和options.js。主要代码都在options.js中了,所以这里主要放下js的代码
let btn_save = document.getElementById("btn_save"); let btn_add = document.getElementById("btn_add"); init(); function add_row(id){ let element_str = ` <div class="form"> <div class="form-item"> <label>账号:</label> <input type="text" class="user"/> </div> <div class="form-item"> <label>密码:</label> <input type="text" class="pwd" /> </div> <div class="form-item"> <label>网址:</label> <input type="text" class="url"/> </div> </div> <div class="form"> <div class="form-item"> <label>账号元素:</label> <input type="text" class="user_tag" /> </div> <div class="form-item"> <label>密码元素:</label> <input type="text" class="pwd_tag" /> </div> <div class="form-item"> <button class="btn_del">删除</button> </div> </div> <div class="line"></div> </div>`; let element = document.createElement("div"); element.setAttribute("class", "row"); element.setAttribute("id", "row" + id); element.innerHTML = element_str; document.getElementById("main").appendChild(element); return element; } function bind_rowdel(element,id){ let btn_del = element.getElementsByClassName("btn_del")[0]; btn_del.addEventListener("click", function () { let row = document.getElementById("row" + id); document.getElementById("main").removeChild(row); btn_save.click(); }); } function init(){ chrome.storage.sync.get("pwd_box", function (result) { let save_list = result.pwd_box; if (save_list==undefined||save_list.length == 0) { save_list=[]; save_list.push({ user: "", pwd: "", url: "", user_tag: "", pwd_tag: "", }); } for (let i = 0; i < save_list.length; i++) { let element=add_row(i); element.getElementsByClassName("user")[0].value = save_list[i].user; element.getElementsByClassName("pwd")[0].value = save_list[i].pwd; element.getElementsByClassName("url")[0].value = save_list[i].url; element.getElementsByClassName("user_tag")[0].value = save_list[i].user_tag; element.getElementsByClassName("pwd_tag")[0].value = save_list[i].pwd_tag; bind_rowdel(element,i); } }); } btn_save.addEventListener("click", async () => { let items = document.getElementsByClassName("row"); let save_list = []; for (let i = 0; i < items.length; i++) { save_list.push({ user: items[i].getElementsByClassName("user")[0].value, pwd: items[i].getElementsByClassName("pwd")[0].value, url: items[i].getElementsByClassName("url")[0].value, user_tag: items[i].getElementsByClassName("user_tag")[0].value, pwd_tag: items[i].getElementsByClassName("pwd_tag")[0].value, }); } await chrome.storage.sync.set({ pwd_box: save_list }, null); alert("操作成功"); }); btn_add.addEventListener("click", async () => { let id=new Date().getTime(); let element=add_row(id); bind_rowdel(element,id); });
3.最后就是我们需要做一个主动赋值的操作了。即上面提到的可交互的页面:popup.js。当然我们也可以写在background.js中,自动监听然后直接赋值,但我这里没有使用这种方式。
let btn = document.getElementById("btn"); async function getCurrentTab() { let queryOptions = { active: true, lastFocusedWindow: true }; let [tab] = await chrome.tabs.query(queryOptions); return tab; } btn.addEventListener("click", async () => { let tab = await getCurrentTab(); chrome.scripting.executeScript({ target: { tabId: tab.id }, func: inputs, args: [tab.url], }); }); function inputs(url) { chrome.storage.sync.get("pwd_box", async (result) => { let model = result.pwd_box.find((s) => { return s.url == url; }); if (model != undefined) { let user_selector, pwd_selector; let utag = model.user_tag.split(":", 2); switch (utag[0].toLowerCase()) { case "id": user_selector = document.getElementById(utag[1]); break; case "class": user_selector = document.getElementsByClassName(utag[1])[0]; break; case "name": user_selector = document.getElementsByName(utag[1])[0]; break; default: break; } user_selector.value = model.user; //await sleep(1000); let ptag = model.pwd_tag.split(":", 2); switch (ptag[0].toLowerCase()) { case "id": pwd_selector = document.getElementById(ptag[1]); break; case "class": pwd_selector = document.getElementsByClassName(ptag[1])[0]; break; case "name": pwd_selector = document.getElementsByName(ptag[1])[0]; break; default: break; } pwd_selector.value = model.pwd; } }); function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } }
到此,我们这个插件就写完了;
到此这篇关于JavaScript实现谷歌浏览器插件开发的方法详解的文章就介绍到这了,更多相关JavaScript谷歌浏览器插件开发内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!