Jak już zauważyłeś, nie możesz wysyłać danych bezpośrednio do okna podręcznego, gdy jest ono zamknięte. Przesyłasz dane na stronę w tle.
Następnie, po otwarciu popup, chcesz danych tam. Jakie są opcje?
Uwaga: ta odpowiedź da złą poradę, a następnie poprawi ją. Ponieważ OP się uczy, ważne jest, aby pokazać proces myślenia i burzę.
Pierwsze rozwiązanie, które przychodzi na myśl, to: spytaj stronę w tle, ponownie używając wiadomości. Wczesne ostrzeżenie: to nie zadziała lub będzie działać słabo
Po pierwsze, ustal, czy mogą występować różne typy wiadomości. Modyfikując swój aktualny kod wiadomości:
// content.js
chrome.runtime.sendMessage({type: "setCount", count: count});
// background.js
chrome.runtime.onMessage.addListener(
function(message, sender, sendResponse) {
switch(message.type) {
case "setCount":
temp = message.count;
break;
default:
console.error("Unrecognised message: ", message);
}
}
);
A teraz, można zapytać w teorii, że w okienko:
// popup.js
chrome.runtime.sendMessage({type: "getCount"}, function(count) {
if(typeof count == "undefined") {
// That's kind of bad
} else {
// Use count
}
});
// background.js
chrome.runtime.onMessage.addListener(
function(message, sender, sendResponse) {
switch(message.type) {
case "setCount":
temp = message.count;
break;
case "getCount":
sendResponse(temp);
break;
default:
console.error("Unrecognised message: ", message);
}
}
);
teraz, jakie są problemy z tym?
Jaki jest czas życia temp
? Podano jednoznacznie "persistent": false
in your manifest. W rezultacie strona w tle może zostać rozładowana w dowolnym momencie, a stan wymazywania, taki jak temp
.
Można to naprawić za pomocą "persistent": true
, ale czytaj dalej.
Której zakładki oczekujesz? temp
będzie mieć zapisane ostatnie dane, które mogą nie być aktualną zakładką.
Możesz to naprawić, zachowując tabulatory (zobacz co tam zrobiłem?) na której karcie wysłano dane, np. za pomocą:
// background.js
/* ... */
case "setCount":
temp[sender.tab.id] = message.count;
break;
case "getCount":
sendResponse(temp[message.id]);
break;
// popup.js
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
// tabs is a single-element array after this filtering
chrome.runtime.sendMessage({type: "getCount", id: tabs[0].id}, function(count) {
/* ... */
});
});
To dużo pracy, prawda? To rozwiązanie działa dobrze choć dla danych non-tab-specyficzny, po utrwaleniu 1.
Następny poprawy do rozważenia: czy musimy tła strony, aby zapisać wynik dla nas? W końcu, chrome.storage
is a thing; to trwałe magazynowanie, do którego mają dostęp wszystkie skrypty rozszerzeń (w tym skrypty treści).
ta przecina tła (i wiadomości) z obrazka:
// content.js
chrome.storage.local.set({count: count});
// popup.js
chrome.storage.local.get("count", function(data) {
if(typeof data.count == "undefined") {
// That's kind of bad
} else {
// Use data.count
}
});
To wygląda czyściej, i całkowicie omija 1 Problem z góry, ale problemem 2 dostaje trudniejsze. You can't directly set/read coś jak count[id]
w magazynie, musisz przeczytać count
obecnie, modyfikować i pisać z powrotem. Może stać się powolny i niechlujny.
Dodaj do tego, że skrypty treści nie są w rzeczywistości znane z identyfikatora karty; będziesz musiał wysłać wiadomość tylko po to, aby się jej nauczyć. Ugh. Nie ładne. Ponownie, jest to doskonałe rozwiązanie dla danych nie związanych z kartami.
Potem następnego zadać pytanie: dlaczego trzeba nawet centralnej lokalizacji, aby zapisać wynik (zakładka specyficzne)? Czas życia skryptu treści to czas życia strony. Możesz poprosić o skrypt zawartości bezpośrednio w dowolnym momencie. W tym z popup.
Czekaj, czekaj, czy nie powiedziałeś na samej górze, że nie możesz wysłać danych do wyskakującego okienka? No tak, kinda: kiedy nie wiesz, czy jest tam słuchanie. Ale jeśli wyskakujące okienko zapyta, to musi być gotowe na odpowiedź, nie?
Więc, odwróćmy logikę skryptu treści. Zamiast natychmiastowego wysyłania danych, czekać i słuchać żądań:
chrome.runtime.onMessage.addListener(
function(message, sender, sendResponse) {
switch(message.type) {
case "getCount":
sendResponse(count);
break;
default:
console.error("Unrecognised message: ", message);
}
}
);
Następnie w okienko, musimy zapytać kartę który zawiera skrypt treści. Jest to inna funkcja przesyłania wiadomości i musimy określić identyfikator karty.
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {type: "getCount"}, function(count) {
/* ... */
});
});
Teraz jest znacznie czystszy. Problem 2 został rozwiązany: zapytanie o kartę, z której chcemy usłyszeć. Problem 1 wydaje się być rozwiązany: tak długo, jak skrypt liczy, czego potrzebujemy, może odpowiedzieć.
Należy pamiętać, że jako ostatnia komplikacja, skrypty zawartości nie są zawsze wstrzykiwane, gdy oczekują, że: porozszerzenie zostanie ponownie załadowane. Oto an answer wyjaśniając to bardzo szczegółowo. Można go obejść, jeśli chcesz, ale teraz po prostu ścieżki kodu dla niego:
function(count) {
if(typeof count == "undefined") {
// That's kind of bad
if(chrome.runtime.lastError) {
// We couldn't talk to the content script, probably it's not there
}
} else {
// Use count
}
}
bardzo dokładny jak zwykle – Auspex
Dzięki @Xan za szczegółową odpowiedź. Jedyne problemy, których nie jestem w stanie zrealizować za pomocą podejścia 3, to - jeśli wyślę wiadomość w formie zakładki z popup.js i pozwolę skryptowi treści zwrócić dane, co jeśli użytkownik przejdzie do innej karty, a karta skryptu treści nie jest już aktywna karta? Moje wyskakujące okienko nigdy nie wyświetli żadnych wyników? –
Jeśli użytkownik przejdzie do innej zakładki, popup jest w trakcie procesu zamykany i nie ma jeszcze słuchacza. Ta metoda dotyczy czegoś, na co skrypt treści może natychmiast odpowiedzieć. Jeśli uważasz, że wyskakujące okienko może się zamknąć, musisz pozwolić stronie w tle mówić, a następnie wyskakujące okienko pobiera dane z niego. – Xan