如何编写将内容脚本应用于单页面应用程序的Chrome扩展?
我目前正在编写一个扩展,它将把与RegEx模式(特别是德国电话号码的RegEx模式)匹配的每个字符串转换为可点击的链接,方法是在元素的href中添加tel:,并在需要时使用锚标记将其括起来。
在过去的三天里,我一直在努力让我们公司用于他们联系人的One Single Page App正常工作。但每当我将我的扩展加载到浏览器中,然后重新启动浏览器时,它一开始并不应用我的内容脚本。访问页面后,我首先需要刷新页面。
我正在使用以下文件:
清单.json:
{
"name": "testExtension",
"short_name": "testExtension",
"version": "1.0.0",
"manifest_version": 2,
"description": "Replace telephone numbers with clickable links.",
"author": "Ngelus",
"icons": {
"16": "icons/icon16.png",
"48": "icons/icon48.png",
"128": "icons/icon128.png"
},
"browser_action": {
"default_icon": "icons/icon48.png",
"default_title": "testExtension"
},
"default_locale": "en",
"permissions": [
"tabs",
"activeTab",
"<all_urls>",
"*://*.examplecontactsapp.de/*",
"storage",
"webRequest",
"webNavigation"
],
"content_scripts": [
{
"matches": [
"*://web.examplecontactsapp.de/contacts",
"*://web.examplecontactsapp.de/contacts*"
],
"js": ["src/inject/contentscript.js"]
}
],
"background": {
"scripts": ["src/bg/background.js"],
"persistent": true
}
}
后台.js:
let currentUrl = '';
let tabId;
chrome.webRequest.onCompleted.addListener(
function (details) {
const parsedUrl = new URL(details.url);
if (currentUrl && currentUrl.indexOf(parsedUrl.pathname) > -1 && tabId) {
chrome.tabs.sendMessage(tabId, { type: "pageRendered" });
}
},
{ urls: ['*://web.examplecontactsapp.de/contacts*'] }
);
chrome.webNavigation.onHistoryStateUpdated.addListener(
(details) => {
tabId = details.tabId;
currentUrl = details.url;
},
{
url: [
{
hostSuffix: 'examplecontactsapp.de',
},
],
}
);
ContScript.js:
var readyStateCheckInterval = setInterval(function () {
if (!location.href.startsWith('https://web.examplecontactsapp.de/contacts')) return;
if (document.readyState === 'complete') {
clearInterval(readyStateCheckInterval);
console.log(
`[---testExtension---]: replacing all telephone numbers with clickable links...`
);
replaceNumbersWithLinks();
}
}, 10);
chrome.runtime.onMessage.addListener(function (request) {
if (request && request.type === 'pageRendered') {
const readyStateCheckInterval = setInterval(function () {
if (document.readyState === 'complete') {
clearInterval(readyStateCheckInterval);
console.log(
`[---testExtension---]: replacing all telephone numbers with clickable links...`
);
replaceNumbersWithLinks();
}
}, 10);
}
});
function replaceNumbersWithLinks() {
document
.querySelectorAll(
'body > main > div.page-content > div > table > tbody > tr > td > p > a'
)
.forEach((a) => {
var b = a.innerText.replaceAll(' ', '').trim();
a.removeAttribute('data-phonenumber');
if (b != '') a.href = 'tel:' + b;
});
}
这样做的正确方式是什么? 如何在我每次访问该单页面应用程序时使其工作?
提前感谢大家。
解决方案
使matches
匹配清单中的整个站点.json:
{
"content_scripts": [
{
"matches": [
"*://web.examplecontactsapp.de/*"
],
"js": ["src/inject/contentscript.js"]
}
],
使用MutationWatch,并使用中等速度的querySelector检查Conentscript.js中每个突变的选择器,然后继续执行速度较慢的querySelectorAll on Success:
const SEL = 'a[data-phonenumber]';
const mo = new MutationObserver(onMutation);
observe();
function onMutation() {
if (document.querySelector(SEL)) {
mo.disconnect();
replaceNumbersWithLinks();
observe();
}
}
function observe() {
mo.observe(document, {
subtree: true,
childList: true,
});
}
function replaceNumbersWithLinks() {
document.querySelectorAll(SEL).forEach((a) => {
a.removeAttribute('data-phonenumber');
const b = a.textContent.replaceAll(' ', '').trim();
if (b) a.href = 'tel:' + b;
});
}
相关文章