find.find()
在选项卡中搜索文本。
您可以使用此函数搜索普通的 HTTP(S) 网页。它搜索单个选项卡:您可以指定要搜索的特定选项卡的 ID,或者默认情况下它将搜索活动选项卡。它搜索选项卡中的所有框架。
您可以使搜索区分大小写,并使其仅匹配整个单词。
默认情况下,该函数仅返回找到的匹配项数。通过传入includeRangeData
和includeRectData
选项,您可以获取有关目标选项卡中匹配项位置的更多信息。
此函数在内部存储结果,因此下次任何扩展调用find.highlightResults()
时,将突出显示此 find 调用的结果,直到下次有人调用find()
。
这是一个返回Promise
的异步函数。
语法
browser.find.find(
queryphrase, // string
options // optional object
)
参数
options
可选-
object
. 指定附加选项的对象。它可以采用以下任何属性,所有属性都是可选的区分大小写
-
boolean
. 如果为true
,则搜索区分大小写。默认为false
。 整个单词
-
boolean
. 仅匹配整个单词:因此“Tok”不会在“Tokyo”中匹配。默认为false
。 includeRangeData
-
boolean
. 在响应中包含范围数据,这些数据描述在页面 DOM 的哪个位置找到匹配项。默认为false
。 includeRectData
-
boolean
. 在响应中包含矩形数据,这些数据描述在渲染页面中的哪个位置找到匹配项。默认为false
matchDiacritics
-
boolean
. 如果为true
,则搜索区分重音字母及其基本字母。例如,当设置为true
时,搜索“résumé”不会找到“resume”的匹配项。默认为false
。 tabId
-
integer
. 要搜索的选项卡的 ID。默认为活动选项卡。
queryphrase
-
string
. 要搜索的文本。
返回值
一个Promise
,它将使用包含最多三个属性的对象来实现
计数
-
integer
. 找到的结果数。 rangeData
可选-
array
. 如果在options
参数中给出了includeRangeData
,则将包含此属性。它作为RangeData
对象的数组提供,每个匹配项一个。每个RangeData
对象都描述在 DOM 树的哪个位置找到匹配项。例如,这将使扩展能够获取每个匹配项周围的文本,以便显示匹配项的上下文。这些项目对应于
rectData
中给出的项目,因此rangeData[i]
描述与rectData[i]
相同的匹配项。每个
RangeData
包含以下属性endOffset
-
匹配项在其文本节点中结束位置的序数。
endTextNodePos
-
匹配项结束所在的文本节点的序数。
framePos
-
包含匹配项的框架的索引。0 对应于父窗口。请注意,
rangeData
数组中对象的顺序将与框架索引的顺序依次对齐:例如,rangeData
对象的第一组的framePos
将为 0,下一组的framePos
将为 1,依此类推。 startOffset
-
匹配项在其文本节点中开始位置的序数。
startTextNodePos
-
匹配项开始所在的文本节点的序数。
rectData
可选-
array
. 如果在options
参数中给出了includeRectData
,则将包含此属性。它是一个RectData
对象的数组。它包含搜索中所有匹配文本的客户端矩形,相对于视口的左上角。扩展可以使用它来提供对结果的自定义突出显示。每个
RectData
对象都包含单个匹配项的矩形数据。它有两个属性rectsAndTexts
-
一个包含两个属性的对象,这两个属性都是数组
rectList
:一个对象的数组,每个对象都有四个整数属性:top
、left
、bottom
、right
。这些描述了相对于视口左上角的矩形。textList
:一个字符串数组,对应于rectList
数组。textList[i]
处的条目包含由rectList[i]
处的矩形绑定的匹配项的一部分。
例如,考虑网页的一部分,如下所示
如果您搜索“You may”,则匹配项需要由两个矩形描述
在这种情况下,在描述此匹配项的
RectData
中,rectsAndTexts.rectList
和rectsAndTexts.textList
将分别包含 2 个项目。textList[0]
将包含“You ”,而rectList[0]
将包含其边界矩形。textList[1]
将包含“may”,而rectList[1]
将包含其边界矩形。
文本
-
匹配项的完整文本,在上例中为“You may”。
浏览器兼容性
BCD 表仅在启用 JavaScript 的浏览器中加载。
示例
基本示例
在活动选项卡中搜索“banana”,记录匹配项数并突出显示它们
function found(results) {
console.log(`There were: ${results.count} matches.`);
if (results.count > 0) {
browser.find.highlightResults();
}
}
browser.find.find("banana").then(found);
在所有选项卡中搜索“banana”(请注意,这需要“选项卡”权限或匹配的主机权限,因为它访问tab.url
)
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
拆分为每个框架一组,并在每个框架中执行脚本。
后台脚本
// 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);
});
内容脚本
/**
* 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 来“涂黑”匹配项
请注意,从很多方面来说,这是一种糟糕的页面涂抹方式。
后台脚本
// 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);
});
内容脚本
// 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);
});