总结
阿里十分注重你对源码的理解,对你所学,所用东西的理解,对项目的理解。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
click me
在content-scripts中,加入以下代码:
var greeting = "hola, ";
var button = document.getElementById(“mybutton”);
button.person_name = “Roberto”;
button.addEventListener(“click”, function() {
alert(greeting + button.person_name + “.”);
}, false);
当页面运行之后,脚本内容也会在插件定义的时间运行,当页面点击按钮时,会出现两次弹窗。
content-scripts配置:
{
…
“content_scripts”: [
{
// 在匹配的URL中运行,<all_urls>表示所有的URL都会运行。
“matches”: [“<all_urls>”],
// 注入的js,会按顺序运行。
“js”: [“./js/content.js”],
// css引入需谨慎,因为可能会影响全局的样式,同样也能接收多个css文件,会按顺序插入到页面中
“css”: [“./css/style.css”],
// 代码注入的时机,可选值: “document_start”, “document_end”, or “document_idle”,最后一个表示页面空闲时,默认document_idle
“run_at”: “document_start”
},
{
“matches”: [“https://www.baidu.com/”],
“js”: [“./js/other.js”],
“run_at”: “document_start”
}
],
…
}
content.js代码如下:
console.log(‘hello, from content.js’);
other.js代码如下:
console.log(‘hello, from other.js…’)
更新插件,当在 https://bytedance.feishu.cn/drive/home/运行时:
因为【 https://bytedance.feishu.cn/drive/home/】只匹配到了<all_urls>的规则,所以之后运行content.js
当在https://www.baidu.com/运行时:
同时命中了2个规则,所以content.js和other.js都会运行,顺序也是正确的。
content-scripts 和原始页面共享DOM,但是不共享JS,如要访问页面JS(例如某个JS变量),只能通过inject-scripts来实现。content-scripts能够访问的Chrome API的权限也比较低,只能访问以下四个API:
-
chrome.extension(getURL , inIncognitoContext , lastError , onRequest , sendRequest)
-
chrome.i18n
-
chrome.runtime(connect , getManifest , getURL , id , onConnect , onMessage , sendMessage)
-
chrome.storage
Inject-scripts
inject-scripts 是通过DOM操作插入的JS代码,通常在content-scripts只能操作DOM,但是却无法访问页面的JS,借助content-scripts可以操作DOM的能力,往页面中插入JS文件,给页面提供调用插件API的能力,以及和background通信的能力。
在插入之前,需配置一下web可访问的资源,同时content-scripts的调用时机换成"document_end"或者"document_idle",不然会无法获取DOM,导致插入失败。在manifest.json中添加以下内容:
{
…
“content_scripts”: [
{
“matches”: [“<all_urls>”],
“js”: [“./js/content.js”],
“run_at”: “document_end”
},
…
],
“web_accessible_resources”: [“js/inject.js”],
…
}
inject.js的内容如下:
function mockApi () {
console.log(‘this is from inject.js’)
}
content.js增加以下代码:
(function () {
let path = ‘js/inject.js’;
let script = document.createElement(‘script’);
script.setAttribute(‘type’, ‘text/javascript’);
// 注意,路径需用Chrome API 生成,这个方法可以获得插件的资源的真实路径。
// 类似:chrome-extension://ihcokhadfjfchaeagdoclpnjdiokfakg/js/inject.js
script.src = chrome.extension.getURL(path);
script.onload = function () {
// 在执行完代码之后移除script标签
this.parentNode.removeChild(this);
}
document.body.appendChild(script);
})();
更新插件后,页面就可以访问inject.js的方法:
permissions
插件后台有的操作需要配置相应的权限,例如本地存储、网络请求、通知等等,示例:
{
…
“permissions”: [
“contextMenus”, // 右键菜单
“tabs”, // 标签
“notifications”, // 通知
“webRequest”, // web请求
“webRequestBlocking”,
“storage” // 插件本地存储
],
…
}
完整的manifest配置
官方文档:https://developer.chrome.com/extensions/manifest
通信
–
popup和background通信
popup可以通过 chrome.extension.getBackgroundPage() API 直接获取到background的上下文,从而调用background的方法来通信:
// popup.js
var backend = chrome.extension.getBackgroundPage();
backend.test(); // 访问bbackground的函数
background可以通过chrome.extension.getViews({type:‘popup’}) 获取到popup的上下文,前提是popup页面是打开的状态下。
let views = chrome.extension.getViews({type:‘popup’});
let popup = null
if(views.length > 0) {
popup = views[0];
// 直接访问popup的函数
popup.test();
}
这里需要注意一点:
在popup页面,你如果想编写js,请将js编写在一个文件里面,然后引入进来,不然会报错,这是因为Chrome的安全政策规定的:https://developer.chrome.com/extensions/contentSecurityPolicy
popup错误示范:
…
hello world!!
正确姿势:
…
hello world!!
content-scripts和background通信
content-scripts可以通过 chrome.runtime.sendMessage(message) 给background发送消息:
chrome.runtime.sendMessage(‘message content’, (res) => {
console.log(‘from background:’, res)
});
background通过chrome.runtime.onMessage.addListener()监听content-scripts发送的消息:
chrome.runtime.onMessage.addListener(function(message, sender, callback) {
console.log(mesasge); // meesage content
callback && callback(‘yes this from background’)
});
background主动给content-scripts发消息,首先得查找要给哪个tab发消息,使用chrome.tabs.query 这个方法查找到tab,再使用chrome.tabs.sendMessage 方法给tab发消息:
// {active: true, currentWindow: true} 表示查找当前屏幕下的active状态的tab;
chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
chrome.tabs.sendMessage(tabs[0].id, ‘message content’, (res) => {
console.log(‘from content:’, res)
});
});
content-scripts通过chrome.runtime.onMessage.addListener 去监听事件:
chrome.runtime.onMessage.addListener(function (message, sender, callback) {
console.log(message, sender)
callback && callback(‘yes this from content’)
});
注意:
1.消息内容可以直接发送JSON格式的对象。
2.popup和content的通信方式与上面一样。
3.如果popup和background都监听了从content发来的消息,两者都能收到监听消息,但是callback只会触发一次,被谁触发取决与谁先发送。
inject-scripts和content-scripts
inject-scripts和content-scripts通信有两种方法:
1.window.postMessage发送,window.addEventListener接收
2.还有一种是自定义的DOM事件;
但是很少情况会是content-scripts去调inject-scripts,因为,可以,但是没必要…content-scripts完全可以自己处理一些API的事件监听,况且inject-scripts也只是content-scripts生成并插入到DOM里面的,所以在content-scripts眼里,inject-scripts就是个弟弟…
但是,很多用户触发的事件,需要通过inject-scripts告诉content-scripts,content-scripts再给background通信并且去做一些事情,然后再发消息告诉inject-scripts,从这个角度看:content-scripts就是一个inject-scripts的工具人!
(扯平了,完美。)
inject-scripts给content-scripts发消息:
window.postMessage({“test”: ‘你好!工具人!’}, ‘*’);
content-scripts接收消息:
window.addEventListener(“message”, function(message) {
console.log(‘来了老弟!’, message.data);
}, false);
同样的,content-scripts给inject-scripts发消息是一样的。
练练手:HTTP Header 插件
实现一个HTTP Header 插件,可以实现动态添加header,并且给网络请求自动加上header,header参数可以配置。
示例图:
Background 功能设计
background复制存储、操作headers,对所有浏览器请求做一层拦截,并加上启用的headers。
注意:因为涉及到网络请求,所以需在manifest.json中添加权限:
{
…
“permissions”: [
“storage”, // 本地存储
“webRequest”, // 网络请求
“webRequestBlocking”, // 网络请求 阻塞式
“<all_urls>” // 匹配的URL
]
…
}
Background 功能伪代码:
// headers数据结构, 附带默认值;(可以改为本地存储)。
const headers = [
{
key: ‘Content-Type’,
value: ‘application/x-www-form-urlencoded’,
enable: false,
},
{
key: ‘Test-Header’,
value: ‘按F进入坦克’,
enable: true,
},
];
// 获取、新增、删除、启用禁用
function getHeaders () {
return headers;
}
function addHeader (header) {
headers.push(header);
}
function deleteHeader (index) {
headers.splice(index, 1);
}
function toggleHeader(index) {
headers[index].enable = !headers[index].enable;
}
…
// 请求拦截器
// On install 在被安装的时候去初始化
chrome.runtime.onInstalled.addListener(function(){
// 添加事件
chrome.webRequest.onBeforeSendHeaders.addListener(requestHandle, {
urls: [“<all_urls>”],// 拦截所有URL的请求
},[“blocking”, “requestHeaders”]); // 阻塞式
console.log(‘load’);
});
// 添加header
function requestHandle(request) {
let requestHeaders = request.requestHeaders;
// 添加headers
headers.forEach(item => {
if (item.enable) {
requestHeaders.push({
name: item.key,
value: item.value,
});
}
});
return {requestHeaders};
}
chrome.webRequest的生命周期:
详细参考:https://developer.chrome.com/extensions/webRequest
popup 页面设计
最后
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
给大家分享一些关于HTML的面试题。
rls: [“<all_urls>”],// 拦截所有URL的请求
},[“blocking”, “requestHeaders”]); // 阻塞式
console.log(‘load’);
});
// 添加header
function requestHandle(request) {
let requestHeaders = request.requestHeaders;
// 添加headers
headers.forEach(item => {
if (item.enable) {
requestHeaders.push({
name: item.key,
value: item.value,
});
}
});
return {requestHeaders};
}
chrome.webRequest的生命周期:
详细参考:https://developer.chrome.com/extensions/webRequest
popup 页面设计
最后
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
给大家分享一些关于HTML的面试题。
[外链图片转存中…(img-oUX6BKcc-1715399999826)]
[外链图片转存中…(img-h0J7TvFA-1715399999827)]