(第二章)浏览器插件开发(附源码):内容脚本Content Script的注入方式

847 阅读4分钟

(第二章)浏览器插件开发(附源码):内容脚本Content Script的注入方式

一 Content Scripts的作用

绝大多数插件都需要操作网页的DOM元素,来增强和拓展浏功能。而Content Scripts(内容脚本)是专门用来要操作浏网页DOM的。

二 Content Scripts的注入方式

利用内容脚本操作网页dom,就需要将内容脚本注入到网页中,而注入方式主要分为两种方式:静态注入 动态注入

静态注入

在上一章节中我们一进入到百度首页,网页的背景色就立即变成了红色。 如果我们需要进入到匹配的网页就自动执行内容脚本,那么静态注入就是最好的选择。

manifest.json文件中配置content_scripts进行静态注入

{
  ...
  "content_scripts": [
    {
      "matches": ["https://*.baidu.com/*"],//指定此内容脚本将被注入到哪些页面
      "js": ["scripts/content.js"] // 内容脚本的文件
    }
  ],
  ...
}

content_scripts 还支持以下配置项:

配置项类型说明
matchesArray或string指定此内容脚本将被注入到哪些页面,支持通配符匹配,如需详细了解这些字符串的语法,请参阅匹配模式匹配模式和 glob,去排除网址。
cssArray或string可选。要注入到匹配页面的 CSS 文件列表。这些是 在构建或显示任何 DOM 之前,按照它们在此数组中出现的顺序注入 。
jsArray要注入的JavaScript文件列表,这些文件会被注入到匹配的页面中
run_atrun_at指定脚本注入的时机,可选值:document_start(页面加载开始时)、document_end(DOM加载完成时)、document_idle(页面加载完成后)
all_frames布尔值是否将脚本注入到所有frame中,默认为false
match_about_blank布尔值是否将脚本注入到about:blank页面中,默认为false
worldExecutionWorld指定脚本运行的隔离环境,可选值:ISOLATED(独立环境)、MAIN(主页面环境),默认ISOLATED

动态注入

但是如果并不想一进入到页面就执行Content Scripts,而是在做了一些响应后,再注入执行,就需要进行动态注入。

动态注入无需在manifest.json文件中配置,而通常在Service Worker中使用chrome.scripting.executeScript()进行动态注入,但是在注入之前需要获取注入页面的主机权限,可以通过设置host_permissions或者设置activeTab权限获取临时主机权限。

设置host_permissions
{
  "host_permissions": ["https://*.baidu.com/*"], // 添加需要访问的域名,也可以利用*通配符来进行匹配
}
设置activeTab权限
{
  "permissions": ["scripting", "activeTab"], // 添加scripting和activeTab权限,scripting是脚本注入权限
}

动态注入可以直接注入脚本文件,如果功能简单也可以直接注入函数。

注入脚本文件
// background/background.js
chrome.scripting.executeScript({
  target: {tabId: tab.id}, // 注入到目标标签页
  files: ['scripts/content.js'] //脚本文件路径
})
注入函数
// background/background.js
chrome.scripting.executeScript({
  target: {tabId: tab.id}, // 注入到目标标签页
  func: function() {
    document.body.style.backgroundColor = "orange";
  }
})

三 案例演示

动态注入示例-进入到百度首页后,点击插件图标,将页面背景色改为橙色

四 将内容脚本注入到MAIN环境中

一个浏览器可以安装很多插件,为了不让插件之间和网页页面互相影响,每个内容脚本在自己隔离的世界中,因此内容脚本对自己JavaScript进行更改也不会与页面或其他扩展的内容脚本发生冲突。

例如我们在内容脚本中定义了一个变量

// scripts/content.js
 const contentStr = '这是content脚本中的内容'

我们在网页主环境中打印会显示未定义,而在脚本环境中打印会显示内容

image.png

如果我们想打破这种环境隔离,使网页主环境可以访问脚本的变量,我们可以通过设置worldMAIN来达到目的。

// background/background.js
chrome.scripting.executeScript({
  target: {tabId: tab.id}, // 注入到目标标签页
  files: ['scripts/content.js'], //脚本文件路径
  world: 'MAIN', // 将脚本文件运行在主环境中中
})

x.png