Tiện ích mở rộng Chrome cách gửi dữ liệu từ tập lệnh nội dung tới popup.html


96

Tôi biết điều này đã được hỏi trong nhiều bài viết nhưng thành thật mà nói thì tôi không hiểu. Tôi chưa quen với JavaScript, Tiện ích mở rộng của Chrome và mọi thứ và tôi có bài tập trong lớp này. Vì vậy, tôi cần tạo một plugin có thể đếm các đối tượng DOM trên bất kỳ trang nhất định nào bằng cách sử dụng Yêu cầu tên miền chéo. Cho đến nay, tôi đã có thể đạt được điều này bằng cách sử dụng API tiện ích mở rộng của Chrome. Bây giờ vấn đề là tôi cần hiển thị dữ liệu trên trang popup.html của mình từ tệp contentScript.js. Tôi không biết làm thế nào để làm điều đó. Tôi đã thử đọc tài liệu nhưng nhắn tin trong chrome, tôi không thể hiểu phải làm gì.

sau đây là mã cho đến nay.

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 

});

Mọi sự giúp đỡ sẽ được đánh giá cao và vui lòng tránh bất kỳ hành động nào mà tôi đã làm :)

Câu trả lời:


173

Mặc dù bạn chắc chắn đang đi đúng hướng (và thực sự đã gần kết thúc), nhưng có một số (imo) thực hành không tốt trong mã của bạn (ví dụ: chèn toàn bộ thư viện (jquery) cho một nhiệm vụ tầm thường như vậy, khai báo các quyền không cần thiết, tạo ra superflous các lệnh gọi đến các phương thức API, v.v.).
Tôi đã không tự kiểm tra mã của bạn, nhưng từ tổng quan nhanh, tôi tin rằng việc sửa những điều sau có thể dẫn đến một giải pháp hoạt động (mặc dù không gần với mức tối ưu nhất):

  1. Trong tệp kê khai.json : Thay đổi thứ tự của các tập lệnh nội dung, đặt jquery trước. Theo các tài liệu liên quan :

    "js" [...] Danh sách các tệp JavaScript được đưa vào các trang phù hợp. Chúng được tiêm theo thứ tự xuất hiện trong mảng này.

    (nhấn mạnh của tôi)

  2. Trong contentscript.js : Di chuyển chrome.runtime.sendMessage ({...}) khối bên trong các onMessagecallback nghe.


Điều đó nói rằng, đây là cách tiếp cận được đề xuất của tôi:

Kiểm soát dòng chảy:

  1. Một tập lệnh nội dung được đưa vào mỗi trang phù hợp với một số tiêu chí.
  2. Sau khi được đưa vào, các tập lệnh nội dung sẽ gửi một thông báo đến trang sự kiện (hay còn gọi là trang nền không liên tục) và trang sự kiện sẽ đính kèm một hành động trang vào tab.
  3. Ngay sau khi cửa sổ bật lên hành động trang được tải, nó sẽ gửi một thông báo đến tập lệnh nội dung, yêu cầu thông tin mà nó cần.
  4. Tập lệnh nội dung xử lý yêu cầu và phản hồi để cửa sổ bật lên hành động trang có thể hiển thị thông tin.

Cấu trúc thư mục:

          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>

Chà! cảm ơn anh trai, kiểm tra cách tiếp cận của bạn bây giờ tôi cảm thấy có bao nhiêu vấn đề tôi đã tạo ra với mã của tôi. Cảm ơn rất nhiều công việc này giống như một sự quyến rũ. :)
Sumair Baloch

Xin chào, Xin lỗi, tôi đã không tham gia một thời gian, chỉ cần kiểm tra nhận xét của bạn. Tôi không thể chấp nhận bất kỳ câu trả lời nào. nó nói rằng bạn cần 15 điểm danh tiếng để làm như vậy.
Sumair Baloch

Bạn có thể giúp tôi giải quyết một vấn đề tương tự không? <a href=" stackoverflow.com/questions/34467627/…> Bức ảnh hiện tại của tôi là khá nhiều mã của bạn từ câu trả lời này. Nhưng tôi vẫn không thể làm cho nó hoạt động và dường như không tìm được bất kỳ trợ giúp hữu ích nào về vấn đề này.
wuno

tại sao bạn sử dụng chrome.tabs.sendMessagetrong popupjs và chrome.runtime.onMessage.addListenertrong content.js tại sao .tabscho popupjs và .runtimetrong content.js
Habib Kazemi

2
@hkm: Vì đó là cách bạn gửi và nhận tin nhắn. Tất cả đều có trong tài liệu .
gkalpak

7

Bạn có thể sử dụng localStorage cho điều đó. Bạn có thể lưu trữ bất kỳ dữ liệu nào ở định dạng bảng băm trong bộ nhớ trình duyệt và sau đó truy cập dữ liệu đó bất kỳ lúc nào. Tôi không chắc liệu chúng ta có thể truy cập localStorage từ tập lệnh nội dung (trước đó nó đã bị chặn) hay không, hãy thử tự làm điều đó. Đây là cách thực hiện thông qua trang nền của bạn (tôi chuyển dữ liệu từ tập lệnh nội dung sang trang nền trước, sau đó lưu nó trong localStorage):

trong contentScript.js:

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

trong eventPage.js (trang nền của bạn):

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

Sau đó, bạn có thể truy cập biến đó trong popup.js với localStorage ["total_elements"].

Có thể bạn có thể truy cập localStorage trực tiếp từ tập lệnh nội dung trong các trình duyệt hiện đại. Sau đó, bạn không cần phải chuyển dữ liệu qua trang nền của mình.

Đọc tốt về localStorage: http://diveintohtml5.info/storage.html


1
Vui lòng không quảng bá việc sử dụng chrome.extension.onRequest / sendRequest không dùng nữa (btw không tải trang nền không liên tục trước khi thực thi). Thay vào đó, hãy sử dụng chrome.runtime. * .
gkalpak

1
@ExpertSystem Vui lòng, nếu bạn thấy thông tin lỗi thời như vậy, hãy đề xuất / chỉnh sửa.
Xan

3
@Xan: Vì vậy, bạn là người kế nhiệm trong [Google-Chrome-Extension] :) Tôi không thích chỉnh sửa bài đăng của mọi người (tôi thấy nó quá xâm phạm). Bên cạnh đó, với rất nhiều hướng dẫn và ví dụ lỗi thời (ít nhất là vào thời điểm đó), tôi thấy tốt hơn là nên có một nhận xét rõ ràng về lý do tại sao nó không tốt khi sử dụng .extension.xxx, thay vì chỉ hiển thị đúng cách (mà một số người có thể nghĩ là " thay thế OK như nhau "). Tôi đoán đó là vấn đề về phong cách. Hãy tiếp tục phát huy !
gkalpak
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.