2015-06-29 13 views
6

Piszę (próbuję się nauczyć) jak zrobić rozszerzenie chrome. Właśnie teraz robię bardzo proste, gdy zlicza przypadki pewnego słowa na stronie. Mam tę część pracy.Przekaż zmienną ze skryptu treści do wyskakującego okienka

Chcę wysłać tę informację do zespołu, aby móc ją wykorzystać do wykonania innych czynności.

Oto co mam do tej pory:

manifest.json

{ 
    "manifest_version": 2, 
    "name": "WeedKiller", 
    "description": "Totally serious $100% legit extension", 
    "version": "0.1", 

    "background": { 
     "persistent": false, 
     "scripts": ["background.js"] 
    }, 

    "permissions":[ 
     "tabs", 
     "storage" 
    ], 
    "browser_action": { 
    "default_icon": "icon.png", 
    "default_title": "WeedKiller", 
    "default_popup": "popup.html" 
    }, 
    "content_scripts": [ 
     { 
      "matches": [ 
       "http://*/*", 
       "https://*/*" 
      ], 
      "js": [ 
       "content.js" 
      ], 
      "run_at": "document_end" 
     } 
    ] 
} 

content.js

var elements = document.getElementsByTagName('*'); 
var count = 0; 

function tokeCounter(){ 
    for (var i = 0; i < elements.length; i++) { 
     var element = elements[i]; 

     for (var j = 0; j < element.childNodes.length; j++) { 
      var node = element.childNodes[j]; 

      if (node.nodeType === 3) { 
       var text = node.nodeValue; 
       if(text == '420'){ 
        count++; 
       } 

       var replacedText = text.replace(/420/, '+1'); 

       if (replacedText !== text) { 
        element.replaceChild(document.createTextNode(replacedText), node); 
       } 
      } 
     }  
    } 
} 

tokeCounter(); 

Więc co chcę się zdarzyć, aby wysłać do zmiennej count popup, dzięki czemu mogę go tam użyć.

Rozejrzałem się i stwierdziłem, że muszę coś zrobić z chrome.runtime.sendMessage.

mam go więc dodać tę linię do końca content.js:

chrome.runtime.sendMessage(count); 

a następnie w background.js:

chrome.runtime.onMessage.addListener(
    function(response, sender, sendResponse){  
     temp = response; 
    } 
); 

mam rodzaj zatrzymany tutaj jako I nie jestem pewien, jak wysłać tę informację do wyskakującego okienka i użyć jej.

Odpowiedz

25

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?

  1. 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.

  2. 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 
    } 
} 
+0

bardzo dokładny jak zwykle – Auspex

+0

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? –

+0

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