find.find()

在標籤頁中搜索文字。

您可以使用此函式搜尋常規的 HTTP(S) 網頁。它搜尋單個標籤頁:您可以指定要搜尋的特定標籤頁的 ID,否則預設搜尋活動標籤頁。它會搜尋標籤頁中的所有框架。

您可以使搜尋區分大小寫,並使其僅匹配整個單詞。

預設情況下,該函式僅返回找到的匹配項數量。透過傳入 includeRangeDataincludeRectData 選項,您可以獲取有關目標標籤頁中匹配項位置的更多資訊。

此函式將結果儲存在內部,因此下次任何擴充套件程式呼叫 find.highlightResults() 時,此次 find 呼叫將突出顯示其結果,直到下次有人呼叫 find()

這是一個非同步函式,返回一個 Promise

語法

js
browser.find.find(
  queryPhrase,       // string
  options            // optional object
)

引數

options 可選

object。一個指定附加選項的物件。它可以包含以下任意屬性,所有屬性都是可選的。

caseSensitive

boolean。如果為 true,則搜尋區分大小寫。預設為 false

entireWord

boolean。僅匹配整個單詞:因此,“Tok”不會在“Tokyo”中匹配。預設為 false

includeRangeData

boolean。在響應中包含 range 資料,它描述了在頁面 DOM 中找到匹配項的位置。預設為 false

includeRectData

boolean。在響應中包含 rect 資料,它描述了在渲染頁面中找到匹配項的位置。預設為 false

matchDiacritics

boolean。如果為 true,則搜尋區分帶重音符號的字母及其基本字母。例如,當設定為 true 時,搜尋“résumé”不會匹配“resume”。預設為 false

tabId

integer。要搜尋的標籤頁的 ID。預設為活動標籤頁。

queryPhrase

string。要搜尋的文字。

返回值

一個 Promise,它將以包含最多三個屬性的物件來 fulfilled。

計數

integer。找到的結果數量。

rangeData 可選

array。如果在 options 引數中指定了 includeRangeData,則將包含此屬性。它以 RangeData 物件陣列的形式提供,每個匹配項一個。每個 RangeData 物件描述了在 DOM 樹中找到匹配項的位置。例如,這可以使擴充套件程式獲取每個匹配項周圍的文字,以便為匹配項顯示上下文。

專案對應於 rectData 中提供的專案,因此 rangeData[i] 描述的匹配項與 rectData[i] 相同。

每個 RangeData 包含以下屬性:

endOffset

匹配項在其文字節點中的結束位置。

endTextNodePos

匹配項結束的文字節點的順序位置。

framePos

包含匹配項的框架的索引。0 對應於父視窗。請注意,rangeData 陣列中物件的順序將按幀索引的順序依次排列:例如,第一系列 rangeData 物件的 framePos 將是 0,下一系列的 framePos 將是 1,依此類推。

起始偏移

匹配項在其文字節點中的開始位置。

startTextNodePos

匹配項開始的文字節點的順序位置。

rectData 可選

array。如果在 options 引數中指定了 includeRectData,則將包含此屬性。它是一個 RectData 物件陣列。它包含搜尋中匹配的所有文字的客戶端矩形,相對於視口左上角。擴充套件程式可以使用此來為結果提供自定義高亮顯示。

每個 RectData 物件包含單個匹配項的矩形資料。它有兩個屬性:

rectsAndTexts

一個包含兩個屬性的物件,兩者都是陣列:

  • rectList:一個物件陣列,每個物件都有四個整數屬性:topleftbottomright。這些描述了相對於視口左上角的矩形。
  • textList:一個字串陣列,對應於 rectList 陣列。textList[i] 中的條目包含由 rectList[i] 中的矩形所界定的匹配項部分。

例如,考慮網頁的一部分如下所示:

Text reading "this domain is established to be used for illustrative examples in documents. You may use this domain in examples without prior coordination or asking for permission." and a "More information" link.

如果搜尋“You may”,則匹配項需要由兩個矩形描述:

This domain is established to be used for illustrative examples in documents. You may use this domain in examples without prior coordination or asking for permission.". The words "you may" are highlighted.

在這種情況下,在描述此匹配項的 RectData 中,rectsAndTexts.rectListrectsAndTexts.textList 都將有 2 個專案。

  • textList[0] 將包含“You ”,而 rectList[0] 將包含其邊界矩形。
  • textList[1] 將包含“may”,而 rectList[1] 將包含邊界矩形。
文字

匹配項的完整文字,“You may”,如上例所示。

示例

基本示例

在活動標籤頁中搜索“banana”,記錄匹配項數量,並突出顯示它們。

js
function found(results) {
  console.log(`There were: ${results.count} matches.`);
  if (results.count > 0) {
    browser.find.highlightResults();
  }
}

browser.find.find("banana").then(found);

在所有標籤頁中搜索“banana”(請注意,這需要“tabs” 許可權或匹配的 主機許可權,因為它訪問 tab.url)。

js
async function findInAllTabs(allTabs) {
  for (const tab of allTabs) {
    const results = await browser.find.find("banana", { tabId: tab.id });
    console.log(`In page "${tab.url}": ${results.count} matches.`);
  }
}

browser.tabs.query({}).then(findInAllTabs);

使用 rangeData

在此示例中,擴充套件程式使用 rangeData 來獲取找到匹配項的上下文。上下文是包含匹配項的節點的完整 textContent。如果匹配項跨越節點,則上下文是所有跨越節點的 textContent 的串聯。

請注意,為簡單起見,此示例不處理包含框架的頁面。要支援這一點,您需要將 rangeData 分組,每幀一組,並在每個框架中執行指令碼。

後臺指令碼

js
// background.js

async function getContexts(matches) {
  // get the active tab ID
  const activeTabArray = await browser.tabs.query({
    active: true,
    currentWindow: true,
  });
  const tabId = activeTabArray[0].id;

  // execute the content script in the active tab
  await browser.tabs.executeScript(tabId, { file: "get-context.js" });
  // ask the content script to get the contexts for us
  const contexts = await browser.tabs.sendMessage(tabId, {
    ranges: matches.rangeData,
  });
  for (const context of contexts) {
    console.log(context);
  }
}

browser.browserAction.onClicked.addListener((tab) => {
  browser.find.find("example", { includeRangeData: true }).then(getContexts);
});

內容指令碼

js
/**
 * Get all the text nodes into a single array
 */
function getNodes() {
  const walker = document.createTreeWalker(
    document,
    window.NodeFilter.SHOW_TEXT,
    null,
    false,
  );
  const nodes = [];
  while ((node = walker.nextNode())) {
    nodes.push(node);
  }

  return nodes;
}

/**
 * Gets all text nodes in the document, then for each match, return the
 * complete text content of nodes that contained the match.
 * If a match spanned more than one node, concatenate the textContent
 * of each node.
 */
function getContexts(ranges) {
  const contexts = [];
  const nodes = getNodes();

  for (const range of ranges) {
    let context = nodes[range.startTextNodePos].textContent;
    let pos = range.startTextNodePos;
    while (pos < range.endTextNodePos) {
      pos++;
      context += nodes[pos].textContent;
    }
    contexts.push(context);
  }
  return contexts;
}

browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
  sendResponse(getContexts(message.ranges));
});

使用 rectData

在此示例中,擴充套件程式使用 rectData 來“遮蔽”匹配項,透過在它們的邊界矩形上方新增黑色 DIV。

Three search results with some texted redacted by black rectangles.

請注意,在許多方面,這是一種糟糕的遮蔽頁面方式。

後臺指令碼

js
// background.js

async function redact(matches) {
  // get the active tab ID
  const activeTabArray = await browser.tabs.query({
    active: true,
    currentWindow: true,
  });
  const tabId = activeTabArray[0].id;

  // execute the content script in the active tab
  await browser.tabs.executeScript(tabId, { file: "redact.js" });
  // ask the content script to redact matches for us
  await browser.tabs.sendMessage(tabId, { rects: matches.rectData });
}

browser.browserAction.onClicked.addListener((tab) => {
  browser.find.find("banana", { includeRectData: true }).then(redact);
});

內容指令碼

js
// redact.js

/**
 * Add a black DIV where the rect is.
 */
function redactRect(rect) {
  const redaction = document.createElement("div");
  redaction.style.backgroundColor = "black";
  redaction.style.position = "absolute";
  redaction.style.top = `${rect.top}px`;
  redaction.style.left = `${rect.left}px`;
  redaction.style.width = `${rect.right - rect.left}px`;
  redaction.style.height = `${rect.bottom - rect.top}px`;
  document.body.appendChild(redaction);
}

/**
 * Go through every rect, redacting them.
 */
function redactAll(rectData) {
  for (const match of rectData) {
    for (const rect of match.rectsAndTexts.rectList) {
      redactRect(rect);
    }
  }
}

browser.runtime.onMessage.addListener((message) => {
  redactAll(message.rects);
});

擴充套件程式示例

瀏覽器相容性