网站制作加谷歌推广,程序员培训机构排名,网站开发方向和移动开发方向那个好,模板ppt免费谷歌浏览器插件开发指南涉及以下几个方面#xff1a;
1. 开发环境准备#xff1a;首先需要安装Chrome浏览器和开发者工具。进入Chrome应用商店#xff0c;搜索“Extensions Reloader”和“Manifest Viewer”两个插件进行安装#xff0c;这两个插件可以方便开发和调试。
2…谷歌浏览器插件开发指南涉及以下几个方面
1. 开发环境准备首先需要安装Chrome浏览器和开发者工具。进入Chrome应用商店搜索“Extensions Reloader”和“Manifest Viewer”两个插件进行安装这两个插件可以方便开发和调试。
2. 创建插件创建插件的方式有两种。第一种是从零开始创建需要编写插件的各种文件包括manifest.json、popup.html等。第二种是使用生成工具如Yeoman它可以自动生成插件文件和代码结构。
3. 编写插件代码插件代码可以使用HTML、CSS、JavaScript等需要根据插件的功能进行编写。
4. 调试和测试在Chrome浏览器中可以使用开发者工具进行调试和测试可以查看插件的运行状态以及对代码进行修改和调试。
5. 发布和分发发布插件需要一个Google开发者账号并进行相应的审核和测试。插件发布后可以通过Chrome应用商店进行分发和安装。
总的来说谷歌浏览器插件开发需要学习HTML、CSS、JavaScript等相关知识并掌握Chrome插件开发的基本流程和技能。 Chrome插件本质上也是一个web页面的功能开发因此需要熟悉以下基本的技能
HTML页面内容标记。CSS页面样式设置。JavaScript处理页面逻辑的脚本。WebPlatformAPIweb平台的标准API。
下面开始正题。
Chrome插件基础概念
ChromeAPI
ChromeAPI是Chrome浏览器提供的JavaScriptAPI在插件开发中使用这些API可以调用Chrome浏览器的提供的诸多功能完成我们定制化的需求。
manifest.json
也叫插件清单可以把它理解为整个插件的配置文件。manifest文件一定要放在根目录下不可或缺主要记录了插件的重要元数据、资源定义、权限声明以及指定要在后台运行和页面运行的文件等。
// manifest.json文件{manifest_version: 3,name: Reading time,version: 1.0,description: Add the reading time to Chrome Extension documentation articles
}
其中manifest_version、name、version是必须的。
Service worker
也就是后台服务主要是负责处理和监听浏览器的各类事件。后台服务可以使用所有ChromeAPI但是不能直接与网页内容交互。
要使用后台服务需要先在manifest文件中注册background
{...background: {service_worker: background.js}
}
后台服务在浏览器运行起来后就会一直在后台运行back.js脚本。 Content Script
也叫内容脚本。上面提到后台服务无法直接与网页内容进行交互而内容脚本便来接替了这部分工作。内容脚本可以读取、修改或注入页面DOM也可以使用一部分的ChromeAPI但是不可使用的那部分ChromeAPI可以通过与后台服务的通讯来完成数据或消息的传递交互。
要使用内容脚本需要先在manifest文件中注册content_scripts
{...content_scripts: [{js: [scripts/content.js],matches: [https://developer.chrome.com/docs/extensions/*,https://developer.chrome.com/docs/webstore/*]}]
}
其中matches表示匹配的网站js表示执行的脚本。即如果网站地址在matches列表中则会执行js列表中的脚本。
pages
页面包含了popup的弹窗页面、option页面以及其他页面这些页面也是就是前端开发中的HTML文件。这些页面都可以访问ChromeAPI。
以上便是Chrome插件开发中很重要且必要的几个概念也是一个插件工程中主要的几个文件因此请务必记住这几个概念。接下来我们将一步一步开发一个插件来逐步的了解Chrome插件开发的工作。 实际案例
插件开发
需求
开发前我们先来看看这个插件需要完成那些功能。
1、阅读时间 在指定的页面上某个位置显示出当前页面预计阅览完成所需要的时间。此处我们已百度百科页面为例在页面开头位置显示当前页面阅览完成大概需要长时间。阅读时间的预估规则我们这里简单计算下使用页面文本的字数除以每分钟200个文字并取整表示。
2、聚焦模式 对于某些页面的侧边栏、广告栏等区域做隐藏实现聚焦主体内容的阅读。
3、标签管理 组织扩展文档选项卡实现对特定域名的标签页组合成标签组。 阅读时间功能开发
思路在内容脚本中使用js统计当前页面的文字数count并假设阅读速度是500个/分钟计算出预估时间
timecount/500
先配置manifest文件
{manifest_version: 3, // 版本号目前2版本已经停止支持推广的是3版本name: toolKits, // 插件名称description: 小工具集, // 插件描述version: 1.0, // 插件开发的版本号自定义即可icons: { // 插件的图标16: images/icon-16.png,32: images/icon-32.png,48: images/icon-48.png,128: images/icon-128.png},content_scripts: [ // 内容脚本注册{js: [scripts/baikeReadTime.js],matches: [https://baike.baidu.com/item/*]}]
}
从配置中可得知内容脚本的注册规则当网址匹配上“https://baike.baidu.com/item/*”时运行scripts/baikeReadTime.js脚本。
编写内容脚本内容脚本是往页面中注入预估的阅读时间元素代码如下
// baikeReadTime.js// 通过检查百度百科页面元素确定大部分内容都是在classmain-content J-content的div标签中因此先获取到内容标签的dom
const mainContent document.getElementsByClassName(main-content J-content)[0]// 如果对应内容dom存在
if (mainContent) {const text mainContent.textContent; // 获取内容dom中所有的文本内容const chineseWordRegExp /[\u4e00-\u9fa5]/g; // 通过正则表达式匹配出所有的汉字const chineseWords text.matchAll(chineseWordRegExp);const count [...chineseWords].length; // 计算汉字长度const readTime Math.round(count / 500); // 计算预计阅读时间const badge document.createElement(span); // 创建一个span标签badge.classList.add(collect-text); // 给spn标签添加样式 样式尽量跟周围的标签样式一致badge.textContent ⏱️ 总字数约${count}, 预计阅读耗时${readTime} 分钟; // 给span标签添加文本内容const topTool document.getElementsByClassName(top-tool)[0] // 找到classtop-tool的domtopTool.insertAdjacentElement(beforebegin, badge); // 把span标签插入到topTool的dom前面
}
演示打开Chrome浏览器安装插件后打开任意百度百科的内容页即可看到我们注入到页面的预估阅读时间元素。比如我们打开百度百科搜索“亚运会”页面展示图待更新。 聚焦模式功能开发
还是以百度百科页面为例我们通过插件实现去掉右侧边栏和底部广告栏的信息
思路分析页面元素找到右侧边栏和底部广告栏的元素再通过内容脚本对其进行样式隐藏即可。
1、首先给插件的图标设置一个徽标用于展示聚焦模式的开关状态。
因为聚集模式的状态应该是在浏览器打开的时候就显示因此设置状态徽标的逻辑应该放在background.js脚本中。具体代码如下
chrome.runtime.onInstalled.addListener(() {chrome.action.setBadgeText({ text: OFF })
})调用ChromeAPI给插件设置徽标。大致意思就是添加一个安装事件的监控器当插件安装后就给插件设置一个徽标内容是“OFF”。
监听插件的点击事件。当点击插件的时候判断当前浏览器标签页(tab页)的网址如果符合要求就将插件徽标设置为“ON”。继续在background.js脚本中添加以下代码
...
const baike baike.baidu.com/item/chrome.action.onClicked.addListener(async (tab) {if (tab.url.includes(baike)) { // 如果标签页的网址中包含baike的网址则将插件徽标设置为“ON”const prevState await chrome.action.getBadgeText({ tabId: tab.id })const nextState prevState ON ? OFF : ONawait chrome.action.setBadgeText({tabId: tab.id,text: nextState})}})
以上两步使用到了Chrome的activeTab权限和scripting权限因此我们需要再manifest文件中配置权限声明
{...permissions: [activeTab,scripting],...
}
此时重新加载插件后如果当前标签页是百科页面点击插件就能看到切换徽标状态的效果的。 2、注入css隐藏元素。
当徽标状态为ON时给百科页面注入css隐藏掉右侧边栏。继续在background.js脚本中添加以下代码
...
chrome.action.onClicked.addListener(async (tab) {if (tab.url.includes(baike)) {...if (nextState ON) {await chrome.scripting.insertCSS({files: [focus-mode.css],target: { tabId: tab.id },});} else if (nextState OFF) {await chrome.scripting.removeCSS({files: [focus-mode.css],target: { tabId: tab.id },});}}})
判断徽标状态如果是“ON”则往目标标签页插入css文件否则就移除掉插入到目标页的css文件。上例中插入了focus-mode.css
编写注入的css文件已达到隐藏侧边栏和底部广告栏的目的。通过分析网页的html代码可知classside-content的标签即为侧边栏的元素标签idtashuo_bottom的标签即为底部广告栏的标签因此代码如下
// focus-mode.css.content {.side-content {display: none;}
}#tashuo_bottom {display: none;
}
3、演示
浏览器中重新加载插件后在百科页点击插件就能看到默认插件的聚集模式是“OFF”状态点击后徽标更新为“ON”状态且页面的侧边栏和底部栏都消失了图待更新。 标签管理功能开发
上面两个案例我们分别体验了内容脚本和后台服务脚本的能力接下来我们看看插件打开的页面相关的能力。
该功能我们期望点击插件能打开一个弹窗页在这个弹窗页中展示当前浏览器窗口的所有标签页然后我们可以选择某些标签页将他们放在一个标签组中。
思路实现popup页面并在页面中展示当前浏览器窗口的所有标签页然后页面中有按钮可创建一个标签组并将选中的标签页放到这个标签组中。
1、首先我们需要一个popup页面
html代码如下
# popup.html!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /link relstylesheet href./popup.css //headbodytemplate idli_templateliah3 classtitleTab Title/h3p classpathnameTab Pathname/p/a/li/templateh1Google Dev Docs/h1button新建/取消组合/buttonul/ulscript src./popup.js typemodule/script/body
/html
需要注意的是这个popup.html无法运行内联 JavaScript因此我们只能通过导入的方式引入JavaScript脚本。
css代码如下:
# popup.cssbody {width: 20rem;
}ul {list-style-type: none;padding-inline-start: 0;margin: 1rem 0;
}li {padding: 0.25rem;
}
li:nth-child(odd) {background: #80808030;
}
li:nth-child(even) {background: #ffffff;
}h3,
p {margin: 0;
}
2、点击插件触发弹窗
要实现点击插件就能打开popup弹窗页有两中方式 方法1可以在manifest文件中的action字段中配置默认弹窗代码如下
{...action: {default_popup: popup.html},...
}
该配置意思是点击插件时默认打开的弹窗就是“popup.html”文件。 方法2后台脚本中通过监听点击事件然后调用ChromeActionAPI的setPopup方法实现。本插件因为之前实现了百度百科页面的聚焦模式功能因此采用这种方式触发弹窗。对之前的代码做了些调整具体如下
// background.js// 监听运行时和安装完成的事件
chrome.runtime.onInstalled.addListener(async () {// 获取当前浏览器窗口激活的标签页tabs await chrome.tabs.query({active: true, currentWindow: true})// 如果标签页的url中包含百度百科的地址就设置徽标否则不设置徽标if(tabs[0].url.includes(baike.baidu.com/item/)){chrome.action.setBadgeText({ text: OFF })}
})// 监听点击事件
chrome.action.onClicked.addListener(async (tab) {// 如果当前页面是百度百科的页面就更新徽标状态并完成聚焦模式的相关功能if (tab.url.includes(baike.baidu.com/item/)) {const prevState await chrome.action.getBadgeText({ tabId: tab.id })const nextState prevState ON ? OFF : ONawait chrome.action.setBadgeText({tabId: tab.id,text: nextState})if (nextState ON) {await chrome.scripting.insertCSS({files: [focus-mode.css],target: { tabId: tab.id },});} else if (nextState OFF) {await chrome.scripting.removeCSS({files: [focus-mode.css],target: { tabId: tab.id },});}}// 如果当前页是菜鸟教程网站的页面就弹出popup弹窗else if(tab.url.includes(www.runoob.com/)){chrome.action.setPopup({ popup: popup/popup.html })}}) tips如果在manifest文件中配置了点击默认弹窗页面那么action.onClicked事件将不会生效。 3、将所有的标签页的title和path展示在popup弹窗页中
交互逻辑通过popup.js实现3.1 调用ChromeAPI查询当前浏览器窗口中的所有标签页
// poppu.js// 查询符合条件的所有tabs
const tabs await chrome.tabs.query({currentWindow: true,url: [https://www.runoob.com/*]
});
...
3.2 将标签页列表插入到popup页面的元素中
...
// 按照默认顺序对tabs列表中的元素进行排序
const collator new Intl.Collator();
tabs.sort((a, b) collator.compare(a.title, b.title));const template document.getElementById(li_template); // 从页面获取模版节点
const elements new Set();
for (const tab of tabs) {const element template.content.firstElementChild.cloneNode(true); // 复制模版第一个节点const title tab.title.split(-)[0].trim(); // 获取tab中的标题const pathname new URL(tab.url).pathname.slice(/docs.length); // 获取tab中的路径element.querySelector(.title).textContent title; // 复制出来的节点中class“title”的子节点写入内容element.querySelector(.pathname).textContent pathname; // 复制出来的节点中class“pathname”的子节点写入内容element.querySelector(a).addEventListener(click, async () { // 复制出来的节点中a标签子节点添加点击事件// 点击的时候更新对应的tab和窗口为激活状态await chrome.tabs.update(tab.id, { active: true });await chrome.windows.update(tab.windowId, { focused: true });});elements.add(element);
}
document.querySelector(ul).append(...elements);
以上代码中使用到了ChromeTabsAPI该API 中的许多方法无需请求任何权限即可使用。但是如果要访问标签页的标题和 URL这些敏感属性就需要声明授权许可。如果我们请求“标签页”权限导致所有标签页的敏感属性都有权限访问但是由于我们仅仅管理特定网站的选项卡因此我们请求更小范围的host权限。 host权限可以授权我们获取指定网站的敏感信息(包含title和URL)以此来缩小权限范围进而保护用户隐私。在manifest文件中配置host权限
{...host_permissions: [https://www.runoob.com/*],...
}
注意如果插件中使用了tabs权限或host权限那么用户在安装插件时都会有弹窗提示。如下图 3.3 对标签页进行分组 该功能需要使用到ChromeTabGroupsAPI该API将允许插件对标签组进行命名和设置颜色。同样的要使用该API也需要在manifest文件中声明权限
{...permissions: [...tabGroups]...
}
3.4 实现按钮的交互
在 popup.js 中创建一个按钮该按钮将使用 tabs.group() 对所有选项卡进行分组并将它们移动到当前窗口中。具体代码如下
...
const button document.querySelector(button); // 获取button标签
// 给button标签添加点击事件
button.addEventListener(click, async () {const tabIds tabs.map(({ id }) id); // 解构出tabs中每个对象的id属性并组合成tabIdsconst group await chrome.tabs.group({ tabIds }); // 将tabIds新建成标签组await chrome.tabGroups.update(groupId, { title: 菜鸟, color: yellow }); // 更新标签组的标题和颜色
});
如果标签页已经在分组中则移出分组 要将标签页移出分组需要使用到ChomeTabsAPI因此要在manifest文件中声明tabs权限
{...permissions: [...tabGroups,tabs]...
}
因为在点击按钮时需要先判断是否已经有标签组了所以对popo.js做如下改造
...
const button document.querySelector(button); // 获取添加组合的button标签
// 给button标签添加点击事件
button.addEventListener(click, async () {const tabGroups await chrome.tabGroups.query({ title: 菜鸟 }) // 找到菜鸟标签组// 如果菜鸟标签组存在则取消标签组否则添加菜鸟标签组if (tabGroups.length) {const tabs await chrome.tabs.query({ groupId: tabGroups[0].id })const tabIds tabs.map(({ id }) id)await chrome.tabs.ungroup(tabIds)} else {const tabIds tabs.map(({ id }) id); // 解构出tabs中每个对象的id属性并组合成tabIdsconst groupId await chrome.tabs.group({ tabIds }); // 将tabIds新建成标签组await chrome.tabGroups.update(groupId, { title: 菜鸟, color: yellow }); // 更新标签组的标题和颜色}
});
------但是在调试过程中发现后台服务中的点击事件存在一些Bug点击事件中如果有根据网站来判断弹哪个页面的话第一个条件规则触发后后面的条件规则将不会覆盖第一个条件规则。目前没有找到原因后续再继续研究下官方文档。 参考文档zhuanlan.zhihu.com/p/655456499