从0开始开发一个chrome插件

202 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情

1、下载demo: 一个来源于官方的基础例子

2、解释一下配置信息:

{ "name": "Getting Started Example", //名字 "description": "Build an Extension!", //描述 "version": "1.0", //版本 "manifest_version": 3, //mainfest版本 2或3 "background": { "service_worker": "background.js" }, //插件权限 "permissions": ["storage", "activeTab", "scripting"], "action": { //插件页面显示 "default_popup": "popup.html", "default_icon": { "16": "/images/get_started16.png", "32": "/images/get_started32.png", "48": "/images/get_started48.png", "128": "/images/get_started128.png" } }, "icons": { //图标 "16": "/images/get_started16.png", "32": "/images/get_started32.png", "48": "/images/get_started48.png", "128": "/images/get_started128.png" }, "options_page": "options.html" //选项功能页,非必须 }

其中name,version.mainfest_version三个属性必不可少;

backgroud 是一个常驻的页面,它的生命周期是插件中所有类型页面中最长的,它随着浏览器的打开而打开,随着浏览器的关闭而关闭,所以通常把需要一直运行的、启动就运行的、全局的代码放在background里面。

3、主要代码:

popup.html

<!DOCTYPE html>
<html>
    <head>
     <title>删除稿件插件</title>   
     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
     <link rel="stylesheet" href="popup.css">
    </head>
    <body>
        <div class="pop-wrap">
            <button id="startDel">删除</button>
        </div>

        <script src="libs/jquery-3.6.0.min.js"></script>
        <script src="popup.js"></script>
    </body>    
</html>

popup.js

// Initialize butotn with users's prefered color
let startDel = document.getElementById("startDel");

// When the button is clicked, inject setPageBackgroundColor into current page
startDel.addEventListener("click", async () => {
  
  let [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
  chrome.scripting.executeScript({
    target: { tabId: tab.id },
    //function: setPageBackgroundColor,
    files :['delbdwk.js'],
  });
});

// The body of this function will be execuetd as a content script inside the
// current page
function setPageBackgroundColor() {
  console.log('执行一些操作...')
}

files属性是执行的业务代码;

1、manifest.json文件说明请参考上一篇文章,这此在文件中新增加了一个属性:

 "content_scripts":[{
        "matches":["http://*/*","https://*/*"],
        "js":[
            "libs/jquery-3.6.0.min.js", //引用的jquery库
            "content_script.js"  //新建js文件用于业务处理
        ],
        "css":["base.css"], //css
        "run_at": "document_end"  //文档加载完成支线
    }],

manifest匹配地址的页面在刷新时会直接执行这里的代码;

2、在content_script.js编码业务处理逻辑: 例如编写一段去广告的js代码,会在页面加载完成后,将页面指定属性隐藏,实现去广告效果;

//去广告
function removeCSDNAd(){
    $('#footerRightAds').hide()
    $('#aw0').hide()
    console.log('隐藏广告')
    $('.hide-preCode-bt').click()
    console.log('点击更多按钮')
}
removeCSDNAd();

3、backgroud.js backgoud.js只能执行和chrome扩展相关的函数,无法操作dom 可以再其中创建自定义菜单:


const menu = {
    menus: [
        {
            id: "main",
            visible: true,
            title: "常用操作",
        },
        {
            id: "open",
            type: "normal",
            visible: true,
            title: "打开必应",
            parentId: "main"
        },
        {
            id: "del",
            visible: true,
            type: "normal",
            title: "执行函数",
            parentId: "main"
        },
    ],
};

function toUrl(info) {
    let url;
    switch (info.menuItemId) {
        case "open":
            url = "https://cn.bing.com";
            chrome.tabs.create({
                url,
            });
            break;
        case "del":
            sendToContent();
            break;
    }
    
}

const createMenu = () => {
    menu.menus.forEach(({ fn, ...data }) => {
        chrome.contextMenus.create(data);
    });
    chrome.contextMenus.onClicked.addListener(toUrl);
};



//安装时 创建菜单
chrome.runtime.onInstalled.addListener(async () => {
   createMenu();
   console.log('创建了菜单')
 
   
})

3、popup.js: popup.js是popup.html打开时加载的js.同样可以操作dom;

4、自定义新打开标签页 在manifest.json中可以自定义标签页:

     "chrome_url_overrides":
     {
         "newtab": "newtab.html"
     },

配置完成后,就可以打开自定义的标签页‘

接着讲一下各个js之间的通信;

backgroud.js是中间商

backgroud.js可以和content_script.js之间相互通信 backgroud.js也可以和popup.js之间相互通信 content_script.js和popup.js之间不能直接通信;

backgroud.js和content_script.js通信:

通信的数据预先存储在本地存储中,方便存取

  • 在backgroud.js中

//监听来自content_script的消息,接收消息并回复
chrome.runtime.onMessage.addListener(function(senderRequest,sender,sendResponse) {//接收到content
    console.log(senderRequest);
    if(senderRequest.fromContent&&senderRequest.fromContent=='getDB'){
        DBdata('get',function(res){//从本地取数据
            console.log(res);
            if(res.LocalDB){
                var LocalDB=res.LocalDB;
                switch(LocalDB.Content){
                    case 'TEST':
                        chrome.tabs.query({
                            active: true, 
                            currentWindow: true
                        }, function(tabs){
                            chrome.tabs.sendMessage(tabs[0].id, {LocalDB: LocalDB});//发送到content		
                        });
                        break;
                  
                    default:
                        break;
                }
            }else{
                chrome.tabs.query({
                    active: true, 
                    currentWindow: true
                }, function(tabs){
                    chrome.tabs.sendMessage(tabs[0].id, {msg: 'no data'});//发送到content		
                });
            }
        });
    }
    sendResponse('已接收')
});

从background.js直接发送消息给content.script.js

//给background发消息
chrome.runtime.sendMessage(chrome.runtime.id, {//当页面刷新时发送到bg
    fromContent: 'getDB'
});
//从数据库取数据发送到content_script.js
function sendToContent(){
    DBdata('get',function(res){
        var LocalDB=res.LocalDB;
        console.log(LocalDB)
        chrome.tabs.query({active: true, currentWindow: true
        }, function(tabs){
            chrome.tabs.sendMessage(tabs[0].id, {LocalDB:LocalDB},function(response){
                console.log(response)
            });//发送到content		
        });
    })
}
  • content_script.js中
//监听background的消息
chrome.runtime.onMessage.addListener(function(senderRequest,sender, sendResponse) {//接收到bg
    console.log('demo已运行');
    var LocalDB=senderRequest.LocalDB;
    console.log(LocalDB);
    if(!!LocalDB){
        console.log(LocalDB.Content);
        switch(LocalDB.Content){
            case 'TEST':
                console.log('收到消息了');
                break;
            case 'content':
                console.log('执行操作');
                del()
                break;
        }
    }else{
        console.log(senderRequest)
    }
    sendResponse('已接收')
});
  • popup.js中

给backgroud.js发消息,并监听background发来的消息


//初始化bgCommunicationPort
window.bgCommunicationPort = chrome.runtime.connect();
//给bg发消息
let startDel = document.getElementById("startDel");
startDel.addEventListener("click", async () => {
  let page_num = $('#page').val()
  bgCommunicationPort.postMessage({//发送到bg,键值可以自由设置
    Content :'content',//说明
    Page_num : page_num,//数据
    step : 0//步骤
  });
})

//打开popup时触发,读取之前存储的参数
$(document).ready(function(){
	bgCommunicationPort.postMessage({fromPopup:'getDB'});//向background发送消息
	bgCommunicationPort.onMessage.addListener(function(receivedPortMsg) {//监听background
		console.log(receivedPortMsg);//这是background发来的内容
		if(receivedPortMsg&&receivedPortMsg.Page_num){
        $('#page').val(receivedPortMsg.Page_num)
		}
	});
});
  • backgroud.js监听popup.js的消息

popup可以通过backgroud.js中转发消息给content_script.js

//监听脚本 监听来自popup的消息 chrome.runtime.onConnect.addListener(function(port) {//接收到popup port.onMessage.addListener(function(receivedMsg) {//监听popup发来的内容receivedMsg if(receivedMsg.fromPopup&&receivedMsg.fromPopup=='getDB'){//如果接收到了getDB,这里读取数据并返回相当于初始化popup页面 DBdata('get',function(res){ port.postMessage(res.LocalDB);//发送到popup }); }else{//如果不是,则说明是收到来自popup手动点击设置的数据,存入以用于popup打开时展示 DBdata('set','',receivedMsg) //发送消息给content_script; sendToContent(receivedMsg)
} }) });