まず、アクセス許可で使用する必要があるタブのアクセス許可を宣言する必要があります。
{
"permissions": [
"tabs",
// "storage",
// "cookies",
// "alarms",
// "scripting",
// "webRequest",
// "webRequestBlocking",
// "*://*/*"
]
}
背景.js
// 监听页面url变化
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
// console.log({changeInfo, tab})
if (!['complete', 'loading'].includes(changeInfo.status)) return false
chrome.tabs.sendMessage(tabId, {
type:'routeUpdate', content: tab}, response => {
console.log(response)
});
});
コンテンツスクリプト.js
// 记录页面路由变化情况
let tabUpdate = 0;
/**
* 接收bg|popup发给content-script的消息
* message object 消息对象
* sender object 发送者,含{id: "插件的ID字符串", origin: "null"}
* sendResponse function 消息响应,可回复发送者
.*/
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse)
{
let {
type, content} = message;
// console.log('crx: 收到来自bg|popup的消息:');
// console.log({message, sender});
if (type === 'routeUpdate') {
// 页面路由变化会有两次通知,一次加载时,一次完成时,
// 判断是更新还是新加载,一律放在complete,
// 因为重定向会出现多次loading,而complete仅页面加载完成才会触发
if (content.status == 'loading') {
// 如果页面存在重定向会出现只完成一次complete但不止一次的loading,
// 非特殊情况不在loading判断处理,防止不准
}
else if (content.status == 'complete') {
if (++tabUpdate > 1) {
console.log('complete路由变化' + parseInt(tabUpdate - 1));
}
else {
console.log('complete新开的页面' + tabUpdate);
}
}
}
sendResponse('crx: 我是后台,我已收到你的消息:' + JSON.stringify(message));
})
Chrome インターフェース機能の使用に加えて、履歴を書き換えることもできます
!!重写history应该是注入到top,而注入到contentScript是监听不到的
- 履歴を書き換える
class Dep {
// 订阅池
constructor(name){
this.id = new Date() //这里简单的运用时间戳做订阅池的ID
this.subs = [] //该事件下被订阅对象的集合
}
defined(){
// 添加订阅者
Dep.watch.add(this);
}
notify() {
//通知订阅者有变化
this.subs.forEach((e, i) => {
if(typeof e.update === 'function'){
try {
e.update.apply(e) //触发订阅者更新函数
} catch(err){
console.warr(err)
}
}
})
}
}
Dep.watch = null;
class Watch {
constructor(name, fn){
this.name = name; //订阅消息的名称
this.id = new Date(); //这里简单的运用时间戳做订阅者的ID
this.callBack = fn; //订阅消息发送改变时->订阅者执行的回调函数
}
add(dep) {
//将订阅者放入dep订阅池
dep.subs.push(this);
}
update() {
//将订阅者更新方法
var cb = this.callBack; //赋值为了不改变函数内调用的this
cb(this.name);
}
}
var addHistoryMethod = (function(){
let historyDep = new Dep();
return function(name) {
if(name === 'historychange'){
return function(name, fn){
let event = new Watch(name, fn)
Dep.watch = event;
historyDep.defined();
Dep.watch = null; //置空供下一个订阅者使用
}
} else if(name === 'pushState' || name === 'replaceState') {
let method = history[name];
return function(){
method.apply(history, arguments);
historyDep.notify();
}
}
}
}())
window.addHistoryListener = addHistoryMethod('historychange');
history.pushState = addHistoryMethod('pushState');
history.replaceState = addHistoryMethod('replaceState');
- 食べ方
// 使用监听
window.addHistoryListener('history', function(){
console.log('窗口的history改变了');
})