Chrome 插件特性及实战场景案例分析
一、前言
提起Chrome扩展插件(Chrome Extension),每个人的浏览器中或多或少都安装了几个插件,像一键翻译、广告屏蔽、录屏等等,通过使用这些插件,可以有效的提高我们的工作效率;但有时候,我们想要的某个功能市面上没有现成的插件,作为开发者自然而然想到,自己是否可以动手开发一个定制化的插件?网上目前很多不错的关于Chrome插件的开发教程,可以帮助我们快速上手开发一个插件, 本文换个思路,从应用着手,通过讲解插件的特性来启发读者在工作中哪些场景可以通过插件来解决。
本文侧重点不是Chrome插件的基础开发,而是聚焦于原理及应用,会从插件的一些重要特性讲起,结合实际的插件案例,来分析这些特性的作用,从而能够启发读者利用这些特性开发出自己的效率工具,打造自己的趁手利器。
二、什么是Chrome扩展插件
什么是Chrome扩展插件?在我们印象中,它就像跑在浏览器中的应用,可以把浏览器想象成手机,那么插件就像是应用,我们从Chrome应用商店中下载,然后安装到Chrome浏览器中,就可以在浏览器中进行运行了。
我们看看官方解释:
Chrome Extension是一个小的软件程序,它可以用来定义浏览器的浏览体验,让用户可以根据个人需求或者偏好定制Chrome浏览器的功能和行为,主要使用的技术栈是HTML、Javascript和CSS。
一句话总结:Chrome扩展插件是用前端的技术栈,来定制浏览器的功能,改善用户体验。
可能大家还听过一个词:Chrome Plugin。翻译过来是Chrome插件,和Chrome扩展插件很相近,特别容易搞混,那么他们之间有什么区别呢?
Chrome Extension仅仅是用来增强浏览器网页的功能,它是利用浏览器提供的已有功能和和各种API,进行功能组合,从而改善浏览器体验,停留在浏览器层面;
Chrome Plugin不仅能增强网页的功能,同时能够扩展浏览器本身的功能;当浏览器提供的功能已经无法满足你的需求,就需要你通过C/C++这样的编译语言来扩展浏览器的功能,例如我们常用的Flash 插件,Chrome Plugin工作在内核层面。
三、Chrome扩展插件组成及核心机制
3.1 Chrome扩展插件的组成
一个 Chrome 扩展插件通常由 3 类文件组成:
1) 配置文件 manifest.json,用于配置扩展的名称、版本号、作者、图标 icon、弹出界面、权限、脚本路径等信息;
2) 图片、css 等资源文件;
3)js脚本文件,其中包含:
popup.js:用于搭配 popup.html 使用,点击插件图标的时候展示页面及页面逻辑控制;
background.js:用于定义一个后台页面,相当于一个常驻页面,生命周期和浏览器一致;
content_scripts.js:用于向页面中注入 JS 脚本,它可以操作页面dom,但不会和页面中的脚本产生冲突。
3.2 Chrome扩展插件的核心机制
Chrome扩展插件中比较核心的几个概念:Extension Page、background.js、Content_script.js ,它们在什么时机触发,扮演着什么角色,彼此之间如何进行通信?可以看一下下面的关系图:
从图中可以看出,存在三个进程:扩展进程(Extension Process)、页面渲染进程(Render Process)、浏览器进程(Browser Process)。
1)扩展进程中运行Extension Page,Extension Page主要包括backgrount.html和popup.html:
backgrount.html中没有任何内容,是通过background.js创建生成,当浏览器打开时,会自动加载插件的background.js文件,它独立于网页并且一直运行在后台,它主要通过调用浏览器提供的API和浏览器进行交互;
popup.html则不同,它有内容,是一个实实在在的页面,和我们普通的web页面一样,由html、css、Javascript组成,它是按需加载的,需要用户去点击地址栏的按钮去触发,才能弹出页面。
2)渲染进程主要运行Web Page,当打开页面时,会将content_script.js加载并注入到该网页的环境中,它和网页中引入的Javascript一样,可以操作该网页的DOM Tree,改变页面的展示效果;
3)浏览器进程在这里更多起到桥梁作用,作为中转可以实现Extension Page和Content_script.js之间的消息通信。
四、Chrome扩展插件能做什么
Chrome扩展插件的使用方向主要包含两个部分:
改变浏览器的外观:
brower Actions
page Actions
content menus
桌面通知
Omnibox
override 替代页
和浏览器进行交互:
Cookie控制
标签控制
书签控制
下载控制
事件监听
网络请求
代理...
下面我们通过实例来分析这些功能的使用案例:
实例1:替换页面
使用替代页,可以将Chrome默认的一些特定页面替换掉,改为使用扩展提供的页面。这让开发者可以开发更多有趣或者实用的基本功能页面。
"chrome_url_overrides": {
"newtab": "newTab.html", //替换新标签页
"bookmarks":"bookmarks.html", //替换书签管理器页面
"history":"history.html" //替换历史记录页面
},
下面是一个替换新标签页的效果图:
实例2:Cookie控制
通过Cookie的API,可以对浏览器的Cookie进行增删改查工作。例如我们在开发工作中,经常需要频繁的清除浏览器缓存,每次都需要先找到清除按钮,弹出对话框,进行确认,操作很繁琐,如果开发一个chrome扩展插件,就可以轻松实现一键快捷清除浏览器Cookie等缓存,可以参考Clear Store插件。
**实例3:标签控制 **
使用chrome.tabs API与浏览器的标签系统进行交互,可以查询,创建、修改和重新排列浏览器中的标签页;我们在使用浏览器时,经常会打开很多标签页,显得很混乱,中途想要找打开的某个页面时,效率低且痛苦,如果能将这些标签页进行整理并有序的展示该多好,这里给大家推荐一个Chrome扩展插件:OneTab,该插件将所有打开的标签页在新的页面中有序的排列出来,如下图,一目了然。
我们甚至可以通过tabs 实现页签之间的交互,出于安全考虑,tab的属性中没有document, 因此无法在扩展中直接获取某个标签页面中的dom元素,但是可以通过发送事件请求来实现:
chrome.tabs.sendRequest(tab_id, {
hello: "ok"
}, function(response){
// response处理
});
chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
if (request.hello == "ok"){
sendResponse({
data: $("#hello") // 获取id是hello的元素发过去
});
}
}
);
实例4:拦截请求或者反向代理
在在页面性能点检时,我们经常会检查页面图片资源是否存在尺寸过大,例如200K,获取一个过大的图片列表页面。
chrome.webRequest API只能在background.js中使用,所以可以通过图片拦截,将链接通过消息传给当前页面的content_script.js,然后在content_script.js中进行图片下载和大小检查。
// background.js
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
// url就是图片下载的链接
const { url ,tabId} = details
// 向content_script.js发送下载图片链接
chrome.tabs.sendMessage(tabId, {picUrl: url}, function(response) {
//...
});
return {cancel: isCancel};
},
{urls: ["http://baidu.com"],types: "image"},
["blocking"]
);
// content_script.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse)
{
if(sender.tab && request.picUrl && request.picUrl == sender.tab.id){
//获取图片大小并下载
}
});
实例5:页面元素操作
利用Content_script.js可操作dom元素,进行对页面元素进行操作,实现自动化登录,解放双手。
//输入
function input(inputElement, content) {
let event = document.createEvent('HTMLEvents');
event.initEvent('input', true, true);
inputElement.value = content;
inputElement.dispatchEvent(event)
}
const usernameDom = document.getElementById("userName"); //用户名
const pwdDom = document.getElementById("password"); //密码
const btnDom = document.getElementById("submitBtn");//按钮
//输入后,点击确认
input(usernameDom, "姓名");
input(pwdDom, "密码");
//登录
btnDom.click();
五、业务实践
痛点:我目前主要负责vivo全球商城的业务,全球化的业务都会面临国际化语言的问题,我们自主开发了一个多语言管理后台,配置key-value,前端通过接口获取多语言在页面展示;如果运营查看页面,觉得某个文案不太合适,想要修改,需要进行如下图的一系列操作:
可以看到当运营想要修改文案时,他先要知道该文案对应的key值,而页面上面无法获取到key值,需要让开发提供,然后需要到多语言管理平台去更新对应key的值。
这样遇到两个问题:
不能所见即所得,看到页面不能知道key值;
所见无法直接修改,需要到另一个管理平台去修改 ;
目前这个在修改内容少的情况下,还是可以操作的,当修改内容很多时,这样操作起来很繁琐,效率很低。
思考:
1)运营是否可以直接在页面上修改并生效?
2)如果可以修改,怎么去实现跨域请求?
3)怎么实现登录授权?
如果对Chrome扩展插件熟悉,会发现Chrome就是为这量身定制,可以完美解决这些问题。
**实现方案: **
1)对页面中涉及文案dom进行修改,绑定多语言key值。
<div data-lang-key="address.delete.button">{{ language.addressDeleteButton }}</div>
2)利用Content_script,js可以操作页面dom元素,当启动插件时,将页面所有可修改的文案的dom增加contenteditable属性,支持可编辑,如图;
3)创建一个修改面板,获取当前选中的key值和value值,和修改后的值,如上图,右上角面板。
4)利用Chrome插件支持跨站请求的特性,向多语言平台直接发送修改请求。
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
try{
sendResponse(JSON.parse(xhr.response));
}catch(e) {
// 异常处理
}
}
};
xhr.send(new URLSearchParams(params));
return true
}
);
5)利用Chrome插件可以获取浏览器中Cookie特性,新开一个标签页打开多语言后台,进行登录,登录成功后就可以实现请求的授权修改了。
六、总结
最后总结一下,生活中经常会感叹:看过好多人生道理,依然过不好这一生。同样,使用过很多Chrome插件,依然码不好自己的一个插件,所以最后再送给你一个阅读Chrome插件源码的插件,堪称插件中的插件,插件中的王者——Chrome extension source viewer。通过它可以很方便的查看其它插件的源码,让我们能够站在巨人的肩膀上往前走~~
作者:vivo互联网前端团队-Zhang hao
Chrome 插件特性及实战场景案例分析的更多相关文章
- 《深入理解Java虚拟机》-----第5章 jvm调优案例分析与实战
案例分析 高性能硬件上的程序部署策略 例 如 ,一个15万PV/天左右的在线文档类型网站最近更换了硬件系统,新的硬件为4个CPU.16GB物理内存,操作系统为64位CentOS 5.4 , Resin ...
- Salesforce学习之路-developer篇(五)一文读懂Aura原理及实战案例分析
1. 什么是Lightning Component框架? Lightning Component框架是一个UI框架,用于为移动和台式设备开发Web应用程序.这是一个单页面Web应用框架,用于为Ligh ...
- Laravel 中使用 swoole 项目实战开发案例二 (后端主动分场景给界面推送消息)
推荐阅读:Laravel 中使用 swoole 项目实战开发案例一 (建立 swoole 和前端通信) 需求分析 我们假设有一个需求,我在后端点击按钮 1,首页弹出 “后端触发了按钮 1”.后端点了 ...
- CSS3-3D制作案例分析实战
一.前言 上一节,介绍了基础的CSS3 3D动画原理实现,也举了一个小小的例子来演示,但是有朋友跟我私信说想看看一些关于CSS3 3D的实例,所以在这里为了满足一下大家的需求,同时也为了以后能够更好的 ...
- 【Cocos游戏实战】功夫小子第七课之游戏主功能场景逻辑功能和暂停功能场景的分析和实现
CSDN的markdown编辑器是吃屎了么! !.什么玩意.!写了一半写不了东西还全没了,搞个毛线! 本节课的视频教程地址是:第七课在此 假设本教程有帮助到您,希望您能点击进去观看一下,并且如今注冊成 ...
- 【JVM.4】调优案例分析与实战
之前已经介绍过处理Java虚拟机内存问题的知识与工具,在处理实际项目的问题时,除了知识与工具外,经验同样是一个很重要的因素.本章会介绍一些具有代表性的案例. 本章的内容推荐还是原文全篇看完的好,实在不 ...
- Python核心技术与实战——十|面向对象的案例分析
今天通过面向对象来对照一个案例分析一下,主要模拟敏捷开发过程中的迭代开发流程,巩固面向对象的程序设计思想. 我们从一个最简单的搜索做起,一步步的对其进行优化,首先我们要知道一个搜索引擎的构造:搜索器. ...
- 软工案例分析之OJ
项目 内容 这个作业属于哪个课程 2021春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 案例分析作业要求 我在这个课程的目标是 和我的团队开发一个真正的软件,一起提升开发与合作的能力 这 ...
- mysql转ElasticSearch的案例分析
前言 最近工作中在进行一些技术优化,为了减少对数据库的压力,对于只读操作,在程序与db之间加了一层-ElasticSearch.具体实现是db与es通过bin-log进行同步,保证数据一致性,代码调用 ...
随机推荐
- 阿里云 Serverless 再升级,从体验上拉开差距
差距都在细节上. Serverless 要成就云计算的下一个 10 年,不仅需要在技术上持续精进,也需要在产品体验上精耕细作. 近日,阿里云 Serverless 再度升级,发布了一系列围绕产品体验方 ...
- 二进制对比工具HexCmp的使用
一.前提 遇到一个问题,文件通过后台上传成功后,客户端下载解压后,再次加载文件报错,报错信息该模块应包含一个程序集清单. (异常来自 HRESULT:0x80131018).但该错误文件与原文件大小一 ...
- C# datagridview、datagrid、GridControl增加行号
01 - WinForm中datagridview增加行号 在界面上拖一个控件dataGridView1,在datagridview添加行事件中添加如下代码: private void dataGri ...
- Frida高级逆向-Hook Java
Frida Hook Java 层 Frida两种启动方式的区别 span 模式:frida 重新打开一个进程 frida -U -f 包名 -l js路径 --no-pause attch 模式: ...
- BUAA软件工程:软件案例分析
BUAA软件工程:软件案例分析 Author:17373015 乔玺华 项目 内容 这个作业属于哪个课程 2020计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 软件案例分析博客作业 我在这个 ...
- freemarker自定义指令
最近项目中使用了spring boot搭建项目,使用spring security管理项目中的权限,使用freemarker作为视图层.为了将权限控制到按钮上,因此考虑直接使用spring secur ...
- Noip模拟67 2021.10.3
还是困,不过已经可以用脑子思考问题了 T1 数据恢复 没啥明确的算法,可以说是贪心? 考虑部分分, 链的直接扫, 对于菊花的发现只要根节点在第一个,剩下的点位置不重要 那么按照$a/b$排序,扫一遍就 ...
- 2021.9.28考试总结[NOIP模拟64]
T1 三元组 发现确定\(b,c\)的情况下,\(a\)的值域是连续的.确定\(b\)后\(a+b\)的取值是\([1+b,b+b]\).树状数组维护对每个\(b\)可行的\(c\). 注意取模后取值 ...
- 设计的MOS管三极管简单开关电路驱动能力不够1
您需要 登录 才可以下载或查看,没有帐号?注册 x . ?& P' U5 r/ ~& `: B 用AOD409设计的开关电路为什么驱动能力不够,请大家帮忙分析一下原因啊.这个电路作用就 ...
- TypeError: Error when calling the metaclass bases Cannot create a consistent method resolution
Python Error when calling the metaclass bases Cannot create a consistent method resolution order (MR ...