繁体   English   中英

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

[英]How do I write a chrome extension that applies a content script to a Single Page Application?

我目前正在编写一个扩展程序,该扩展程序会将与 RegEx 模式(特别是德国电话号码的 RegEx 模式)匹配的每个字符串转换为可点击的链接,方法是在元素的 href 中添加 tel: 并用如果需要,锚标记。

在过去的三天里,我一直在努力使其适用于我们公司用于联系人的这个单页应用程序。 但是每当我将扩展程序加载到浏览器然后重新启动浏览器时,它首先不会应用我的内容脚本。 我首先需要在访问后刷新页面。

我正在使用以下文件:

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

内容脚本.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匹配 manifest.json 中的整个站点:

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

使用 MutationObserver 并使用中等速度的 querySelector 检查 contentscript.js 中每个突变上的选择器,然后在成功时继续执行慢速 querySelectorAll:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM