Ekstensi Chrome cara mengirim data dari script konten ke popup.html

96

Saya tahu ini telah ditanyakan di banyak posting tetapi jujur ​​saya tidak mengerti. Saya baru mengenal JavaScript, Ekstensi Chrome, dan segalanya, dan saya memiliki tugas kelas ini. Jadi saya perlu membuat plugin yang akan menghitung objek DOM pada halaman tertentu menggunakan Permintaan Lintas Domain. Saya sudah bisa mencapai ini sejauh ini menggunakan API Ekstensi Chrome. Sekarang masalahnya adalah saya perlu menampilkan data di halaman popup.html saya dari file contentScript.js. Saya tidak tahu bagaimana melakukannya. Saya sudah mencoba membaca dokumentasinya tetapi mengirim pesan di chrome saya tidak mengerti apa yang harus dilakukan.

berikut adalah kodenya sejauh ini.

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 

});

Bantuan apa pun akan dihargai dan harap hindari noobness yang saya lakukan :)

Sumair Baloch
sumber

Jawaban:

173

Meskipun Anda benar-benar berada di arah yang benar (dan sebenarnya cukup dekat dengan akhir), ada beberapa (imo) praktik buruk dalam kode Anda (misalnya memasukkan seluruh pustaka (jquery) untuk tugas sepele seperti itu, menyatakan izin yang tidak perlu, membuat panggilan ke metode API, dll.).
Saya tidak menguji kode Anda sendiri, tetapi dari gambaran umum singkat saya yakin bahwa mengoreksi hal berikut dapat menghasilkan solusi yang berfungsi (meskipun tidak terlalu mendekati optimal):

  1. Dalam manifest.json : Ubah urutan skrip konten, dengan menempatkan jquery terlebih dahulu. Menurut dokumen yang relevan :

    "js" [...] Daftar file JavaScript yang akan dimasukkan ke halaman yang cocok. Ini disuntikkan sesuai urutan kemunculannya dalam larik ini.

    (penekanan saya)

  2. Dalam contentscript.js : Pindahkan chrome.runtime.sendMessage ({...}) blok dalam satu onMessagecallback pendengar.


Karena itu, inilah pendekatan yang saya usulkan:

Aliran kontrol:

  1. Sebuah script konten dimasukkan ke dalam setiap halaman yang cocok dengan beberapa kriteria.
  2. Setelah dimasukkan, skrip konten mengirim pesan ke halaman acara (alias halaman latar belakang non-persisten) dan halaman acara melampirkan tindakan halaman ke tab.
  3. Segera setelah munculan tindakan halaman dimuat, ia mengirim pesan ke skrip konten, meminta info yang dibutuhkannya.
  4. Skrip konten memproses permintaan, dan merespons sehingga pop-up tindakan halaman dapat menampilkan info.

Struktur direktori:

          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>
gkalpak.dll
sumber
Wow ! terima kasih saudara, memeriksa pendekatan Anda sekarang saya merasakan berapa banyak masalah yang saya buat dengan kode saya. Terima kasih banyak ini berfungsi seperti pesona. :)
Sumair Baloch
halo, Maaf saya belum masuk selama beberapa waktu, baru saja memeriksa komentar Anda. Saya tidak dapat menerima jawaban apa pun. dikatakan Anda membutuhkan 15 poin reputasi untuk melakukannya.
Sumair Baloch
Maukah Anda membantu saya memecahkan masalah yang sangat mirip? <a href=" stackoverflow.com/questions/34467627/…> Gambar saya saat ini adalah sebagian besar kode Anda dari jawaban ini. Tapi saya masih belum bisa membuatnya berfungsi dan sepertinya tidak bisa menemukan bantuan yang baik tentang masalah ini.
wuno
mengapa Anda menggunakan chrome.tabs.sendMessagepopupjs dan chrome.runtime.onMessage.addListenerdi content.js mengapa .tabsuntuk popupjs dan .runtimedi content.js
Habib Kazemi
2
@hkm: Karena begitulah cara Anda mengirim dan menerima pesan. Semuanya ada di dokumen .
gkalpak
7

Anda dapat menggunakan localStorage untuk itu. Anda dapat menyimpan data apa pun dalam format tabel hash di memori browser dan kemudian mengaksesnya kapan saja. Saya tidak yakin apakah kita dapat mengakses localStorage dari skrip konten (sebelumnya diblokir), coba lakukan sendiri. Berikut cara melakukannya melalui halaman latar belakang Anda (saya meneruskan data dari skrip konten ke halaman latar belakang terlebih dahulu, kemudian menyimpannya di penyimpanan lokal):

di contentScript.js:

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

di eventPage.js (halaman latar belakang Anda):

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

Kemudian Anda dapat mengakses variabel itu di popup.js dengan localStorage ["total_elements"].

Mungkin Anda dapat mengakses localStorage langsung dari skrip konten di browser modern. Maka Anda tidak perlu meneruskan data melalui halaman latar belakang Anda.

Bacaan bagus tentang localStorage: http://diveintohtml5.info/storage.html

gthacoder.dll
sumber
1
Harap, jangan promosikan penggunaan chrome.extension.onRequest / sendRequest yang sudah tidak digunakan lagi (yang tidak memuat halaman latar belakang yang tidak tetap sebelum dijalankan). Gunakan chrome.runtime. * Sebagai gantinya.
gkalpak
1
@ExpertSystem Tolong, jika Anda melihat informasi yang sudah ketinggalan zaman, sarankan / edit.
Xan
3
@Xan: Jadi, Anda adalah penerus [Google-Chrome-Extension] :) Saya tidak suka mengedit kiriman orang (menurut saya terlalu mengganggu). Selain itu, dengan begitu banyak tutorial dan contoh yang sudah ketinggalan zaman (setidaknya saat itu), saya merasa lebih baik memberikan komentar eksplisit tentang mengapa itu buruk untuk digunakan .extension.xxx, daripada hanya menunjukkan cara yang benar (yang mungkin dianggap beberapa orang sebagai " alternatif yang sama-sama OK "). Saya kira ini lebih ke masalah gaya. Pertahankan kerja bagus!
gkalpak