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 对象(方案一)

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

1. 方案思路

  1. 新建两个 js 文件,index.jslucky.js
  2. content_scripts 中嵌入 index.js 文件
  3. index.js 中通过 script 标签,嵌入 lucky.js
  4. index.js 中通过 window.dispatchEvent 派发自定义 custom event 消息;派发消息的内容为一个函数转换的字符串,函数返回的内容则为你需要获取的 window 下的对象值
  5. lucky.js 中通过 addEventListener 监听消息,再通过 dispatchEvent 派发消息;监听到对应的 custom eventtype 的时候,进行参数函数的执行,通过 new Function() 的方式执行,并获取返回值,再进行消息派发到 index.js 文件
  6. index.js 中通过 addEventListener 监听消息拿到对应的值
  7. manifest.json 文件中添加 web_accessible_resources
1.1. 方案流程

流程图如下:

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 = () => {
  const script = document.createElement('script')
  script.src = chrome.runtime.getURL('lucky.js')
  document.head.appendChild(script)

  // lucky.js 加载
  setTimeout(() => sendMessage(), 100)

  // script.onload = () => {
  //   sendMessage()
  // }

  // 插入 button 按钮
  const button = document.createElement('button')
  button.innerText = '获取数据'
  button.id = 'chrome-ext-but'
  document.body.appendChild(button)
  button.onclick = () => {
    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": [
        "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": [
    {
      "resources": ["lucky.js"],
      "matches": ["http://localhost:*/*"],
      "use_dynamic_url": true
    }
  ]
}
3.4. 项目文件结构
shell 复制代码
.
├── index.html
├── index.js
├── lucky.js
├── manifest.json
└── service-worker.js
3.5. 方案效果

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

4. 动态获取数据

4.1. 实现思路
  1. index.js 文件中动态插入 button 按钮到当前页面
  2. 绑定 click 事件,
  3. 点击的时候触发 index.js 文件的派发事件,并进行数据监听
  4. 拿到对应的数据再进行操作
4.2. 点击按钮
4.3. 数据返回

5. 代码地址

参考

相关推荐
鹏北海-RemHusband14 分钟前
从零到一:基于 micro-app 的企业级微前端模板完整实现指南
前端·微服务·架构
LYFlied15 分钟前
AI大时代下前端跨端解决方案的现状与演进路径
前端·人工智能
光影少年19 分钟前
AI 前端 / 高级前端
前端·人工智能·状态模式
一位搞嵌入式的 genius20 分钟前
深入 JavaScript 函数式编程:从基础到实战(含面试题解析)
前端·javascript·函数式
anOnion31 分钟前
构建无障碍组件之Alert Dialog Pattern
前端·html·交互设计
choke23339 分钟前
[特殊字符] Python 文件与路径操作
java·前端·javascript
云飞云共享云桌面41 分钟前
高性能图形工作站的资源如何共享给10个SolidWorks研发设计用
linux·运维·服务器·前端·网络·数据库·人工智能
Deng9452013141 小时前
Vue + Flask 前后端分离项目实战:从零搭建一个完整博客系统
前端·vue.js·flask
威迪斯特1 小时前
Flask:轻量级Web框架的技术本质与工程实践
前端·数据库·后端·python·flask·开发框架·核心架构
wuhen_n1 小时前
JavaScript内置数据结构
开发语言·前端·javascript·数据结构