[拯救上班族的 Chrome 扩充套件] Chrome Extention 的讯息传接球

Hi 各位大大~
今天要来分享在 Chrome extension 讯息传递的部分,
主要算是官方文件的导读,
我们为什麽需要传递讯息?

官方文件:Since content scripts run in the context of a web page and not the extension, they often need some way of communicating with the rest of the extension.

简单来说就是网页的内容已经不是扩充的一部分,
但他们又很常需要跟扩充去沟通,
基本上有三种用法,但是今天只主要会讲前两个
(第三个我目前没需求使用到)

  1. one-time requests
    如果你只需要传送单一的讯息,可以用两种方式,一个是 runtime.sendMessage , 另一个则是 tabs.sendMessage,它可以让你传 JSON 格式的讯息 , 然後有一个 callback 参数是 option 的,如果你希望他的 response 是你需要 handle 的话可以用这个。
    如果你想从 content script 传送 request 出来可以使用像是以下范例的做法。

    chrome.runtime.sendMessage({greeting: "hello"}, function(response) {
      console.log(response.farewell);
    });
    

    如果你想从 extension 传送到 content script 可以透过以下做法。

    chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
      chrome.tabs.sendMessage(tabs[0].id, {greeting: "hello"}, function(response) {
        console.log(response.farewell);
      });
    });
    

    基本上可以把它拆成两段,第一段是去搜寻目前 tab 的ID ,将第一个拿到的 ID 作为指定的目标,当然你也可以自己把它改成寄送所有页面可参考以下范例。

    chrome.tabs.query({}, function(tabs) {
        const message = {foo: bar};
        for (let i=0; i < tabs.length; ++i) {
            chrome.tabs.sendMessage(tabs[i].id, message);
        }
    });
    

    最後,有传送当然就有接收,你可以在content script 或是 extension 藉由以下范例去接收传送的讯息,如下面范例

    chrome.runtime.onMessage.addListener(
      function(request, sender, sendResponse) {
        console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
        if (request.greeting === "hello")
          sendResponse({farewell: "goodbye"});
      }
    );
    

    官方提醒:Note:

    1. If multiple pages are listening for onMessage events, only the first to call sendResponse() for a particular event will succeed in sending the response. All other responses to that event will be ignored.
    2. The sendResponse callback is only valid if used synchronously, or if the event handler returns true to indicate that it will respond asynchronously. The sendMessage function's callback will be invoked automatically if no handlers return true or if the sendResponse callback is garbage-collected.

    翻译蒟蒻:

    1. 如果有多个页面在监听 onMessage 的 events sendResponse() 只有第一个成功送出回应的会被理,其他都会被忽略QQ
    2. 如果 sendResponse 要被使用非同步的话要在最後 return true ,否则他就只允许你让他被同步的使用。
  2. long-lived connections
    如果你需要较长时间的请求的话可以用这个方式,一样有两种用法,一个是 runtime.connect 另一个则是 tabs.connect ,另外他有可以让你选择该 channel 的名称,让你去区分不同的连线。
    如果是 content script 你可以参考如以下范例,

    const port = chrome.runtime.connect({name: "knockknock"});
    port.postMessage({joke: "Knock knock"});
    port.onMessage.addListener(function(msg) {
      if (msg.question === "Who's there?")
        port.postMessage({answer: "Madame"});
      else if (msg.question === "Madame who?")
        port.postMessage({answer: "Madame... Bovary"});
    });
    

    如果是 extension 的部分其实非常相似如以下范例,

    chrome.runtime.onConnect.addListener(function(port) {
      console.assert(port.name === "knockknock");
      port.onMessage.addListener(function(msg) {
        if (msg.joke === "Knock knock")
          port.postMessage({question: "Who's there?"});
        else if (msg.answer === "Madame")
          port.postMessage({question: "Madame who?"});
        else if (msg.answer === "Madame... Bovary")
          port.postMessage({question: "I don't get it."});
      });
    });
    

以上是今天的内容,
从这边你就可以想像,

今天你透过扩充让使用者在设定一些东西时,想要让画面做一些什麽事情,
比方说充满猫咪,然後异常抖动或是缩放,基本上就是

扩充: 欸欸 插入图片
Content script : 收到! 我插入了... 图片! 阿斯~
扩充: 欸欸 他喝水了
Content script : 收到! 我把插入的... 图片取消了~

以上是今天分享的内容
祝各位连假快乐xD

感谢各位,我们明日再战。

参考文献:

Message passing


<<:  Motion 效果基本项目

>>:  [Angular] Day19. Dependency providers

Day 29 - 使用 Config 为 NestJS 专案拆分不同开发环境

前言 终於来到了第 29 天了,也就是名义上技术篇章的最後一篇了 XDD,到了今天我还真是突然不知道...

D25 - 用 Swift 和公开资讯,打造投资理财的 Apps { 三大法人成交比重 资料分析 }

台湾股市有揭露三大法人当日买进卖出的金额,在市场上会有流派依照这些进出的资讯,调整手上的资金部位。因...

Ruby基本介绍(四)

基本上大叔宅男不是很想放男团K-pop, XD 本篇会提到的 定义方法 回圈(loop) 定义方法 ...

Unity与Photon的新手相遇旅途 | Day28-Unity 发布到IOS手机上

今天内容为教大家如何把Unity专案发布到IPhone或IPad上。 ...