Отправить сообщение на фоновую страницу, обновить html, а затем отобразить его на вкладке

#javascript #html #google-chrome-extension

#javascript #HTML #google-chrome-расширение

Вопрос:

У меня есть расширение Chrome, в котором пользователь вводит некоторую информацию, и оно генерирует отчет. Теперь, конечно, этот отчет будет отличаться каждый раз в зависимости от того, что ввел пользователь.

Чего я хочу добиться, так это того, чтобы мое расширение сообщало:

Привет, мистер фоновая страница. Вот необходимая вам информация, теперь создайте некоторый html на основе того, что я вам дал, и покажите его пользователю.

Вот manifest.json , который я использую:

 {
  "manifest_version": 2,

  "name": "XXXX",
  "description": "XXXX",
  "version": "1.0.0",
  "permissions": ["storage", "tabs"],
  "options_page": "settings.html",

  "background":
  {
    "page": "background.html"
  },

  "content_scripts":
  [
    {
      "matches": ["<all_urls>"],
      "js": ["js/jquery-3.1.1.min.js", "js/bootstrap.min.js", "js/main.js", "js/background.js"],
      "css": ["css/bootstrap.min.css", "css/font-awesome.min.css"]
    }
  ],

  "browser_action": {
    "default_icon": "icon.png",
    "default_popup": "popup.html"
  },
  "icons": { "128": "logo.png" }
}
  

Вот мой background.html

 <html>
<body>
    <script src="js/jquery-3.1.1.min.js"></script>
    <script src="js/bootstrap.min.js"></script>
    <script src="js/background.js"></script>
</body>
</html>
  

И вот мой background.js

 $(document).ready(function() {
    chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
        $("body").html(msg.message);
        console.log("Message from: "   msg.message);
    });
});
  

Теперь, когда пользователь нажимает кнопку на моем расширении, я использую следующий код для отправки сообщения:

 $("#generate").click(function() {
    chrome.tabs.create({url: 'background.html'});
    chrome.runtime.sendMessage({
        message: "Sample message."
    });
});
  

Теперь я ожидал, что моя background.html страница откроется, а затем тело страницы изменится в зависимости от того, какое сообщение было отправлено, но это не работает.

Есть идеи?

Ответ №1:

Вы совершаете огромную концептуальную ошибку, пытаясь использовать ту же страницу для фона и для отображения чего-либо. Это может привести к очень непредсказуемому поведению.

По сути, вы пытаетесь открыть вкладку с помощью background.html и каким-то образом ожидаете, что это будет «та самая» фоновая страница. Это так не работает — вы открываете новый экземпляр того же документа. Представьте, что вы открываете одну и ту же веб-форму на двух вкладках — вы не ожидаете, что они будут отражать текст, введенный в поля.

Кроме того, накоплено много ошибок в отношении взаимодействия всплывающих страниц с открывающимися вкладками.

Итак, план действий:

  1. Если вам действительно нужно, чтобы фрагмент кода выполнялся на (постоянно невидимой) фоновой странице, назовите его идиоматически background.js и переключитесь на scripts определение фоновой страницы в стиле:

     "background": {
      "scripts": ["background.js"]
    }
      

    Также рассмотрите возможность использования страниц событий.

  2. Все, что вы используете для отображения отчета, не должно вызываться background ради вашего здравомыслия. Переименуйте его report.html / report.js .

  3. В вашем всплывающем коде ваша ошибка № 1 — это выбор времени. Вы открываете страницу, которая должна прослушать ваше сообщение, но не ждете, пока оно станет готовым к прослушиванию. Вам следует использовать обратный вызов tabs.create , если вы хотите убедиться, что страница действительно открыта и готова.

     chrome.tabs.create({url: "report.html"}, function(tab) {
      // Okay, now it's ready, right? Right?..
      chrome.runtime.sendMessage(/*...*/);
    });
      
  4. Однако это не решит проблему, поскольку открытие новой вкладки по умолчанию фокусирует ее (что, по-видимому, вам и нужно), что немедленно приводит к закрытию всплывающего окна. Вы ничего не можете сделать, чтобы предотвратить это, как только вкладка сфокусирована. Но это означает, что ваше сообщение не будет отправлено: всплывающее окно будет уничтожено до того, как это произойдет.

    Итак, не полагайтесь на обмен сообщениями. Предположительно, вы можете сохранить любые данные, на которых основан ваш отчет, в хранилище. Итак, сначала установите его, затем откройте страницу отчета, где вы считываете данные и создаете отчет.

     // Popup
    chrome.storage.local.set({foo: bar}, function() {
      // Storage is updated, it's showtime!
      chrome.tabs.create({url: "report.html"});
      // And now, we die, inevitably. Goodbye, cruel world.
    });
    
    // Report
    chrome.storage.local.get("foo", function(data) {
      // Oh, what joy is to have data.foo in here!
    });
      

Комментарии:

1. На самом деле, background.js изначально был вызван test.js , я забыл переименовать его ради этой темы. В любом случае, спасибо вам за эту информацию!

2. Кроме того, chrome.storage.local означает ли это, что эти данные впоследствии уничтожаются в отличие от chrome.storage.sync ?

3. Нет, это означает, что оно остается на вашем компьютере, вместо того, чтобы пытаться воспроизвести его через авторизованный аккаунт Google.

4. Я вижу. Спасибо!