谷歌插件开发:Content Script API 详解

我正在参加「掘金·启航计划」

本节将详细介绍 Google Chrome 插件的高级特性之一:Content Script API。作为插件开发的关键组成部分,Content Script API 提供了与网页内容交互的能力,为开发者提供了更多自定义和增强浏览器功能的机会。通过深入了解 Content Script API,您将能够开发出更强大、智能化的插件,为用户带来更好的浏览体验。


课程目录(暂定18节)

后续可持续关注此贴,目录路径都会补上,点击即可跳转前往

  1. 序章:拓展技术池,一起来探索谷歌插件吧!
  2. 插件结构:manifest.json 配置文件详解
  3. 实战开发:创建自己的第一个Google插件
  4. 插件结构:background.js 文件详解
  5. 进阶高级:Browser Action API 详解
  6. 进阶高级:Tabs Manager API 详解
  7. 谷歌插件开发:content.js 文件详解
  8. 谷歌插件开发:Content Script API 详解
  9. 进阶高级:Message Passing API 详解
  10. 进阶高级:Storage API 详解
  11. 进阶高级:File System Access API 详解
  12. 进阶高级:XMLHttpRequest 详解
  13. 进阶高级:Bookmarks API 详解
  14. 进阶高级:Downloads API 详解
  15. 进阶高级:如何使用vue来开发一款Google插件
  16. 实战开发:从零开发一款企业级Google插件(上)
  17. 实战开发:从零开发一款企业级Google插件(下)
  18. 收官之作:总结与展望

一. 基本介绍

Content Script API 是 Google Chrome 插件开发中的一个重要概念。简而言之,Content Script 是一段 JavaScript 代码,可以注入到特定的网页中,与该网页的 DOM 和 JavaScript 环境进行交互。Content Script API 则是用于操作和控制 Content Script 的 API 集合。

通过 Content Script API,插件可以在浏览器加载的网页中执行自定义脚本,修改网页的外观和行为,提供额外的功能和交互方式。这为开发者提供了无限的可能性,可以根据网页的特定需求来定制插件的行为,为用户提供更个性化的浏览体验。

在实际开发场景中,我们可以使用 Content Script API 来实现以下功能,例如:

  1. 修改网页中的内容: 可以使用它来修改网页中的文本、样式、DOM 结构等。
  2. 注入 JavaScript 代码: 可以使用它在网页中注入 JavaScript 代码,实现各种功能和特性。
  3. 与后台页面通信: 可以使用它与后台页面进行通信,传递数据和消息。
  4. 与页面交互: 可以使用它与页面进行交互,实现各种操作和功能。

Content Script API 的作用非常广泛,可以用于实现各种浏览器扩展和功能,例如广告过滤器、自动化测试工具、数据采集工具、样式美化工具等。

运行方式

Content Script API 的运行方式与其他插件组件略有不同。它并不是直接在插件的后台页面或弹出窗口中运行,而是注入到特定的网页中执行。

要使用 Content Script API,首先需要在插件清单文件(manifest.json)中声明 Content Script。在清单文件中,使用content_scripts字段来定义哪些网页将被注入 Content Script。

"content_scripts": [
  {
    "matches": ["https://example.com/*"],
    "js": ["content_script.js"]
  }
]

上述示例中,我们将 Content Script 注入到以 example.com/ 开头的网页中,并指定了要执行的 JavaScript 文件为 content_script.js。

接下来,我们需要编写实际的 Content Script 代码。Content Script 是一段独立的 JavaScript 代码,可以访问网页的 DOM 和 JavaScript 环境,并与之交互。

// 在网页加载完成后执行
window.addEventListener('load', () => {
  // 修改网页标题
  document.title = 'Hello, Content Script!';

  // 在网页上插入一个元素
  const div = document.createElement('div');
  div.textContent = 'This is a Content Script.';
  document.body.appendChild(div);

  // 发送消息给插件的后台页面
  chrome.runtime.sendMessage({ message: 'Hello from Content Script!' });
});

// 监听来自插件的消息
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  console.log('Received message:', message);
});

上述示例中,我们在 Content Script 中修改了网页的标题,向网页中插入了一个

元素,并与插件的后台页面进行了消息通信。

Content Script 的执行时机是在网页加载完成后,但在网页的 DOMContentLoaded 事件之前。这样可以确保 Content Script 在网页完全加载之前就注入并执行,以便进行必要的修改和交互。

但是需要注意的是,Content Script 与网页中的其他 JavaScript 代码是相互独立的,它们运行在不同的执行环境中。这意味着 Content Script 无法直接访问网页中的全局变量和函数,也无法修改网页中已经存在的 JavaScript 代码。

可配置项

它提供了一系列可在manifest.json文件中进行配置的配置项,让开发者能够更灵活地控制 Content Script 的注入和执行方式。

1.匹配规则(Matches)

在声明 Content Script 时,可以使用matches字段指定要注入的网页的 URL 匹配规则。这个规则可以是具体的 URL,也可以使用通配符(*)来匹配一类网页。

"content_scripts": [
  {
    "matches": ["https://example.com/*"],
    "js": ["content_script.js"]
  }
]

上述示例中,我们将 Content Script 注入到以 example.com/ 开头的所有网页中。

2.注入时机(Run At)

通过run_at字段,可以指定 Content Script 的注入时机。可以选择在文档开始加载时注入(document_start)、文档结束加载前注入(document_end)或默认情况下在文档加载完成后注入(document_idle)。

"content_scripts": [
  {
    "matches": ["https://example.com/*"],
    "js": ["content_script.js"],
    "run_at": "document_end"
  }
]

上述示例中,我们将 Content Script 在文档加载完成前注入。

3.多文件注入(Multiple Files)

如果需要注入多个 Content Script 文件,可以在js字段中指定一个文件数组。

"content_scripts": [
  {
    "matches": ["https://example.com/*"],
    "js": ["content_script1.js", "content_script2.js"]
  }
]

4.CSS 注入(CSS Injection)

除了 JavaScript 文件外,Content Script API 还允许注入 CSS 文件来修改网页的样式。

"content_scripts": [
  {
    "matches": ["https://example.com/*"],
    "js": ["content_script.js"],
    "css": ["styles.css"]
  }
]

通过合理配置这些可选项,开发者可以灵活地控制 Content Script 的注入范围、时机和行为,实现更精确的功能定制和用户体验。

需要注意的事项 ⚠️

  1. 权限:需要在插件的 manifest.json 文件中声明权限,才能访问网页的内容。
  2. 跨域访问:由于 Content Script 是在网页的上下文中运行的,所以需要注意跨域访问的问题。
  3. 异步调用:由于它是异步调用的,所以需要使用 Promise 和回调函数处理异步操作。
  4. 页面状态:由于它是在网页的上下文中运行的,所以需要注意页面的状态,避免在页面未加载完成时进行操作。

Content Script API 主要提供了以下内容 :

字段名 描述
chrome.runtime.onMessage.addListener() 用于监听来自扩展程序的后台页面或其他 content script 发送的消息
chrome.extension.getURL() 用于获取扩展程序中指定文件的 URL
document.createElement() 用于在当前页面中创建新的 HTML 元素
window.addEventListener() 用于监听当前页面中的事件,如点击、滚动、键盘按键等
chrome.runtime.executeScript() 在指定的标签页中执行JavaScript代码
chrome.runtime.insertCSS() 向指定的标签页动态注入CSS样式
chrome.tabs.sendMessage() 向指定标签页发送消息并接收响应

二. 主要方法

1. chrome.extension.getURL()

chrome.extension.getURL用于获取插件中的资源文件的URL地址,该方法的作用就是将插件目录下的相对路径转化为完整的URL地址,并返回给调用它的脚本。这样,我们就可以通过该API获取到插件中的任何资源文件,并在网页中进行处理、修改或注入操作。

在Google插件开发中,我们通常会将一些资源文件(例如图标、CSS或JS文件等)放在插件的文件夹中,并在插件运行时动态加载和使用它们。但由于插件的文件夹位置和URL地址可能会随着安装位置和浏览器版本的不同而改变,因此我们不能直接使用相对路径来引用这些资源文件。这时,chrome.extension.getURL()方法就能够派上用场了。

chrome.extension.getURL()方法只有一个参数:path,它表示插件中资源文件的相对路径。该路径必须以斜杠“/”开头,并且相对于插件根目录来指定。

需要注意的是,Chrome插件的安全机制要求所有的资源文件都必须被明确地列在manifest.json文件的"web_accessible_resources"字段中,否则将无法通过chrome.extension.getURL()方法来访问它们。

下面是一个使用chrome.extension.getURL()方法获取插件图标URL地址的示例代码:

// 获取插件图标的URL地址
let iconUrl = chrome.extension.getURL('images/icon.png');
// 将图标添加到网页中
let imgElement = document.createElement('img');
imgElement.src = iconUrl;
document.body.appendChild(imgElement);

该示例代码中,首先使用chrome.extension.getURL('images/icon.png')方法获取插件图标的完整URL地址,然后将其赋值给img元素的src属性,并将该元素添加到网页的body中。这样,我们就成功地向网页中注入了插件图标。

2. chrome.runtime.executeScript()

chrome.runtime.executeScript()用于在指定的标签页中执行JavaScript代码,它的作用是在指定的标签页中执行一段或多段JavaScript代码。在执行脚本时,我们可以选择将代码直接传递给executeScript方法,也可以将脚本文件路径传递给executeScript方法。在执行完毕后,该API可以返回执行结果(例如,如果脚本有返回值,则会将其传递给回调函数)。

在Google插件开发中,我们通常需要向当前或其他标签页注入自定义的JavaScript代码,并与网页内容进行交互。此时,chrome.runtime.executeScript方法就可以派上用场了。

它共有三个参数:

字段名 描述
tabId 要注入代码的标签页ID
details 要执行的代码或脚本文件路径,可以使用code或file字段来设置
callback 执行完毕后的回调函数,该函数会在代码执行完毕后被调用,可以访问脚本返回的任何JavaScript对象

下面是一个使用chrome.runtime.executeScript方法向当前标签页注入JavaScript代码的示例:

// 在当前标签页中注入自定义的JS文件
chrome.runtime.executeScript({file: 'myScript.js'}, function(result) {
  console.log('执行结果:', result);
});

该示例代码中,首先使用chrome.runtime.executeScript方法将"myScript.js"脚本文件注入到当前标签页中,并在回调函数中接收执行结果result并输出到控制台。

3. chrome.runtime.insertCSS()

chrome.runtime.insertCSS()用于向指定的标签页动态注入CSS样式,它的作用是将CSS样式表动态注入到指定的标签页中。我们可以将要注入的CSS样式代码直接传递给该方法,也可以将CSS样式文件的路径传递给该方法。在注入样式后,该API可以返回注入结果。

在Google插件开发中,我们通常需要向网页中注入自定义的CSS样式,来修改页面的外观和布局。此时,chrome.runtime.insertCSS方法就可以派上用场了。

它共有三个参数:

字段名 描述
tabId 要注入样式的标签页ID
details 要注入的样式或样式文件路径,可以使用code或file字段来设置
callback 注入完毕后的回调函数,该函数会在注入完成后被调用,可以访问注入结果的任何JavaScript对象

下面是一个使用chrome.runtime.insertCSS方法向当前标签页注入CSS样式的示例代码:

// 向当前标签页注入自定义的CSS样式
chrome.runtime.insertCSS({code: 'body { background-color: #f00; }'}, function(result) {
  console.log('注入结果:', result);
});

该示例代码中,首先使用chrome.runtime.insertCSS方法将"body { background-color: #f00; }"样式代码注入到当前标签页中,并在回调函数中接收注入结果result并输出到控制台。

4. chrome.tabs.sendMessage()

chrome.tabs.sendMessage()用于向指定标签页发送消息并接收响应,它的作用是将消息发送到指定标签页,并等待接收响应。在发送消息时,我们可以传递一个包含要发送数据的JavaScript对象,而在接收响应时,则需要提供一个回调函数来处理返回的数据。

在Google插件开发中,我们经常需要从Content Script向指定的标签页发送请求或获取数据,以便对网页进行交互。此时,chrome.tabs.sendMessage方法就可以派上用场了。

它共有三个参数:

字段名 描述
tabId 要发送消息的标签页ID
message 要发送的消息内容,可以是任何JavaScript对象
responseCallback 接收响应的回调函数,该函数会在接收到响应时被调用,可以访问响应返回的任何JavaScript对象

需要注意的是,在使用该API时,我们需要先获取目标标签页的ID,然后才能通过chrome.tabs.sendMessage向该标签页发送消息。

下面是一个使用chrome.tabs.sendMessage方法向指定标签页发送消息和接收响应的示例代码:

// 获取当前选项卡ID
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
  // 向当前选项卡发送消息
  chrome.tabs.sendMessage(tabs[0].id, {action: 'getData'}, function(response) {
    console.log('获取到的数据为:', response);
  });
});

该示例代码中,首先使用chrome.tabs.query方法获取当前选项卡的ID,然后在回调函数中使用chrome.tabs.sendMessage方法向该标签页发送一个JavaScript对象{action: 'getData'}作为请求参数,并在接收到响应后将其输出到控制台。


三. 应用示例

根据 Content Script API 提供的 API,我们来实现一个简易的 Google 插件:百度过滤搜索结果,它可以在百度搜索结果页面上添加一个按钮,点击该按钮可以隐藏指定的搜索结果。

下面我们先来看看预览效果:

谷歌插件开发:Content Script API 详解

然后看下我们规划的目录结构

谷歌插件开发:Content Script API 详解

我们先在扩展程序根目录下创建 manifest.json 文件,并添加以下配置:

{
  "name": "百度过滤搜索结果",
  "version": "1.0",
  "manifest_version": 2,
  "description": "Filter Baidu search results.",
  "permissions": [
    "tabs",
    "storage",
    "https://www.baidu.com/*"
  ],
  "background": {
    "scripts": ["background.js"],
    "persistent": false
  },
  "browser_action": {
    "default_popup": "popup.html"
  },
  "content_scripts": [
    {
      "matches": ["https://www.baidu.com/s*"],
      "js": ["content.js"]
    }
  ]
}

其中,“https://www.baidu.com/*”表示插件可以访问baidu.com域名下的所有页面。

然后我们在content.js文件中编写代码实现在搜索结果页面添加「过滤」按钮的功能。以下是具体的代码:

let results = document.querySelectorAll('.result.c-container');

results.forEach((result) => {
  let filterButton = document.createElement('button');
  filterButton.textContent = '过滤';

  result.appendChild(filterButton);

  filterButton.addEventListener('click', () => {
    chrome.runtime.sendMessage({
      type: 'filter',
      url: result.querySelector('h3 a').href
    });

    result.style.display = 'none';
  });
});

chrome.storage.local.get({ filters: [] }, function (data) {
  let filters = data.filters;

  results.forEach((result) => {
    if (filters.some(filter => result.querySelector('h3 a').href.includes(filter))) {
      result.style.display = 'none';
    }
  });
});

具体实现步骤如下:

  1. 使用document.querySelectorAll方法获取所有的搜索结果列表,并将其保存在results变量中。
  2. 遍历每个搜索结果,为其创建一个「过滤」按钮,并将该按钮添加到搜索结果中。
  3. 为每个「过滤」按钮添加一个点击事件监听器,当用户点击该按钮时,向插件的后台页面发送消息,以保存用户选择的过滤条件,并将当前搜索结果隐藏。
  4. 调用chrome.storage.local.get方法获取保存在本地的过滤条件列表,如果搜索结果的链接地址包含任意一个过滤条件,则将该搜索结果隐藏。

需要注意的是,上面的代码只实现了一个基本的搜索结果过滤功能,实际应用中可能还需要对过滤条件进行验证和处理,同时要确保用户数据的安全性和隐私性。

接下来我们在background.js文件中编写代码实现接收来自content.js的消息,并保存用户选择的过滤条件。以下是具体的代码:

// 监听来自content.js的消息
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  if (request.type === 'filter') {
    // 保存用户选择的过滤条件
    chrome.storage.local.get({filters: []}, function(data) {
      let filters = data.filters;
      if (!filters.includes(request.url)) {
        filters.push(request.url);
        chrome.storage.local.set({filters: filters});
      }
    });
  }
});

这段代码的作用是在插件的后台页面监听来自Content Script的消息,并根据消息内容对本地存储进行操作。具体实现步骤如下:

  1. 使用chrome.runtime.onMessage.addListener方法注册一个消息监听器,该监听器会在接收到来自Content Script的消息时被调用。
  2. 在监听器函数中,判断接收到的消息类型是否为'filter'。如果是,则表示Content Script请求保存用户选择的过滤条件。
  3. 调用chrome.storage.local.get方法获取当前存储的过滤条件列表,并将其传递给回调函数。
  4. 在回调函数中,将接收到的过滤条件列表取出并保存到本地存储中。

然后我们在popup.html和popup.js文件中编写代码实现弹出用户设置过滤条件的对话框的功能。以下是具体的代码:

popup.html

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <title>Baidu Filter Search Results</title>
    <style>
      body {
        font-family: Arial, sans-serif;
      }
    </style>
  </head>

  <body>
    <h1>设置过滤条件</h1>
    <p>输入要过滤的关键词:</p>
    <input type="text" id="keyword">
    <button id="save">保存</button>
    <p id="status"></p>
    <script src="popup.js"></script>
  </body>

</html>

popup.js

// 获取保存按钮和状态信息的元素
let saveButton = document.getElementById('save');
let statusText = document.getElementById('status');

// 为保存按钮添加点击事件
saveButton.addEventListener('click', () => {
  // 获取用户输入的关键词
  let keyword = document.getElementById('keyword').value.trim();

  // 如果关键词不能为空
  if (keyword === '') {
    statusText.textContent = '关键词不能为空!';
    return;
  }

  // 将关键词添加到过滤条件中
  chrome.storage.local.get({ filters: [] }, function (data) {
    let filters = data.filters;
    if (!filters.includes(keyword)) {
      filters.push(keyword);
      chrome.storage.local.set({ filters: filters }, function () {
        statusText.textContent = '保存成功!';
      });
    } else {
      statusText.textContent = '该关键词已存在!';
    }
  });
});

以上就是一个完整的使用Content Script API实现的Chrome插件示例。该插件可以自动在百度搜索结果页面中添加「过滤」按钮,并可以根据用户设置的过滤条件隐藏指定的搜索结果。


本节详细介绍了 Google Chrome 插件的高级特性之一:Content Script API。我们首先了解了 Content Script 的概念和作用,它是一段 JavaScript 代码,可以注入到网页中,与网页的 DOM 和 JavaScript 环境进行交互。然后,我们深入探讨了 Content Script API 的运行方式,包括声明 Content Script、编写 Content Script 代码以及执行时机和安全性限制。最后我们用了一个实际的应用示例,让您能更简单地了解 Content Script API 所为我们提供的功能。

希望本节对您理解和使用 Content Script API 提供了帮助。通过深入学习和实践,您可以进一步掌握该API的使用方法,并开发出更加强大和创新的插件。

本节课程源码 📥

链接: pan.baidu.com/s/1n-TJrHy7… 提取码: 5555

原文链接:https://juejin.cn/post/7231704360668020794 作者:黄勇超

(0)
上一篇 2023年5月11日 上午10:36
下一篇 2023年5月11日 上午10:47

相关推荐

发表回复

登录后才能评论