Chrome Uzantısı, içerik komut dosyasından popup.html'ye veri gönderme


97

Bunun sayısız gönderide sorulduğunu biliyorum ama dürüst olmak gerekirse onları anlamıyorum. JavaScript, Chrome Uzantıları ve her şeyde yeniyim ve bu sınıf ödevim var. Dolayısıyla, Etki Alanları Arası İstekleri kullanarak herhangi bir sayfadaki DOM nesnelerini sayan bir eklenti yapmam gerekiyor. Şimdiye kadar Chrome Uzantı API'larını kullanarak bunu başarabildim. Şimdi sorun şu ki, pop-up.html sayfamdaki verileri contentScript.js dosyasından göstermem gerekiyor. Bunu nasıl yapacağımı bilmiyorum, belgeleri okumayı denedim, ancak krom mesajlaşmayı ne yapacağımı anlayamıyorum.

Şu ana kadarki kod aşağıdadır.

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 

});

Herhangi bir yardım için minnettar olurum ve lütfen yaptığım herhangi bir sessizlikten kaçının :)

Yanıtlar:


176

Kesinlikle doğru yönde (ve aslında sonuna çok yakın) olmanıza rağmen, kodunuzda birkaç (imo) kötü uygulama vardır (örneğin, böylesine önemsiz bir görev için bütün bir kitaplığı (jquery) enjekte etmek, gereksiz izinleri bildirmek, gereksiz hale getirmek API yöntemlerine çağrı vb.).
Kodunuzu kendim test etmedim, ancak hızlı bir genel bakıştan, aşağıdakileri düzeltmenin çalışan bir çözümle sonuçlanabileceğine inanıyorum (en iyiye çok yakın olmasa da):

  1. In manifest.json : Değişim içerik komut sırası, ilk jquery koyarak. Göre ilgili dokümanlar :

    "js" [...] Eşleşen sayfalara enjekte edilecek JavaScript dosyalarının listesi. Bunlar, bu dizide göründükleri sırayla enjekte edilir .

    (vurgu benim)

  2. In contentscript.js : Taşı chrome.runtime.sendMessage ({...}) blok içindekionMessage dinleyici callback'inde.


Bununla birlikte, işte benim önerdiğim yaklaşım:

Kontrol akışı:

  1. Her sayfaya bazı kriterlere uyan bir içerik komut dosyası enjekte edilir.
  2. Enjekte edildikten sonra, içerik komut dosyaları olay sayfasına (kalıcı olmayan arka plan sayfasına) bir mesaj gönderir ve olay sayfası sekmeye bir sayfa eylemi ekler.
  3. Sayfa eylemi açılır penceresi yüklenir yüklenmez, içerik betiğine ihtiyaç duyduğu bilgiyi isteyen bir mesaj gönderir.
  4. İçerik komut dosyası isteği işler ve yanıt verir, böylece sayfa eylemi açılır penceresi bilgileri görüntüleyebilir.

Dizin yapısı:

          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>

Vaov ! teşekkürler kardeşim, yaklaşımını şimdi kontrol ediyorum, kodumla kaç problem yarattığımı hissediyorum. Çok teşekkürler, bu bir cazibe gibi çalışıyor. :)
Sumair Baloch

merhaba, kusura bakma bir süredir burada değildim, sadece yorumunu kontrol ettim. Hiçbir cevabı kabul edemem. Bunu yapmak için 15 itibar puanına ihtiyacınız olduğunu söylüyor.
Sumair Baloch

Çok benzer bir sorunu çözmeme yardım eder misiniz? <a href=" stackoverflow.com/questions/34467627/…> Bu konudaki şu anki çekimim, bu yanıttaki kodunuzdur. Ancak yine de işe yarayamıyorum ve bu konuda iyi bir yardım bulamıyorum.
wuno

neden chrome.tabs.sendMessagepopupj'lerde ve chrome.runtime.onMessage.addListenercontent.js'de kullandınız , neden .tabspopupj'ler ve .runtimecontent.js'de kullandınız
Habib Kazemi

2
@hkm: Çünkü mesajları böyle gönderip alırsınız. Hepsi belgelerde .
gkalpak

7

Bunun için localStorage'ı kullanabilirsiniz. Karma tablo formatında herhangi bir veriyi tarayıcı belleğinde saklayabilir ve daha sonra istediğiniz zaman bunlara erişebilirsiniz. LocalStorage'a içerik betiğinden erişip erişemeyeceğimizden emin değilim (daha önce engellendi), bunu kendiniz yapmayı deneyin. Arka plan sayfanız aracılığıyla bunu nasıl yapacağınız aşağıda açıklanmıştır (verileri önce içerik komut dosyasından arka plan sayfasına geçiririm, ardından localStorage'a kaydederim):

contentScript.js'de:

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

eventPage.js'de (arka plan sayfanız):

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

Ardından, localStorage ["total_elements"] ile popup.js'deki bu değişkene erişebilirsiniz.

Belki de localStorage'a modern tarayıcılardaki içerik betiğinden doğrudan erişebilirsiniz. Ardından verileri arka plan sayfanızdan geçirmenize gerek kalmaz.

LocalStorage hakkında güzel okuma: http://diveintohtml5.info/storage.html


1
Lütfen, kullanımdan kaldırılmış chrome.extension.onRequest / sendRequest'in kullanımını teşvik etmeyin (btw, çalıştırmadan önce kalıcı olmayan bir arka plan sayfası yüklemez). Bunun yerine chrome.runtime. * Kullanın .
gkalpak

1
@ExpertSystem Lütfen, bu tür eski bilgiler görürseniz, bir düzenleme önerin / yapın.
Xan

3
@Xan: Yani, [Google-Chrome-Uzantısı] 'nın halefisiniz :) İnsanların gönderilerini düzenlemeyi sevmiyorum (bunu çok rahatsız edici buluyorum). Ayrıca, modası geçmiş pek çok öğretici ve örnek varken (en azından o zamanlar), sadece doğru yolu göstermek yerine (bazı insanlar bunu bir "" olarak düşünebilir), neden kullanmanın kötü olduğuna dair açık bir yorumda bulunmayı daha iyi buldum. .extension.xxxeşit derecede iyi alternatif "). Sanırım daha çok stil meselesi. İyi çalışmaya devam edin!
gkalpak
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.