怎么从零编写一个 v3 版本的 chrome 浏览器插件实现 CSDN 博客网站的暗黑和明亮主题切换?

简介: 怎么从零编写一个 v3 版本的 chrome 浏览器插件实现 CSDN 博客网站的暗黑和明亮主题切换?

整体效果

流沙插件主题切换演示:https://live.csdn.net/v/228888



源码

https://github.com/kaimo313/quicksand



实现步骤


1、新建 manifest.json 文件

新建一个 chrome 文件夹,在文件夹里新建 manifest.json 文件,在文件里输入下面代码,给插件取名叫流沙,版本是 1.0。

{
    "name": "流沙",
    "version": "1.0",
    "manifest_version": 3
}


a2575516ee184b98bfae499517f9287a.png



这里需要注意的是 manifest_version 必须是整数 2 或者 3,我们这里使用 3。


   2023 年 1 月后 MV2 插件不能再继续更新,MV2 插件将不能在 Chrome 中运行;2023 年 6 月后 即使使用企业策略,MV2 扩展程序也不再在 Chrome 中运行。目前已经不能再发布 MV2 版本的插件,相比于 MV2,MV3 有诸多不同,例如权限控制,API 的变动,发起请求的方式等。


0c0eb7810392406cb3bb2c303305c09f.png



2、将插件添加到扩展程序中

打开 chrome 浏览器,输入 chrome://extensions/,点击加载已解压的扩展程序,选择刚刚新建的 chrome 文件夹即可。


7caff52394be48b695e3f3725067c155.png


选择好文件夹之后,流沙这个插件就被加载到浏览器中了。


578d69f4e229461bbec1076d94fcf623.png


3、配置 service-worker.js

background script 是扩展的事件处理程序;它包含对扩展很重要的浏览器事件的侦听器。它处于休眠状态,直到触发事件,然后执行指示的逻辑。有效的后台脚本仅在需要时加载,并在空闲时卸载。


先在 manifest.json 配置:

{
    "name": "流沙",
    "version": "1.0",
    "manifest_version": 3,
    "background": {
        "service_worker": "service-worker.js"
    }
}


b2a36a210dbd46d797e04f3a43cea967.png


manifest.json 同级新建 service-worker.js 文件,里面添加下面代码

console.log("流沙---> service-worker", chrome);
chrome.action.onClicked.addListener(function () {
    console.log('点击了流沙插件图标');
});


fcf668b9420545bbbaf85383021cfd96.png


然后我们刷新扩展程序页面,发现有个错误

0beb864be274473d889db94add0b39d1.png

错误如下:Uncaught TypeError: Cannot read properties of undefined (reading 'onClicked'),没有onClicked方法


aaa02b3b138b4d6396024d505eec9816.png


chrome.action 文档:必须在 manifest 中声明才能使用此 api

在 manifest 中配置 action

{
    "name": "流沙",
    "version": "1.0",
    "manifest_version": 3,
    "background": {
        "service_worker": "service-worker.js"
    },
    "action": {}
}


刷新清除掉错误之后,点击 Service Worker,就可以看到打印的日志

78664b82d941404ca377069251fc5c39.png


点击右上角的流沙插件,就会打印日志出来。

7ea5ae80d7cb4c75bea06da246f49859.png


如果没有这个图标的可以添加上来。

2ac1655193074604aa35019e97d14af2.png



4、实现点击插件图标切换主题 icon

manifest.json 配置

{
    "name": "流沙",
    "version": "1.0",
    "manifest_version": 3,
    "description": "用于 CSDN 博客网站的暗黑和明亮主题切换",
    "author": "kaimo",
    "background": {
        "service_worker": "service-worker.js"
    },
    "icons": {
        "16": "icons/logo.png",
        "48": "icons/logo.png", 
        "128": "icons/logo.png"
    },
    "action": {
        "default_icon": {
            "32": "icons/popup_light_32.png"
        },
        "default_title": "流沙:明亮模式"
    }
}


service-worker.js 添加代码

console.log("流沙---> service-worker", chrome);
let themeType = "light";
chrome.action.onClicked.addListener(function () {
    console.log('点击了流沙插件图标');
    // 修改初始值
    themeType = themeType === "light" ? "dark" : "light";
    chrome.action.setIcon({
        path: "icons/popup_" + themeType + "_32.png"
    });
    chrome.action.setTitle({
        title: themeType === "light" ? "流沙:明亮模式" : "流沙:暗黑模式"
    });
});


添加 icons 文件夹跟图片

32bfa452ea634d46ada01720b1c17788.png


效果如下:

6fdeb3c2680a424cbd3e5124e37bf135.png


流沙:明亮模式

753a8655fc314aa89aecd972edfb120c.png


点击切换到流沙:暗黑模式

cefd9eec57634344a1b2032db23f04fe.png



5、让 CSDN 的网页加载插件

先匹配 csdn 网站,在 manifest.json 里添加 content_scripts 的配置

"content_scripts": [
    {
        "matches": ["https://*.blog.csdn.net/*"],
        "js": ["content-script.js"]
    }
]


然后新建 content-script.js 文件,添加代码

alert("匹配到了 CSDN 博客网站")


测试效果,访问 csdn 博客网站的时候,就会弹出。其他网址就不会。

6cf55b3b2a1745e7a782ed946750fa42.png



6、插件里实现样式主题的切换

我们发现 id 为 userSkin 的 dom 元素的类不同可以显示不同的主题的效果。

暗黑主题效果:skin-blackwhale user-skin-Black

53c98f1bda0041a2bec6b66a64691224.png


明亮主题效果:skin-yellow user-skin-White

466dffcf9b894966a35f04a6d5a86056.png


具体代码如下:

manifest.json 文件

{
    "name": "流沙",
    "version": "1.0",
    "manifest_version": 3,
    "description": "用于 CSDN 博客网站的暗黑和明亮主题切换",
    "author": "kaimo",
    "background": {
        "service_worker": "service-worker.js"
    },
    "icons": {
        "16": "icons/logo.png",
        "48": "icons/logo.png", 
        "128": "icons/logo.png"
    },
    "action": {
        "default_icon": {
            "32": "icons/popup_light_32.png"
        },
        "default_title": "流沙:明亮模式"
    },
    "content_scripts": [
        {
            "matches": ["https://*.blog.csdn.net/*"],
            "js": ["content-script.js"]
        }
    ],
    "permissions": ["storage", "tabs"]
}


service-worker.js 文件

console.log("流沙---> service-worker", chrome);
// 设置主题类型
function setThemeType(type) {
    chrome.storage.local.set({ theme: type }, () => {
        console.log('设置主题模式为:', type);
    });
}
// 通过 tabs 发送消息改变主题类型
// tabs api,必须被注册在 manifest 的 permissions 字段中给插件使用,这里不然获取不到 url。
function changeThemeByTabs(themeType){
    chrome.tabs.query({}, tabs => {
        console.log("获取 tabs", tabs);
        for (var i = 0; i < tabs.length; i++) {
            console.log(`tabs[${i}].url`, tabs[i].url);
            try {
                const location = new URL(tabs[i].url);
                const host = location.host;
                console.log(host, host.includes("blog.csdn.net"));
                if (host.includes("blog.csdn.net")) {
                    console.log(tabs[i].id, tabs[i], themeType);
                    // 向选项卡发送消息
                    chrome.tabs.sendMessage(tabs[i].id, {
                        theme: themeType
                    }, response => {
                        // 将打印出"接收到主题切换";
                        console.log(response);
                    });
                }
            }
            catch (e) {
                console.error("报错--->", e);
            }
        }
    });
}
// 添加插件监听被安装事件
// 在 onInstalled 监听器内部,扩展使用 storage API 设置一个值。这将允许多个扩展组件访问该值并进行更新。
// 大部分 API,包括 storage api,必须被注册在 manifest 的 permissions 字段中给插件使用。
chrome.runtime.onInstalled.addListener(() => {
    console.log("插件已安装");
    // 设置主题类型
    setThemeType("light");
});
// 添加图标点击事件监听
chrome.action.onClicked.addListener(() => {
    console.log('1、点击了流沙插件图标');
    // 获取主题类型
    chrome.storage.local.get(["theme"], res => {
        console.log("2、缓存的theme", res);
        let { theme } = res;
        // 修改初始值
        theme = theme === "light" ? "dark" : "light";
        console.log("3、切换 theme 为:", theme);
        // 设置图标
        chrome.action.setIcon({
            path: "icons/popup_" + theme + "_32.png"
        });
        // 设置title
        chrome.action.setTitle({
            title: theme === "light" ? "流沙:明亮模式" : "流沙:暗黑模式"
        });
        // 设置主题类型
        setThemeType(theme);
        // 通过 tabs 发送消息改变主题类型
        changeThemeByTabs(theme);
    });
});


content-script.js 文件

console.log("流沙---> content-script", chrome);
// 设置明亮主题
function setLightThemes() {
    document.getElementById("userSkin").className = "skin-yellow user-skin-White";
}
// 设置暗黑主题
function setDarkThemes() {
    document.getElementById("userSkin").className = "skin-blackwhale user-skin-Black";
}
// 切换主题
function switchThemes(type = "light") {
    if(type === "dark") {
        setDarkThemes();
    } else {
        setLightThemes();
    }
}
// 初始化设置
chrome.storage.local.get(['theme'], res => {
    let { theme } = res;
    console.log("初始化设置 theme--->", theme);
    switchThemes(theme);
});
// 监听消息
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
    console.log("监听消息--->", request, sender, sendResponse);
    // 接收信息返回给发送方
    sendResponse("接收到主题切换");
    const { theme } = request;
    switchThemes(theme);
});



说明

目前这里只实现了博客首页的部分内容样式,感兴趣的可以自己研究完善。

另外就是打包扩展程序 crx 文件的生成。第一次可以不用选私有秘钥 .pem 文件。

acaf94bd55c246f5b2cb4e6ce6472f73.png


浏览器会自动生成的

d07d834b78d84d27b79c89d9ad940624.png


确定就会生成,不过这个 crx 不能直接放到扩展程序里使用。

3bdabe9648654578a765b088d6e28a1f.png

该扩展程序未列在 Chrome 应用商店中,并可能是在您不知情的情况下添加的。


82836e9e8dee4f3f89d30dbe118b35ba.png



参考 manifest.json 所有配置项

官网中给出所有配置项

  {
  // Required - 通俗易懂
  "manifest_version": 3,
  "name": "My Extension",
  "version": "versionString",
   // 『重点』action配置项主要用于点击图标弹出框,对于弹出框接受的是html文件
  "action": {
     "default_title": "Click to view a popup",
     "default_popup": "popup.html"
   }
  // 通俗易懂
  "default_locale": "en",
  "description": "A plain text description",
  "icons": {...},
  "author": ...,
  // 『重点』下面将出现的background.js 配置service work
  "background": {
    // Required
    "service_worker": "service-worker.js",
  },
    // 『重点』下面将出现content_script.js 应用于所有页面上下文的js
  "content_scripts": [
     {
       "matches": ["https://*.nytimes.com/*"],
       "css": ["my-styles.css"],
       "js": ["content-script.js"]
     }
   ],
    // 使用/添加devtools中的功能
  "devtools_page": "devtools.html",
    /**
    * 三个permission
    * host_permissions - 允许使用扩展的域名
    * permissions - 包含已知字符串列表中的项目 【只需一次弹框要求允许】
    * optional_permissions - 与常规类似permissions,但由扩展的用户在运行时授予,而不是提前授予【安全】
    * 列出常见选项
    * {
    *   activeTab: 当扩展卡选项被改变需要重新获取新的权限
    *   tabs: 操作选项卡api(改变位置等)
    *   downloads: 访问chrome.downloads API 的权限 便于下载但还是会受到跨域影响
    *   history: history api权限
    *   storage: 访问localstorage/sessionStorage权限
    * }
    */
  "host_permissions": ["http://*/*", "https://*/*"],
  "permissions": ["tabs"],
  "optional_permissions": ["downloads"],
    // 内部弹出可选页面 - 见fehelper操作页
  "options_page": "options.html",
  "options_ui": {
    "chrome_style": true,
    "page": "options.html"
  },
}




目录
相关文章
|
4月前
|
数据采集 人工智能 程序员
PHP 程序员如何为 AI 浏览器(如 ChatGPT Atlas)优化网站
OpenAI推出ChatGPT Atlas,标志AI浏览器新方向。虽未颠覆现有格局,但为开发者带来新机遇。PHP建站者需关注AI爬虫抓取特性,优化技术结构(如SSR、Schema标记)、提升内容可读性与语义清晰度,并考虑未来agent调用能力。通过robots.txt授权、结构化数据、内容集群与性能优化,提升网站在AI搜索中的可见性与引用机会,提前布局AI驱动的流量新格局。
232 8
|
5月前
|
Web App开发 人工智能 IDE
从痛点到解决方案:为什么我开发了Chrome元素截图插件
传统的截图方式要么截取整个页面然后手动裁剪,要么使用浏览器自带的截图功能,但效果都不理想。特别是当内容包含SVG元素或复杂样式时,截图质量和速度、便捷性往往不尽如人意。
263 4
|
5月前
|
Web App开发 人工智能 前端开发
产品发布策略:如何让Chrome插件在竞争激烈的市场中脱颖而出
Chrome Web Store每天新增很多个插件。插件刚发布,用户只有我自己,如何在这样的红海市场中找到自己的位置,是我一直在思考的问题。
213 0
|
7月前
|
机器学习/深度学习 人工智能 文字识别
浏览器AI模型插件下载,支持chatgpt、claude、grok、gemini、DeepSeek等顶尖AI模型!
极客侧边栏是一款浏览器插件,集成ChatGPT、Claude、Grok、Gemini等全球顶尖AI模型,支持网页提问、文档分析、图片生成、智能截图、内容总结等功能。无需切换页面,办公写作效率倍增。内置书签云同步与智能整理功能,管理更高效。跨平台使用,安全便捷,是AI时代必备工具!
576 8
|
运维 Prometheus 监控
如何在测试环境中保持操作系统、浏览器版本和服务器配置的稳定性和一致性?
如何在测试环境中保持操作系统、浏览器版本和服务器配置的稳定性和一致性?
|
监控 供应链 前端开发
浏览器拨测:将网站护航的阵地再前推一米
近年来,针对网站的攻击形式愈发多样,手段也变得更加隐蔽,使用浏览器拨测来监控服务的整个生命周期有助于及时发现攻击,保护核心业务链路不受损。阿里云监控浏览器拨测使用真实的浏览器进行拨测,通过提供丰富的断言能力和脚本录制能力护航服务的全生命周期和核心业务链路,助力开发者更好地监控服务的可用性,消除潜在风险。
536 124
浏览器拨测:将网站护航的阵地再前推一米
|
9月前
|
Web App开发 人工智能 JavaScript
一键三连不求人!用 CodeBuddy 写个浏览器插件自动点赞、评论、收藏
本文介绍了一款通过 CodeBuddy AI 工具开发的浏览器插件,可自动完成“点赞、评论、收藏”三连操作。作者从需求出发,分四步实现:搭建基础框架、指定目标网页、解析内容并模拟点击事件,最后加载验证插件。借助 CodeBuddy 自动生成代码,整个过程高效便捷,大幅提升用户体验。此工具不仅节省手动操作时间,还为自动化任务提供了新思路,适合热爱技术与效率提升的网页冲浪者尝试。
|
Web App开发 人工智能 JSON
AutoMouser:AI Chrome扩展程序,实时跟踪用户的浏览器操作,自动生成自动化操作脚本
AutoMouser是一款Chrome扩展程序,能够实时跟踪用户交互行为,并基于OpenAI的GPT模型自动生成Selenium测试代码,简化自动化测试流程。
946 17
AutoMouser:AI Chrome扩展程序,实时跟踪用户的浏览器操作,自动生成自动化操作脚本
|
人工智能 程序员 测试技术
AI编程:Coze + Cursor实现一个思维导图的浏览器插件
本文是小卷关于AI编程工具学习的第3篇文章,通过开发一个思维导图生成工具,详细介绍了AI编程的完整流程。从需求分析、插件选择(如Coze的TreeMind),到创建测试工作流、发布API,再到整合API和开发浏览器插件,最终实现了用户选中文字后生成思维导图的功能。文章展示了如何利用现有工具高效开发,并总结了AI编程的优势与未来趋势。
1341 14

热门文章

最新文章