如何编写一个将内容脚本应用于单页应用程序的chrome扩展?

u59ebvdq  于 2021-09-13  发布在  Java
关注(0)|答案(1)|浏览(171)

我目前正在编写一个扩展,通过在元素的href中预先添加tel:并在其周围添加锚定标记(如果需要),可以将与regex模式(特别是德国电话号码的regex模式)匹配的每个字符串转换为可点击链接。
在过去的三天里,我一直在努力让它在我们公司用于联系人的单页应用程序上运行。但是,每当我将扩展加载到浏览器中,然后重新启动浏览器时,它都不会首先应用我的内容脚本。我首先需要在访问后刷新页面。
我正在使用以下文件:
manifest.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
  }
}

background.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',
      },
    ],
  }
);

contentscript.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;
    });
}

正确的方法是什么?当我访问单页应用程序时,如何使其工作?
提前谢谢大家。

whitzsjs

whitzsjs1#

制作 matches 在manifest.json中匹配整个站点:

{
  "content_scripts": [
    {
      "matches": [
        "*://web.examplecontactsapp.de/*"
      ],
      "js": ["src/inject/contentscript.js"]
    }
  ],

使用mutationobserver并使用queryselector检查contentscript.js中每个变异上的选择器(速度适中),然后在成功后继续使用慢速queryselector all:

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;
  });
}

相关问题