2015-06-29 4 views
6

Ich bin herumspielen (versuchen zu lernen), wie man eine Chrome-Erweiterung machen. Im Moment mache ich einfach super, wo es Instanzen eines bestimmten Wortes auf einer Seite zählt. Ich habe diesen Teil in Arbeit.Übergeben Sie eine Variable aus dem Inhaltsskript in Popup

Was ich tun möchte, ist diese Informationen an den Pop zu senden, damit ich es verwenden kann, um etwas anderes zu tun. Hier

ist das, was ich bisher:

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(); 

Also, was ich passieren soll, ist die count Variable die senden Popup, damit ich es dort benutzen kann.

Ich habe mich umgesehen und festgestellt, dass ich etwas mit chrome.runtime.sendMessage tun muss.

Ich habe es so ich diese Linie bis zum Ende der content.js hinzufügen:

chrome.runtime.sendMessage(count); 

und dann in background.js:

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

ich irgendwie bin hier, da ich fest bin mir nicht sicher, wie ich diese Information an Popup senden und verwenden soll.

Antwort

25

Wie Sie richtig bemerkt haben, können Sie Daten nicht direkt an das Popup senden, wenn es geschlossen ist. Sie senden also Daten an die Hintergrundseite.

Dann wenn Sie das Popup öffnen, möchten Sie die Daten dort. Also, was sind die Optionen?

Bitte beachten Sie: Diese Antwort wird zuerst einen schlechten Rat geben und dann verbessern. Da OP lernt, ist es wichtig, den Gedankenprozess und die Straßenböen zu zeigen.

Erste Lösung, die in den Sinn kommt, ist die folgende: Fragen Sie die Hintergrundseite, Messaging erneut verwenden. Frühwarnung: Dies funktioniert nicht oder funktioniert nicht einwandfrei.

Zuerst stellen Sie fest, dass es verschiedene Arten von Nachrichten geben kann. Ändern Ihres aktuellen Code-Messaging:

// 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); 
     } 
    } 
); 

Und jetzt, Sie in der Theorie könnte, dass in dem Popup fragen:

// 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); 
     } 
    } 
); 

Nun, was mit diesem die Probleme?

  1. Was ist die lebensdauer von temp? Sie haben explizit "persistent": false in your manifest angegeben. Als Ergebnis kann die Hintergrundseite jederzeit aus dem Wischzustand entfernt werden, z. B. temp.

    Sie könnten es mit "persistent": true beheben, aber lesen Sie weiter.

  2. Welche Anzahl von Tabs erwarten Sie? temp werden die letzten Daten geschrieben haben, die sehr wahrscheinlich nicht die aktuelle Registerkarte sein.

    Sie könnten es mit Registerkarten beheben (siehe was ich dort getan habe?) auf dem Tab die Daten gesendet, z. mit:

    // 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) { 
         /* ... */ 
        }); 
    }); 
    

    Es ist eine Menge Arbeit, oder? Diese Lösung funktioniert zwar gut für Nicht-Reiter spezifischen Daten nach 1.


Nächste Verbesserung Festsetzung zu berücksichtigen: brauchen wir die Hintergrundseite für uns das Ergebnis zu speichern? Immerhin chrome.storage is a thing; Es ist ein persistenter Speicher, auf den alle Erweiterungsskripte (einschließlich Inhaltsskripten) zugreifen können.

Dies reduziert den Hintergrund (und Messaging) aus dem Bild:

// 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 
    } 
}); 

Das sieht saubere und umgeht völlig Problem 1 von oben, aber Problem 2 wird schwieriger. You can't directly set/read etwas wie count[id] im Speicher, müssen Sie count lesen, ändern und schreiben Sie es zurück. Es kann langsam und unordentlich werden.

Hinzuzufügen, dass Inhaltsskripts ihre Registerkarte ID nicht wirklich kennen; Sie müssen den Hintergrund der Nachricht nur mitteilen, um es zu lernen. Pfui. Nicht hübsch. Auch dies ist eine großartige Lösung für nicht tab-spezifische Daten.


Dann wird die nächste Frage stellen: warum wir auch eine zentrale Lage müssen die (Tab spezifisch) Ergebnis zu speichern? Die Lebensdauer des Inhaltsskripts ist die Lebensdauer der Seite. Sie können das Inhaltsskript jederzeit direkt anfordern. Einschließlich aus dem Popup.

Warte, warte, hast du nicht ganz oben gesagt, dass du keine Daten an das Popup senden kannst? Nun, ja, irgendwie: wenn Sie nicht wissen, ob es da zu hören ist. Aber wenn das Popup fragt, dann muss es bereit sein, eine Antwort zu bekommen, nein?

Also, lassen Sie uns die Inhaltsskriptlogik umkehren. Statt sofort die Daten zu senden, warten und für Anfragen hören:

chrome.runtime.onMessage.addListener(
    function(message, sender, sendResponse) { 
     switch(message.type) { 
      case "getCount": 
       sendResponse(count); 
       break; 
      default: 
       console.error("Unrecognised message: ", message); 
     } 
    } 
); 

Dann im Popup, müssen wir die Registerkarte abzufragen, der die Content-Skript enthält. Es ist eine andere Messaging-Funktion, und wir müssen die Registerkarte ID angeben.

chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { 
     chrome.tabs.sendMessage(tabs[0].id, {type: "getCount"}, function(count) { 
      /* ... */ 
     }); 
    }); 

Jetzt ist das viel sauberer. Problem 2 ist gelöst: Wir fragen die Registerkarte ab, von der wir hören möchten. Problem 1 scheint gelöst zu sein: Solange ein Skript gezählt hat, was wir brauchen, kann es antworten.

Beachten Sie als letzte Komplikation, dass Content-Scripts nicht immer injiziert werden, wenn Sie dies erwarten: Sie werden erst bei der Navigation aktiviert, nachdem die Erweiterung (erneut) geladen wurde (10). Hier ist an answer, die das im Detail erklärt. Es kann umgangen werden, wenn Sie wollen, aber für jetzt nur noch einen Code-Pfad für sie:

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

Sehr gründlich wie gewohnt – Auspex

+0

Dank @Xan für die ausführliche Antwort. Nur Probleme, die ich mit Ansatz 3 nicht durchstehen kann, sind - wenn ich eine tab-basierte Nachricht von popup.js sende und das Inhaltsskript die Daten zurücksenden lasse, was passiert, wenn der Benutzer auf eine andere Registerkarte wechselt und die Inhaltsskript-Registerkarte nicht mehr ist aktive Registerkarte? Mein Pop-up zeigt nie irgendwelche Ergebnisse? –

+0

Wenn der Benutzer auf eine andere Registerkarte wechselt, wird das Popup geschlossen und es gibt sowieso keinen Listener. Diese Methode ist für etwas, auf das das Inhaltsskript sofort antworten kann. Wenn Sie der Meinung sind, dass das Popup dazwischen geschlossen werden kann, müssen Sie Ihre Hintergrundseite sprechen lassen und dann werden die Daten vom Popup abgerufen. – Xan

Verwandte Themen