chrome插件开发之封装好用组件-communicator.js

communicator.js

// 存储消息处理器的数组
let messageHandlers = [];

// 设置消息监听器
const setupMessageListener = () => {
    chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
        console.log('Received message:', message, 'from sender:', sender);
        // 调用所有注册的消息处理器
        handleMessage(message, sender, sendResponse);
        return true; // 保持响应通道打开
    });
};

// 处理接收到的消息
const handleMessage = (message, sender, sendResponse) => {
    if (messageHandlers) {
        messageHandlers.forEach((handler) => {
            handler(message, sender, sendResponse);
        });
    }
};

// 发送运行时消息
const sendRuntimeMessage = (message, callback) => {
    console.log('Sending runtime message:', message);
    chrome.runtime.sendMessage(message, (response) => {
        console.log('Received runtime response:', response);
        if (callback) {
            callback(response);
        }
    });
};

// 向指定标签发送消息
const sendTabMessage = (tabId, message, callback) => {
    console.log(`Sending message to tab ${tabId}:`, message);
    chrome.tabs.sendMessage(tabId, message, (response) => {
        console.log(`Received response from tab ${tabId}:`, response);
        if (callback) {
            callback(response);
        }
    });
};

// 注册消息处理器
const registerMessageHandler = (handler) => {
    if (!messageHandlers) {
        messageHandlers = [];
    }
    messageHandlers.push(handler);
};

// 向所有标签发送消息
const sendMessageToAllTabs = (message, callback) => {
    chrome.tabs.query({}, (tabs) => {
        tabs.forEach((tab) => {
            sendTabMessage(tab.id, message, callback);
        });
    });
};

// 向活动标签发送消息
const sendMessageToActiveTab = (message, callback) => {
    chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
        if (tabs.length > 0) {
            sendTabMessage(tabs[0].id, message, callback);
        }
    });
};

// 向背景页发送消息
const sendMessageToBackground = (message, callback) => {
    sendRuntimeMessage(message, callback);
};

// 向内容脚本发送消息
const sendMessageToContentScript = (tabId, message, callback) => {
    sendTabMessage(tabId, message, callback);
};

// 从内容脚本发送消息到后台
const sendMessageFromContentScriptToBackground = (message, callback) => {
    sendRuntimeMessage(message, callback);
};

// 从后台发送消息到内容脚本
const sendMessageFromBackgroundToContentScript = (tabId, message, callback) => {
    sendTabMessage(tabId, message, callback);
};

// 初始化消息监听器
setupMessageListener();

// 导出所有方法
export {
    sendRuntimeMessage,
    sendTabMessage,
    registerMessageHandler,
    sendMessageToAllTabs,
    sendMessageToActiveTab,
    sendMessageToBackground,
    sendMessageToContentScript,
    sendMessageFromContentScriptToBackground,
    sendMessageFromBackgroundToContentScript
};    

1. sendRuntimeMessage

运用场景

在 Chrome 扩展中,当需要在不同组件(如弹出页、后台脚本、内容脚本等)之间进行通信时,如果不涉及特定标签页,就可以使用 sendRuntimeMessage 。例如,弹出页需要向后台脚本发送请求,获取一些全局信息。

用户故事

用户打开 Chrome 扩展的弹出页,点击某个按钮,弹出页需要向后台脚本发送一个请求,获取当前扩展的配置信息。

用户流程图
用户点击弹出页按钮
弹出页脚本检测点击
弹出页使用 sendRuntimeMessage 发送消息
后台脚本接收消息
消息类型是否为获取配置?
后台脚本查询配置信息
后台脚本发送响应
弹出页脚本接收响应
忽略消息
示例代码
// 弹出页脚本 (popup.js)
import { sendRuntimeMessage } from './communicator.js';

document.querySelector('#getConfigButton').addEventListener('click', () => {
    sendRuntimeMessage({ action: 'getConfig' }, (response) => {
        console.log('Received config:', response);
    });
});

// 后台脚本 (background.js)
import { registerMessageHandler } from './communicator.js';

registerMessageHandler((message, sender, sendResponse) => {
    if (message.action === 'getConfig') {
        const config = { theme: 'dark', notifications: true };
        sendResponse(config);
    }
    return true;
});

2. sendTabMessage

运用场景

当需要向特定的标签页发送消息时,例如在后台脚本中,根据用户的操作向某个指定的标签页发送消息,让该标签页的内容脚本执行相应的操作。

用户故事

用户在扩展的管理界面选择了一个特定的标签页,然后点击“刷新内容”按钮,后台脚本需要向该标签页发送消息,让内容脚本刷新页面上的特定内容。

用户流程图
用户点击刷新按钮
管理界面脚本检测点击
管理界面脚本通知后台脚本
后台脚本使用 sendTabMessage 发送消息
内容脚本接收消息
消息类型是否为刷新内容?
内容脚本刷新页面内容
忽略消息
示例代码
// 后台脚本 (background.js)
import { sendTabMessage } from './communicator.js';

// 假设 tabId 是目标标签页的 ID
const tabId = 123;
sendTabMessage(tabId, { action: 'refreshContent' }, (response) => {
    console.log('Response from tab:', response);
});

// 内容脚本 (content.js)
import { registerMessageHandler } from './communicator.js';

registerMessageHandler((message, sender, sendResponse) => {
    if (message.action === 'refreshContent') {
        // 刷新页面内容的逻辑
        console.log('Refreshing content...');
        sendResponse({ status: 'Content refreshed' });
    }
    return true;
});

3. registerMessageHandler

运用场景

用于注册一个回调函数,当接收到消息时,该回调函数会被调用。可以在不同的脚本(如后台脚本、内容脚本、弹出页脚本)中使用,以处理接收到的消息。

用户故事

在内容脚本中,需要处理来自后台脚本或其他组件的消息,通过注册消息处理函数,当接收到特定类型的消息时,执行相应的操作。

用户流程图
消息发送
接收组件接收到消息
是否有注册的消息处理器?
调用注册的消息处理器
消息类型是否匹配?
执行相应操作
忽略消息
示例代码
// 内容脚本 (content.js)
import { registerMessageHandler } from './communicator.js';

registerMessageHandler((message, sender, sendResponse) => {
    if (message.action === 'showAlert') {
        alert(message.data);
        sendResponse({ status: 'Alert shown' });
    }
    return true;
});

4. sendMessageToAllTabs

运用场景

当需要向所有打开的标签页发送消息时,例如在后台脚本检测到某个全局事件(如网络状态变化),需要通知所有标签页的内容脚本更新界面。

用户故事

用户的网络连接从离线变为在线,后台脚本检测到这个变化后,需要通知所有打开的标签页的内容脚本,让它们更新页面上的网络状态提示。

用户流程图
网络状态变为在线
后台脚本检测到变化
后台脚本使用 sendMessageToAllTabs 发送消息
各个内容脚本接收消息
消息类型是否为网络在线?
内容脚本更新网络状态提示
忽略消息
示例代码
// 后台脚本 (background.js)
import { sendMessageToAllTabs } from './communicator.js';

window.addEventListener('online', () => {
    sendMessageToAllTabs({ action: 'networkOnline' }, (response) => {
        console.log('Response from tab:', response);
    });
});

// 内容脚本 (content.js)
import { registerMessageHandler } from './communicator.js';

registerMessageHandler((message, sender, sendResponse) => {
    if (message.action === 'networkOnline') {
        const statusElement = document.getElementById('network-status');
        if (statusElement) {
            statusElement.textContent = 'Online';
        }
        sendResponse({ status: 'Status updated' });
    }
    return true;
});

5. sendMessageToActiveTab

运用场景

当需要向当前活动的标签页发送消息时,例如用户点击扩展的某个功能按钮,需要让当前活动标签页的内容脚本执行相应操作。

用户故事

用户在扩展的弹出页点击“高亮链接”按钮,扩展需要向当前活动的标签页发送消息,让内容脚本将页面上的所有链接高亮显示。

用户流程图
用户点击高亮链接按钮
弹出页脚本检测点击
弹出页脚本使用 sendMessageToActiveTab 发送消息
活动标签页内容脚本接收消息
消息类型是否为高亮链接?
内容脚本高亮页面链接
忽略消息
示例代码
// 弹出页脚本 (popup.js)
import { sendMessageToActiveTab } from './communicator.js';

document.querySelector('#highlightLinksButton').addEventListener('click', () => {
    sendMessageToActiveTab({ action: 'highlightLinks' }, (response) => {
        console.log('Response from active tab:', response);
    });
});

// 内容脚本 (content.js)
import { registerMessageHandler } from './communicator.js';

registerMessageHandler((message, sender, sendResponse) => {
    if (message.action === 'highlightLinks') {
        const links = document.querySelectorAll('a');
        links.forEach((link) => {
            link.style.backgroundColor = 'yellow';
        });
        sendResponse({ status: 'Links highlighted' });
    }
    return true;
});

6. sendMessageToBackground

运用场景

当内容脚本或弹出页脚本需要与后台脚本进行通信时,可以使用该方法。例如,内容脚本检测到页面上的特定元素被加载,需要通知后台脚本进行记录。

用户故事

用户打开一个网页,内容脚本检测到页面上的某个特定广告元素被加载,需要通知后台脚本记录该广告的相关信息。

用户流程图
特定广告元素加载
内容脚本检测到加载
内容脚本使用 sendMessageToBackground 发送消息
后台脚本接收消息
消息类型是否为广告加载?
后台脚本记录广告信息
忽略消息
示例代码
// 内容脚本 (content.js)
import { sendMessageToBackground } from './communicator.js';

const adElement = document.getElementById('specific-ad');
if (adElement) {
    sendMessageToBackground({ action: 'adLoaded', adId: 'ad123' }, (response) => {
        console.log('Response from background:', response);
    });
}

// 后台脚本 (background.js)
import { registerMessageHandler } from './communicator.js';

registerMessageHandler((message, sender, sendResponse) => {
    if (message.action === 'adLoaded') {
        console.log(`Ad ${message.adId} was loaded.`);
        sendResponse({ status: 'Ad info recorded' });
    }
    return true;
});

7. sendMessageToContentScript

运用场景

后台脚本或其他组件需要向特定标签页的内容脚本发送消息时使用。例如,后台脚本在定时任务中需要通知某个标签页的内容脚本进行数据更新。

用户故事

后台脚本有一个定时任务,每隔一段时间需要通知特定标签页的内容脚本更新页面上的股票价格数据。

用户流程图
定时任务触发
后台脚本检测到定时任务
后台脚本使用 sendMessageToContentScript 发送消息
内容脚本接收消息
消息类型是否为更新股票价格?
内容脚本更新页面数据
忽略消息
示例代码
// 后台脚本 (background.js)
import { sendMessageToContentScript } from './communicator.js';

// 假设 tabId 是目标标签页的 ID
const tabId = 456;
setInterval(() => {
    sendMessageToContentScript(tabId, { action: 'updateStockPrices' }, (response) => {
        console.log('Response from content script:', response);
    });
}, 60000);

// 内容脚本 (content.js)
import { registerMessageHandler } from './communicator.js';

registerMessageHandler((message, sender, sendResponse) => {
    if (message.action === 'updateStockPrices') {
        // 更新股票价格数据的逻辑
        console.log('Updating stock prices...');
        sendResponse({ status: 'Stock prices updated' });
    }
    return true;
});

8. sendMessageFromContentScriptToBackground

运用场景

内容脚本在页面上检测到某些事件或状态变化时,需要通知后台脚本进行处理。例如,内容脚本检测到用户在页面上进行了特定的操作,需要通知后台脚本记录日志。

用户故事

用户在网页上填写表单并提交,内容脚本检测到表单提交事件,需要通知后台脚本记录用户的操作信息。

用户流程图
用户提交表单
内容脚本检测到提交
内容脚本使用 sendMessageFromContentScriptToBackground 发送消息
后台脚本接收消息
消息类型是否为表单提交?
后台脚本记录操作信息
忽略消息
示例代码
// 内容脚本 (content.js)
import { sendMessageFromContentScriptToBackground } from './communicator.js';

const form = document.querySelector('form');
if (form) {
    form.addEventListener('submit', () => {
        sendMessageFromContentScriptToBackground({ action: 'formSubmitted', formData: { name: 'John', age: 30 } }, (response) => {
            console.log('Response from background:', response);
        });
    });
}

// 后台脚本 (background.js)
import { registerMessageHandler } from './communicator.js';

registerMessageHandler((message, sender, sendResponse) => {
    if (message.action === 'formSubmitted') {
        console.log('Form submitted with data:', message.formData);
        sendResponse({ status: 'Form submission logged' });
    }
    return true;
});

9. sendMessageFromBackgroundToContentScript

运用场景

后台脚本在处理一些逻辑后,需要向特定标签页的内容脚本发送消息,让内容脚本执行相应的操作。例如,后台脚本接收到服务器的更新通知,需要通知某个标签页的内容脚本更新页面显示。

用户故事

后台脚本接收到服务器推送的新消息通知,需要向特定标签页的内容脚本发送消息,让内容脚本在页面上显示新消息提示。

用户流程图
后台脚本接收到新消息通知
后台脚本处理通知
后台脚本使用 sendMessageFromBackgroundToContentScript 发送消息
内容脚本接收消息
消息类型是否为新消息提示?
内容脚本显示新消息提示
忽略消息
示例代码
// 后台脚本 (background.js)
import { sendMessageFromBackgroundToContentScript } from './communicator.js';

// 假设 tabId 是目标标签页的 ID
const tabId = 789;
// 模拟接收到服务器新消息通知
function onNewMessageReceived() {
    sendMessageFromBackgroundToContentScript(tabId, { action: 'showNewMessage', message: 'You have a new message!' }, (response) => {
        console.log('Response from content script:', response);
    });
}

// 内容脚本 (content.js)
import { registerMessageHandler } from './communicator.js';

registerMessageHandler((message, sender, sendResponse) => {
    if (message.action === 'showNewMessage') {
        const notificationElement = document.createElement('div');
        notificationElement.textContent = message.message;
        document.body.appendChild(notificationElement);
        sendResponse({ status: 'New message notification shown' });
    }
    return true;
});

你可能感兴趣的:(javascript,chrome,前端)