Pytanie Przekaż parametr do skryptu treści wstrzykniętego za pomocą chrome.tabs.executeScript ()


Jak mogę przekazać parametr do skryptu JavaScript w pliku skryptu treści, który jest wstrzykiwany za pomocą:

chrome.tabs.executeScript(tab.id, {file: "content.js"});

35
2017-07-10 09:55


pochodzenie




Odpowiedzi:


Nie ma czegoś takiego jak "przekazanie parametru do pliku".

Co ty mogą do to albo wstawić skrypt zawartości przed wykonanie pliku lub wysłanie wiadomości po wstawienie pliku. Poniżej pokażę przykład dla tych odrębnych metod.

Ustaw parametry przed wykonaniem pliku JS

Jeśli chcesz zdefiniować pewne zmienne przed wstawieniem pliku, po prostu zagnieżdź chrome.tabs.executeScript wzywa:

chrome.tabs.executeScript(tab.id, {
    code: 'var config = 1;'
}, function() {
    chrome.tabs.executeScript(tab.id, {file: 'content.js'});
});

Jeśli twoja zmienna nie jest tak prosta, to polecam jej użyć JSON.stringify aby obrócić obiekt w ciągu znaków:

var config = {somebigobject: 'complicated value'};
chrome.tabs.executeScript(tab.id, {
    code: 'var config = ' + JSON.stringify(config)
}, function() {
    chrome.tabs.executeScript(tab.id, {file: 'content.js'});
});

W poprzedniej metodzie zmienne mogą być używane w content.js w następujący sposób:

// content.js
alert('Example:' + config);

Ustaw parametry po wykonaniu pliku JS

Poprzednia metoda może służyć do ustawiania parametrów po pliku JS. Zamiast definiować zmienne bezpośrednio w zasięgu globalnym, możesz użyć przekazywanie wiadomości API przekazać parametry:

chrome.tabs.executeScript(tab.id, {file: 'content.js'}, function() {
    chrome.tabs.sendMessage(tab.id, 'whatever value; String, object, whatever');
});

W skrypcie treści (content.js), możesz słuchać tych wiadomości za pomocą chrome.runtime.onMessage wydarzenie i obsłużyć wiadomość:

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
    // Handle message.
    // In this example, message === 'whatever value; String, object, whatever'
});

68
2017-07-11 10:40



Otrzymuję tylko obiekt wiadomości bez tekstu. - user1365732
Pokaż swój kod. - Rob W
chrome.extension.onMessage.addListener (function (response, sender) {// Selected Text var text = document.getElementById ('text'); text.innerHTML = response.data; // Potrzebuje uzyskać te dane w pliku js wybrał opcję Tekst na dowolnej karcie chrome.tabs.executeScript (tab.id, {kod: 'var config = 788888888;'}, function () {chrome.tabs.executeScript (tab.id, {file: 'content.js' });});}); - user1365732
@ user1365732 Pokazałem dwa różne metody osiągnięcia tego samego celu. - Rob W
@ user1365732 Tak, ponieważ musisz przeczytać właściwość tego obiektu. W tym przykładzie config.somebigobject. Zauważ, że "somebigobject" może być czymkolwiek, po prostu chciałem pokazać, jak to zrobić w ogóle, i wybierając mało prawdopodobne imię, takie jak "somebigobject", chciałem przekazać wiadomość, że możesz umieścić wszystko, co chcesz na tym obiekcie. - Rob W


Istnieje pięć ogólnych sposobów przekazywania danych do wstrzykniętego skryptu treści tabs.executeScript()(MDN):

  • Ustaw dane przed wstrzykiwanie skryptu
    1. Posługiwać się chrome.storage.local(MDN) przekazać dane (ustawione przed wstrzyknięciem twojego skryptu).
    2. Wprowadź kod przed skryptem, który ustawia zmienną za pomocą danych (szczegółowe omówienie ewentualnego problemu z bezpieczeństwem).
    3. Ustaw plik cookie dla domeny, w której jest wstrzykiwany skrypt treści. Ta metoda może być również używana do przekazywania danych manifest.json skrypty zawartości, które są wstrzykiwane pod adresem document_start, bez potrzeby wykonywania skryptu treści na żądanie asynchroniczne.
  • Wyślij / ustaw dane po wstrzykiwanie skryptu
    1. Posługiwać się przekazywanie wiadomości(MDN) przekazać dane po Twój skrypt zostanie wstrzyknięty.
    2. Posługiwać się chrome.storage.onChanged(MDN) w swoim skrypcie treści, aby nasłuchiwał skryptu w tle, aby ustawić wartość za pomocą chrome.storage.local.set()(MDN).

Posługiwać się chrome.storage.local (ustaw przed uruchomieniem skryptu)

Za pomocą tej metody zachowuje się paradygmat wykonywania, który polega na wstrzykiwaniu skryptu, który wykonuje funkcję, a następnie kończy działanie. Nie ma również potencjalnego problemu z bezpieczeństwem stosowania wartości dynamicznej do budowania kodu wykonawczego, co jest wykonywane w drugiej opcji poniżej.

Z Twojego skryptu wyskakującego:

  1. Przechowuj dane za pomocą chrome.storage.local.set()(MDN).
  2. W wywołaniu dla chrome.storage.local.set(), połączenie tabs.executeScript()(MDN).
var updateTextTo = document.getElementById('comments').value;
chrome.storage.local.set({
    updateTextTo: updateTextTo
}, function () {
    chrome.tabs.executeScript({
        file: "content_script3.js"
    });
});

Ze swojego skryptu treści:

  1. Przeczytaj dane z chrome.storage.local.get()(MDN).
  2. Wprowadź zmiany w DOM.
  3. Unieważnij dane w storage.local (usuń klucz za pomocą: chrome.storage.local.remove()(MDN)).
chrome.storage.local.get('updateTextTo', function (items) {
    assignTextToTextareas(items.updateTextTo);
    chrome.storage.local.remove('updateTextTo');
});
function assignTextToTextareas(newText){
    if (typeof newText === 'string') {
        Array.from(document.querySelectorAll('textarea.comments')).forEach(el => {
            el.value = newText;
        });
    }
}

Patrz: uwagi 1 i 2.

Wprowadź kod przed skryptem, aby ustawić zmienną

Przed wykonaniem skryptu można wstrzyknąć kod, który ustawia zmienną w kontekście skryptu treści, z którego może następnie skorzystać skrypt podstawowy:

Kwestia bezpieczeństwa:

Następujące zastosowania "'" + JSON.stringify().replace(/\\/g,'\\\\').replace(/'/g,"\\'") + "'" zakodować dane do tekstu, który będzie właściwy JSON, gdy zostanie zinterpretowany jako kod, przed umieszczeniem go w code strunowy. The .replace() potrzebne są metody, aby A) poprawnie interpretować tekst jako ciąg znaków, gdy jest używany jako kod, a B) cytować dowolne ' które istnieją w danych. Następnie używa JSON.parse() aby zwrócić dane do ciągu znaków w skrypcie treści. Chociaż to kodowanie nie jest ściśle wymagane, jest to dobry pomysł, ponieważ nie znasz zawartości wartości, którą zamierzasz przesłać do skryptu treści. Ta wartość może łatwo spowodować uszkodzenie kodu, który wstrzykujesz (np. Użytkownik może używać ' i / lub " w wpisanym tekście). Jeśli w jakiś sposób nie unikniesz wartości, istnieje luka w zabezpieczeniach, która może spowodować wykonanie dowolnego kodu.

Z Twojego skryptu wyskakującego:

  1. Wstrzyknij prosty fragment kodu, który ustawia zmienną zawierającą dane.
  2. W wywołaniu dla chrome.tabs.executeScript()(MDN), połączenie tabs.executeScript() wstrzyknąć swój skrypt (uwaga: tabs.executeScript() wykona skrypty w kolejności, w której zadzwonisz tabs.executeScript(), o ile mają tę samą wartość runAt. Tak więc, czekając na oddzwonienie małego code nie jest ściśle wymagane).
var updateTextTo = document.getElementById('comments').value;
chrome.tabs.executeScript({
    code: "var newText = JSON.parse('" + encodeToPassToContentScript(updateTextTo) + "');"
}, function () {
    chrome.tabs.executeScript({
        file: "content_script3.js"
    });
});

function encodeToPassToContentScript(obj){
    //Encodes into JSON and quotes \ characters so they will not break
    //  when re-interpreted as a string literal. Failing to do so could
    //  result in the injection of arbitrary code and/or JSON.parse() failing.
    return JSON.stringify(obj).replace(/\\/g,'\\\\').replace(/'/g,"\\'")
}

Ze swojego skryptu treści:

  1. Wprowadź zmiany w DOM przy użyciu danych przechowywanych w zmiennej
if (typeof newText === 'string') {
    Array.from(document.querySelectorAll('textarea.comments')).forEach(el => {
        el.value = newText;
    });
}

Patrz: uwagi 1, 2 i 3.

Posługiwać się przekazywanie wiadomości(MDN)(przesłać dane po skrypt treści jest wstrzykiwany)

Wymaga to kodu skryptu treści do zainstalowania detektora dla wiadomości wysłanej przez wyskakujące okienko lub skryptu w tle (jeśli interakcja z interfejsem spowoduje zamknięcie okna popup). Jest nieco bardziej złożony.

Z Twojego skryptu wyskakującego:

  1. Określ aktywną kartę za pomocą tabs.query()(MDN).
  2. Połączenie tabs.executeScript()(MDN)
  3. W wywołaniu dla tabs.executeScript(), posługiwać się tabs.sendMessage()(MDN)(co wymaga znajomości tabId), aby wysłać dane jako wiadomość.
var updateTextTo = document.getElementById('comments').value;
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
    chrome.tabs.executeScript(tabs[0].id, {
        file: "content_script3.js"
    }, function(){
        chrome.tabs.sendMessage(tabs[0].id,{
            updateTextTo: updateTextTo
        });
    });
});

Ze swojego skryptu treści:

  1. Dodaj słuchacza za pomocą chrome.runtime.onMessage.addListener()(MDN).
  2. Wyjdź z głównego kodu, pozostawiając aktywnym słuchacza. Możesz wybrać wskaźnik sukcesu, jeśli wybierzesz.
  3. Po otrzymaniu wiadomości z danymi:
    1. Wprowadź zmiany w DOM.
    2. Usuń swój runtime.onMessage słuchacz

# 3.2 jest opcjonalne. Możesz sprawić, że twój kod będzie aktywny, czekając na kolejną wiadomość, ale to zmieni paradygmat, z którego korzystasz, do tego, w którym ładujesz swój kod i pozostaje on rezydentem czekając na wiadomości, aby zainicjować działania.

chrome.runtime.onMessage.addListener(assignTextToTextareas);
function assignTextToTextareas(message){
    newText = message.updateTextTo;
    if (typeof newText === 'string') {
        Array.from(document.querySelectorAll('textarea.comments')).forEach(el => {
            el.value = newText;
        });
    }
    chrome.runtime.onMessage.removeListener(assignTextToTextareas);  //optional
}

Patrz: uwagi 1 i 2.


Uwaga 1: Korzystanie Array.from() jest w porządku, jeśli nie robisz tego wiele razy i używasz wersja przeglądarki, która je posiada (Chrome> = wersja 45, Firefox> = 32). W przeglądarce Chrome i Firefox Array.from() jest powolny w porównaniu do innych metod uzyskiwania tablicy od NodeList. Aby uzyskać szybszą, bardziej zgodną konwersję do macierzy, można użyć skrótu asArray() kod w ta odpowiedź. Druga wersja asArray() podana w tej odpowiedzi jest również bardziej wiarygodna.

Uwaga 2: Jeśli chcesz ogranicz swój kod do wersji Chrome> = 51 lub Firefox w wersji> = 50, Chrome ma forEach() metoda dla NodeLists od wersji v51. W związku z tym nie trzeba konwertować do tablicy. Oczywiście, nie musisz konwertować do tablicy, jeśli używasz innego typu pętli.

Uwaga 3: Podczas gdy wcześniej używałam tej metody (wstrzykiwanie skryptu z wartością zmiennej) w moim własnym kodzie, przypominano mi, że powinienem ją tutaj uwzględnić podczas czytania ta odpowiedź.


10
2017-11-26 06:08



Jesteś pewny, że "wykona skrypty w kolejności, w której kalkujesz"? Czy kolejność nie jest niezdefiniowana? - Pacerier
@Pacerier, wszystkie moje testy (inny projekt, nie tylko dla tej odpowiedzi) wykazały (to samo runAt) skrypty są wstrzykiwane w kolejności tabs.executeScript() nazywa się (zarówno Chrome i Firefox). Nie pamiętam, czy przejrzałem kod źródłowy na obu, aby zweryfikować. Ważnym aspektem tego jest to, że wstrzykiwane skrypty pochodzą z twojego rozszerzenia, a nie z zasobów sieci (gdzie byłaby większość opóźnienia asynchronicznego). Masz rację, że nie jest to zagwarantowane w dokumentacji, dlatego napisałem to tak, że faktycznie czeka na tabs.executeScript() oddzwanianie w celu wstrzyknięcia drugiej,code: scenariusz. - Makyen
@Pacerier, Większość rozsądnych sposobów na wdrożenie takiego kodu może nie gwarancja że zastrzyk występuje w kolejności tabs.executeScript() zostanie wykonany, ale sprawi, że będzie mało prawdopodobne, że nie będzie w tej kolejności. Na przykład: tabs.executeScript() prawdopodobnie wpisuje komunikat instruujący wtrysk w kolejce komunikatów, aby został wysłany do prawidłowego procesu obsługi zawartości. Po otrzymaniu tego procesu wszedł do kolejki do wstrzyknięcia (oddzielna kolejka za runAtlub przynajmniej zorganizowane przez runAt) lub mogą być natychmiast przetworzone (np code: to jest natychmiast dostępny). itp. - Makyen
@Pacerier, W tym przypadku code: skrypt jest natychmiast dostępny (nie trzeba go nawet pobierać z rozszerzenia (np. dysku lub pamięci podręcznej RAM)). Oznacza to, że jest jeszcze bardziej prawdopodobne, że zostanie on wstrzyknięty przed drugim scenariuszem. Jednak testy, które zrobiłem wskazały, że nawet dla wielu (to samo runAt) skrypty pobrane z rozszerzenia, skrypty zostały wstrzyknięte w kolejności tabs.executeScript() jest nazywany. Ponownie, nie jest to gwarantowane, ale działa co najmniej 99% czasu. Ale to nie znaczy, że nie należy czekać na oddzwonienie, gdy masz ciężką zależność. - Makyen