且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Google Chrome 扩展程序 - 架构问题

更新时间:2023-12-05 20:18:22

我将尝试逐步解释我认为这样做的好方法.这并不意味着它是***的方法,它只是一种推荐的方法:)

I will try to explain in steps what I think the nice way of doing this. It doesn't mean it is the best way, it just a recommended way :)

如果我正确理解了问题,您希望在网站上显示一个弹出窗口.根据用户在弹出窗口中的选择,网站 DOM 将被修改.同样,您希望弹出窗口接收远程数据.

If I understand the question correctly, you would like to show a popup on the website. Based on what the user chooses in the popup, the websites DOM will be modified. As well, you would like the popup to receive remote data.

从上面的要求,你很快就会发现需要以下几点:

From the above requirements, you will quickly find out that the following is required:

  • 内容脚本 - 因为您需要直接与 DOM 通信.
  • 后台页面 - 您需要一个地方来执行外部 XHR 请求(与远程通信服务器).
  • 消息传递 - 在内容脚本和后台页面之间进行通信.
  • Content Script - Because you would need to communicate to the DOM directly.
  • Background Pages - You need a single place to do external XHR requests (to communicate to a remote server).
  • Message Passing - To communicate between the Content Script and the Background Page.

通过使用消息传递机制,您将能够在两个不同的世界(上下文菜单和背景页面)之间传递数据.每当您想调用远程服务时,您都将通过 Messaging 进行请求.下面,我将解释一路走来的每一步.

By using Message Passing mechanisms, you will be able to pass data between two different worlds (Context Menus, and Background Page). Whenever you want to call a remote service, you will request that through Messaging. Below, I will explain each step along the way.

您的弹出窗口只是一个您在 JavaScript 中动态创建的普通div"元素.类似于以下内容:

Your popup will just be a normal "div" element that you dynamically create in JavaScript. Something like following:

var overlayDOM= document.createElement('div');
... add your stuff to overlayDOM
document.body.appendChild(overlayDOM);

或者您可以使用 iframe 来保留样式.使用 CSS 技术,您可以适当地设置样式以使其看起来像一个弹出窗口.您可以通过使用绝对定位或沿着这些路线使用任何花哨的东西来做到这一点.

Or you can use an iframe, to preserve the style. Using CSS techniques, you can style it appropriately to look like a popup. You can do this by using absolute positioning or anything fancy along those lines.

现在有两种使用内容脚本的方法.您必须问自己的问题如下:

Now there are two ways to use content scripts. The questions that you have to ask yourself is the following:

  • 用户是否会从浏览器进程中激活该弹出窗口?例如,弹出窗口是否会从任何扩展 UI(上下文菜单、页面操作、浏览器操作、特定事件等)以编程方式显示.

  • 弹出窗口将始终在 DOM 上可见,无需用户干预即可使其可见.

如果您选择前者,则可以使用标签executeScript 功能.这非常简单,您需要做的就是提供要注入 DOM(网站)的代码或 JavaScript 文件.例如:

If you choose the former, then you can use the tabs executeScript functionality. It is pretty straight forward, all you need to do is supply the code or the JavaScript file that you want to inject to the DOM (Website). For example:

chrome.tabs.executeScript(tabId, {file: 'popup_overlay.js'});

如果您打算选择后者(弹出窗口始终在页面上可见).您可以通过在 manifestpopup_overlay.js 将其注入每个页面/a>.

If you planned to choose the latter (the popup always visible on the page). You can inject that popup_overlay.js in every page by defining it in the manifest.

"content_scripts": [
   {
     "matches": ["http://www.google.com/*"],
     "css": ["mystyles.css"],
     "js": ["popup_overlay.js"]
   }
],

背景页面

后台页面将具有权限,以便它可以与远程数据库进行通信.您需要做的第一件事是通过 manifest 提供正确的权限.请务必查看匹配模式,以确保您的权限尽可能受到限制.

Background Page

The background page will have permission so that it can communicate to the remote database. The first thing you need to do is supply the correct permissions via manifest. Make sure you look at the Match Patterns to make sure your permission is as limited as possible.

"permissions": [
  "tabs",
  "http://www.mywebsite.com/"
],

设置权限后,您可以通过XmlHttpRequests (XHR) 与远程服务通信.创建使用 XHR 的 JavaScript 服务 API,您可以随意使用任何设计.我个人喜欢使用 JavaScript 对象来组织我的代码.您的后台页面将可以访问您创建的那些实例化服务 API,并且您可以在扩展程序的整个生命周期中使用这些 API.

Once you setup the permissions, you can communicate to the remote service via XmlHttpRequests (XHR). Create your JavaScript service API that uses XHR, feel free to use any design you please. I personally like to use JavaScript objects to organize my code. Your background page will have access to those instantiated service API that you create and that you can use throughout the lifetime of your extension.

// Lives in the Background Page
var service = new RemoteService();

消息传递

如上所述,消息传递用于允许内容脚本和后台页面之间的通信.在您的情况下,您希望弹出窗口从后台页面获取一些数据(因为这是您的 JS 对象所在的位置)并将结果返回.当您获得这些结果并将它们显示在页面上时,因为您已经与 DOM 处于同一个世界.

Message Passing

As explained above, Message Passing is used to allow communication between the Content Script and the Background page. In your case, you want the popup to grab some data from the background page (since that is where your JS object lives) and return the results back. When you get those results and display them on the page since your already in the same world as the DOM.

您首先需要设置后台页面来接收请求,这是您设置请求侦听器的方法:

You first need to setup the background page to receive requests, this is how you setup the request listener:

chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
  if (request.method == 'GetUserList')
    sendResponse({result: db.getGetUserList()});
  else if (request.method == 'GetUser')
    sendResponse({result: db.getGetUser(request.username)});
  else
    sendResponse({}); // snub them.
});

您可以使上述更有趣,但为了解释起见,我遵循消息传递 文档,它完美地解释了它.正如你在上面看到的,我们正在为扩展请求创建一个监听器.您在侦听器中处理请求.正如您所注意到的,您也可以发回响应.在上面的例子中,我们为我们请求的方法发回了适当的结果.

You can make the above fancier, but for the sake of explaining, I am following the Message Passing document, which explains it perfectly. As you see above, we are creating a listener for extension requests. You handle the request within the listener. As you noticed, you can send back a response too. In the above case we are sending back the appropriate result for the method we are requesting.

在您的内容脚本中,您可以轻松地将请求发送到后台页面:

In your content script you can easily send the request to the background page:

// Retrieve the username called mohamedmansour. Continuation from above.
chrome.extension.sendRequest({method: 'GetUser', username: 'mohamedmansour'}, function(response) {
  console.log(response.result);
});

在上面的代码片段中,我们从内容脚本向扩展程序发送了一个请求,以获取mohamedmansour"的用户数据.然后在控制台打印结果.

In the code snippet above, we are sending a request back to the extension from the Content Script to get the user data for "mohamedmansour". Then the result is printed in the console.

一旦您开始思考消息传递,您就会注意到来回发送 JSON 消息是多么容易.

Once you get your mind around Messaging, you will notice how easy it is for sending JSON messages back and fourth.

希望有帮助!