Chrome Extension come inviare dati dallo script di contenuto a popup.html


95

So che questo è stato chiesto in numerosi post ma onestamente non li capisco. Sono nuovo di JavaScript, estensioni di Chrome e tutto il resto e ho questo compito in classe. Quindi ho bisogno di creare un plug-in che conteggi gli oggetti DOM su una determinata pagina utilizzando le richieste Cross Domain. Finora sono stato in grado di raggiungere questo obiettivo utilizzando le API di estensione di Chrome. Ora il problema è che devo mostrare i dati sulla mia pagina popup.html dal file contentScript.js. Non so come farlo Ho provato a leggere la documentazione ma messaggiando in Chrome non riesco proprio a capire cosa fare.

di seguito è riportato il codice finora.

manifest.json

{
"manifest_version":2,

"name":"Dom Reader",
"description":"Counts Dom Objects",
"version":"1.0",

"page_action": {
    "default_icon":"icon.png",
    "default_title":"Dom Reader",
    "default_popup":"popup.html"
},

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

"content_scripts":[
    {
        "matches":["http://pluralsight.com/training/Courses/*", "http://pluralsight.com/training/Authors/Details/*",                                          "https://www.youtube.com/user/*", "https://sites.google.com/site/*", "http://127.0.0.1:3667/popup.html"],
        "js":["domReader_cs.js","jquery-1.10.2.js"]
        //"css":["pluralsight_cs.css"]
    }
],

"permissions":[
    "tabs",
    "http://pluralsight.com/*",
    "http://youtube.com/*",
    "https://sites.google.com/*",
    "http://127.0.0.1:3667/*"
]

popup.html

<!doctype html>
<html>

    <title> Dom Reader </title>    
    <script src="jquery-1.10.2.js" type="text/javascript"></script>
    <script src="popup.js" type="text/javascript"></script>

<body>
    <H1> Dom Reader </H1>
    <input type="submit" id="readDom" value="Read DOM Objects" />

   <div id="domInfo">

    </div>
</body>
</html>

eventPage.js

var value1,value2,value3;

chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.action == "show") {
    chrome.tabs.query({ active: true, currentWindow: true }, function (tabs) {
        chrome.pageAction.show(tabs[0].id);
    });
}

value1 = request.tElements;
});

popup.js

$(function (){
$('#readDom').click(function(){
chrome.tabs.query({active: true, currentWindow: true}, function (tabs){
    chrome.tabs.sendMessage(tabs[0].id, {action: "readDom"});

 });
});
});

contentScript

var totalElements;
var inputFields;
var buttonElement;

chrome.runtime.onMessage.addListener(function (request, sender, sendResponse){
if(request.action == "readDom"){

    totalElements = $("*").length;
    inputFields = $("input").length;
    buttonElement = $("button").length;


}
})

chrome.runtime.sendMessage({ 
action: "show", 
tElements: totalElements, 
Ifields: inputFields, 
bElements: buttonElement 

});

Qualsiasi aiuto sarebbe apprezzato e per favore evita qualsiasi noia che ho fatto :)

Risposte:


171

Sebbene tu sia decisamente nella giusta direzione (e in realtà abbastanza vicino alla fine), ci sono diverse (imo) cattive pratiche nel tuo codice (ad esempio, iniettare un'intera libreria (jquery) per un'attività così banale, dichiarare permessi non necessari, rendere superfluo chiamate a metodi API ecc.).
Non ho testato personalmente il tuo codice, ma da una rapida panoramica credo che la correzione di quanto segue potrebbe portare a una soluzione funzionante (sebbene non molto vicina all'ottimale):

  1. In manifest.json : cambia l'ordine degli script di contenuto, mettendo prima jquery. Secondo i documenti pertinenti :

    "js" [...] L'elenco dei file JavaScript da inserire nelle pagine corrispondenti. Questi vengono iniettati nell'ordine in cui appaiono in questo array.

    (enfasi mia)

  2. In contentscript.js : Spostare il chrome.runtime.sendMessage ({...}) blocco all'interno della onMessagerichiamata ascoltatore.


Detto questo, ecco il mio approccio proposto:

Flusso di controllo:

  1. Uno script di contenuto viene inserito in ogni pagina che soddisfa alcuni criteri.
  2. Una volta inseriti, gli script di contenuto inviano un messaggio alla pagina dell'evento (ovvero la pagina di sfondo non persistente) e la pagina dell'evento allega un'azione di pagina alla scheda.
  3. Non appena il popup di azione della pagina viene caricato, invia un messaggio allo script del contenuto, chiedendo le informazioni di cui ha bisogno.
  4. Lo script del contenuto elabora la richiesta e risponde in modo che il popup dell'azione della pagina possa visualizzare le informazioni.

Struttura delle directory:

          root-directory/
           |_____img
                 |_____icon19.png
                 |_____icon38.png
           |_____manifest.json
           |_____background.js
           |_____content.js
           |_____popup.js
           |_____popup.html

manifest.json:

{
  "manifest_version": 2,
  "name": "Test Extension",
  "version": "0.0",
  "offline_enabled": true,

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

  "content_scripts": [{
    "matches": ["*://*.stackoverflow.com/*"],
    "js": ["content.js"],
    "run_at": "document_idle",
    "all_frames": false
  }],

  "page_action": {
    "default_title": "Test Extension",
    //"default_icon": {
    //  "19": "img/icon19.png",
    //  "38": "img/icon38.png"
    //},
    "default_popup": "popup.html"
  }

  // No special permissions required...
  //"permissions": []
}

background.js:

chrome.runtime.onMessage.addListener((msg, sender) => {
  // First, validate the message's structure.
  if ((msg.from === 'content') && (msg.subject === 'showPageAction')) {
    // Enable the page-action for the requesting tab.
    chrome.pageAction.show(sender.tab.id);
  }
});

content.js:

// Inform the background page that 
// this tab should have a page-action.
chrome.runtime.sendMessage({
  from: 'content',
  subject: 'showPageAction',
});

// Listen for messages from the popup.
chrome.runtime.onMessage.addListener((msg, sender, response) => {
  // First, validate the message's structure.
  if ((msg.from === 'popup') && (msg.subject === 'DOMInfo')) {
    // Collect the necessary data. 
    // (For your specific requirements `document.querySelectorAll(...)`
    //  should be equivalent to jquery's `$(...)`.)
    var domInfo = {
      total: document.querySelectorAll('*').length,
      inputs: document.querySelectorAll('input').length,
      buttons: document.querySelectorAll('button').length,
    };

    // Directly respond to the sender (popup), 
    // through the specified callback.
    response(domInfo);
  }
});

popup.js:

// Update the relevant fields with the new data.
const setDOMInfo = info => {
  document.getElementById('total').textContent = info.total;
  document.getElementById('inputs').textContent = info.inputs;
  document.getElementById('buttons').textContent = info.buttons;
};

// Once the DOM is ready...
window.addEventListener('DOMContentLoaded', () => {
  // ...query for the active tab...
  chrome.tabs.query({
    active: true,
    currentWindow: true
  }, tabs => {
    // ...and send a request for the DOM info...
    chrome.tabs.sendMessage(
        tabs[0].id,
        {from: 'popup', subject: 'DOMInfo'},
        // ...also specifying a callback to be called 
        //    from the receiving end (content script).
        setDOMInfo);
  });
});

popup.html:

<!DOCTYPE html>
<html>
  <head>
    <script type="text/javascript" src="popup.js"></script>
  </head>
  <body>
    <h3 style="font-weight:bold; text-align:center;">DOM Info</h3>
    <table border="1" cellpadding="3" style="border-collapse:collapse;">
      <tr>
        <td nowrap>Total number of elements:</td>
        <td align="right"><span id="total">N/A</span></td>
      </tr>
      <tr>
        <td nowrap>Number of input elements:</td>
        <td align="right"><span id="inputs">N/A</span></td>
      </tr>
      <tr>
        <td nowrap>Number of button elements:</td>
        <td align="right"><span id="buttons">N/A</span></td>
      </tr>
    </table>
  </body>
</html>

Wow ! grazie fratello, controllando il tuo approccio ora sento quanti problemi ho creato con il mio codice. Grazie mille, questo funziona come un fascino. :)
Sumair Baloch

ciao, scusa non ci sono stato per un po 'di tempo, ho solo controllato il tuo commento. Non posso accettare nessuna risposta. dice che hai bisogno di 15 punti reputazione per farlo.
Sumair Baloch

Ti dispiacerebbe aiutarmi a risolvere un problema molto simile? <a href=" stackoverflow.com/questions/34467627/…> La mia attuale possibilità è più o meno il tuo codice da questa risposta. Ma non riesco ancora a farlo funzionare e non riesco a trovare un buon aiuto in materia.
wuno

perché hai usato chrome.tabs.sendMessagein popupjs e chrome.runtime.onMessage.addListenerin content.js perché .tabsper popupjs e .runtimein content.js
Habib Kazemi

2
@hkm: perché è così che invii e ricevi messaggi. È tutto nei documenti .
gkalpak

7

Puoi usare localStorage per questo. È possibile memorizzare qualsiasi dato in un formato tabella hash nella memoria del browser e quindi accedervi in ​​qualsiasi momento. Non sono sicuro se possiamo accedere a localStorage dallo script del contenuto (era bloccato prima), prova a farlo da solo. Ecco come farlo attraverso la tua pagina in background (passo prima i dati dallo script del contenuto alla pagina in background, quindi li salvo in localStorage):

in contentScript.js:

chrome.runtime.sendMessage({
  total_elements: totalElements // or whatever you want to send
});

in eventPage.js (la tua pagina di sfondo):

chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse){
       localStorage["total_elements"] = request.total_elements;
    }
);

Quindi puoi accedere a quella variabile in popup.js con localStorage ["total_elements"].

Forse puoi accedere a localStorage direttamente dallo script del contenuto nei browser moderni. Quindi non è necessario passare i dati attraverso la pagina in background.

Bella lettura di localStorage: http://diveintohtml5.info/storage.html


1
Per favore, non promuovere l'uso del deprecato chrome.extension.onRequest / sendRequest (che btw non carica una pagina in background non persistente prima dell'esecuzione). Utilizza invece chrome.runtime. * .
gkalpak

1
@ExpertSystem Per favore, se vedi queste informazioni obsolete, suggerisci / fai una modifica.
Xan

3
@Xan: Quindi, sei il successore di [Google-Chrome-Extension] :) Non mi piace modificare i post delle persone (lo trovo troppo invadente). Inoltre, con così tanti tutorial ed esempi obsoleti (almeno allora), ho trovato meglio avere un commento esplicito sul motivo per cui è cattivo da usare .extension.xxx, invece di mostrare semplicemente il modo giusto (che alcune persone potrebbero pensare come un " alternativa altrettanto OK "). Immagino sia più una questione di stile. Continua così !
gkalpak
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.