Chrome 浏览器插件获取网页 window 对象(方案三)

前言

最近有个需求,是在浏览器插件中获取 window 对象下的某个数据,当时觉得很简单,和 document 一样,直接通过嵌入 content_scripts 直接获取,然后使用 sendMessage 发送数据到插件就行了,结果发现不是这样滴...

在这里不推荐使用 runtime.executeScript 进行注入,很可能会报错:
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' 'wasm-unsafe-eval' 'inline-speculation-rules' http://localhost😗 http://127.0.0.1😗". Either the 'unsafe-inline' keyword, a hash ('sha256-P5exJBBLYN1KVh+CK9MkXvRal4ZQQu9VaKPvx4JuVLE='), or a nonce ('nonce-...') is required to enable inline execution.

Chrome 浏览器插件获取网页 window 对象(方案一)

Chrome 浏览器插件获取网页 window 对象(方案二)

一、两个文件,通过 CustomEvent 传递消息

1. 方案思路

  1. 新建两个 js 文件,index.jslucky.js
  2. content_scripts 中嵌入 lucky.js 文件和 index.js 文件
  3. index.js 中通过 window.dispatchEvent 派发自定义 custom event 消息
  4. index.js 中通过 addEventListener 监听消息
  5. lucky.js 中通过 addEventListener 监听消息,再通过 dispatchEvent 派发消息
1.1. content_scripts 嵌入 JS 文件

一定要把 lucky.js 文件放在 index.js 文件前面

content_scripts 中添加 lucky.js 的时候需要加上 "world": "MAIN" 字段

world 为枚举类型

  • ISOLATED 默认值
    • 此扩展程序所独有的执行环境
  • MAIN
    • 指定 DOM 的主域,也就是与托管页面的 JavaScript 共享的执行环境
1.2. 方案流程

流程图如下:

2. 获取内容

获取 window 下的 MyBlog 字段

javascript 复制代码
window.MyBlog = {
  juejin: 'https://juejin.cn/user/2409752520033768/posts',
  csdn: 'https://guoqiankun.blog.csdn.net/',
  'chrome-blog': {
    netlify: 'https://gqk-extension.netlify.app/',
    github: 'https://18055975947.github.io/extension/'
  }
}

3. 实现代码

3.1. index.js
javascript 复制代码
/**
 * index 文件发送消息到 lucky.js 文件
 * @param {string} type custom 类型
 * @param {any} data 数据
 */
const indexSendMessageToLucky = async (type, data) => {
  window.dispatchEvent(new CustomEvent('custom-index-type', { detail: { type, data } }))
  return new Promise((res) => {
    function handleResponse(e) {
      const detail = e.detail
      if (detail.type == type) {
        window.removeEventListener('custom-lucky-type', handleResponse)
        return res(detail.data)
      }
    }
    window.addEventListener('custom-lucky-type', handleResponse)
  })
}

/**
 * 发送消息
 */
const sendMessage = () => {
  function getMyBolg() {
    return window.MyBlog
  }
  indexSendMessageToLucky('run-index-fun', {
    function: getMyBolg.toString()
  }).then((res) => {
    console.log('res-->', res)
  }).catch((e) => {
    console.log('e', e)
  })
}
/**
 * 初始化
 */
const init = () => {

  // 插入 button 按钮
  const button = document.createElement('button')
  button.innerText = '获取数据'
  button.id = 'chrome-ext-but'
  document.body.appendChild(button)
  button.onclick = () => {
    sendMessage()
  }
  // 初始化获取数据
  sendMessage()
}

// 判断 window.top 和 self 是否相等,如果不相等,则不注入
if (window.top == window.self) {
  init()
}
3.2. lucky.js
javascript 复制代码
/**
 * 事件监听
 */
window.addEventListener('custom-index-type', async (e) => {
  const { type, data } = e.detail
  switch (type) {
    case 'run-index-fun': {
      const fn = new Function(`return (${data.function})(...arguments)`)
      const rs = await fn(...(data.args ?? []))
      luckySendMessageToIndex(type, rs)
      break
    }
  }
})

/**
 * lucky 文件发送消息到 index.js 文件
 * @param {string} type custom 类型
 * @param {any} data 数据
 */
const luckySendMessageToIndex = (type, data) => {
  window.dispatchEvent(
    new CustomEvent('custom-lucky-type', {
      detail: { type, data, file: 'lucky' }
    })
  )
}
3.3. manifest.json
json 复制代码
{
  "manifest_version": 3,
  "name": "Get Winddow Object Field",
  "version": "1.0",
  "description": "Gets the field under window",
  "content_scripts": [
    {
      "js": [
        "lucky.js"
      ],
      "matches": ["http://localhost:*/*"],
      "run_at": "document_end",
      "world": "MAIN"
    },
    {
      "js": [
        "index.js"
      ],
      "matches": ["http://localhost:*/*"],
      "all_frames": true,
      "run_at": "document_end"
    }
  ],
  "background": {
    "service_worker": "service-worker.js"
  },
  "host_permissions": [
    "http://localhost:*/*"
  ],
  "permissions": [
  ],
  "web_accessible_resources": []
}
3.4. 项目文件结构
shell 复制代码
.
├── index.html
├── index.js
├── lucky.js
├── manifest.json
└── service-worker.js
3.5. 方案效果

在控制台中选择当前插件,即可查看获取的 window 下的 MyBlog 对象

4. 动态获取数据

4.1. 点击按钮
4.2. 数据返回

5. 代码地址

四、总结

1. 文章总结

  1. 获取当前页面下的 window 对象和 document 对象不一样,需要另外的处理方式
  2. 此次提供了三种方案,核心原理都是嵌入当前页面,通过消息派发和接收来获取数据
  3. 第一种通过 postMessage 的方式更为大家熟悉,自定义 Event 相对偏一点
  4. 三种方案的代码我都上传到 gitee/github 上了

2. 代码地址

引用

相关推荐
climber112138 分钟前
【Python Web】一文搞懂Flask框架:从入门到实战的完整指南
前端·python·flask
Watermelo61739 分钟前
极致的灵活度满足工程美学:用Vue Flow绘制一个完美流程图
前端·javascript·vue.js·数据挖掘·数据分析·流程图·数据可视化
门前云梦41 分钟前
ollama+open-webui本地部署自己的模型到d盘+两种open-webui部署方式(详细步骤+大量贴图)
前端·经验分享·笔记·语言模型·node.js·github·pip
Micro麦可乐41 分钟前
前端拖拽排序实现详解:从原理到实践 - 附完整代码
前端·javascript·html5·拖拽排序·drop api·拖拽api
Watermelo61742 分钟前
Web Worker:让前端飞起来的隐形引擎
前端·javascript·vue.js·数据挖掘·数据分析·node.js·es6
Micro麦可乐1 小时前
前端与 Spring Boot 后端无感 Token 刷新 - 从原理到全栈实践
前端·spring boot·后端·jwt·refresh token·无感token刷新
Heidi__1 小时前
前端数据缓存机制详解
前端·缓存
讨厌吃蛋黄酥1 小时前
前端路由双雄:Hash vs History,谁才是React项目的真命天子?
前端·react.js·设计
VillenK1 小时前
vban2.0中table的使用—action封装
前端·vue.js
Hilaku1 小时前
AVIF vs. JPEG XL:2025年,我们该为网站选择哪种下一代图片格式?
前端·javascript·html