Chrome Extension 콘텐츠 스크립트에서 popup.html로 데이터를 보내는 방법


96

나는 이것이 수많은 게시물에서 요청되었지만 솔직히 이해하지 못한다는 것을 알고 있습니다. 저는 JavaScript, Chrome 확장 프로그램 및 모든 것을 처음 접했고이 수업 과제가 있습니다. 따라서 Cross Domain Requests를 사용하여 특정 페이지에서 DOM 개체를 계산하는 플러그인을 만들어야합니다. 지금까지 Chrome Extension API를 사용하여이를 달성 할 수있었습니다. 이제 문제는 contentScript.js 파일의 popup.html 페이지에 데이터를 표시해야한다는 것입니다. 문서를 읽으려고 시도했지만 크롬으로 메시지를 보내는 방법을 모르겠지만 무엇을 해야할지 이해할 수 없습니다.

다음은 지금까지의 코드입니다.

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 

});

어떤 도움을 주시면 감사하겠습니다. 내가 한 멍청함을 피하십시오 :)

답변:


172

확실히 올바른 방향으로 가고 있지만 (실제로는 거의 끝에 가까웠지만) 코드에는 몇 가지 (imo) 나쁜 관행이 있습니다 (예 : 사소한 작업에 전체 라이브러리 (jquery) 삽입, 불필요한 권한 선언, 슈퍼 플 로스 만들기) API 메서드 호출 등).
코드를 직접 테스트하지는 않았지만 빠른 개요에서 다음을 수정하면 작동하는 솔루션이 될 수 있다고 생각합니다 (최적에 가깝지는 않지만).

  1. 에서 의 manifest.json : 변경 내용 스크립트의 순서, 첫 번째 jQuery를 넣어. 관련 문서 에 따르면 :

    "js"[...] 일치하는 페이지에 삽입 할 JavaScript 파일 목록입니다. 이들은 이 배열에 나타나는 순서대로 삽입 됩니다 .

    (강조 내)

  2. 에서는 contentscript.js : 이동 chrome.runtime.sendMessage ({...}) 블록 내부onMessage 리스너 콜백.


즉, 여기에 제안 된 접근 방식이 있습니다.

제어 흐름 :

  1. 콘텐츠 스크립트는 일부 기준과 일치하는 각 페이지에 삽입됩니다.
  2. 삽입되면 콘텐츠 스크립트가 이벤트 페이지 (비 지속적 배경 페이지라고도 함)에 메시지를 보내고 이벤트 페이지는 페이지 작업을 탭에 첨부합니다.
  3. 페이지 작업 팝업이로드 되 자마자 콘텐츠 스크립트에 필요한 정보를 요청하는 메시지를 보냅니다.
  4. 콘텐츠 스크립트는 요청을 처리하고 페이지 작업 팝업이 정보를 표시 할 수 있도록 응답합니다.

디렉토리 구조 :

          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>

와 ! 감사합니다 형제 님, 지금 귀하의 접근 방식을 확인하십시오. 내 코드로 얼마나 많은 문제를 만들 었는지 느낍니다. 감사합니다. 이것은 매력처럼 작동합니다. :)
Sumair Baloch 2013

안녕하세요, 죄송합니다. 한동안 방송을하지 않았으며 귀하의 의견을 확인했습니다. 나는 어떤 대답도 받아 들일 수 없다. 그렇게하려면 15 개의 평판 포인트가 필요하다고합니다.
Sumair Baloch 2013

매우 유사한 문제를 해결하도록 도와 주시겠습니까? <a href=" stackoverflow.com/questions/34467627/…> 현재이 장면은이 답변의 코드와 거의 비슷합니다.하지만 여전히 작동하도록 할 수 없으며 문제에 대한 좋은 도움을 찾을 수없는 것 같습니다.
wuno

왜 사용 chrome.tabs.sendMessagepopupjs과 chrome.runtime.onMessage.addListener이유를 content.js에 .tabspopupjs 및 .runtimecontent.js에
하비브 카 제미

2
@hkm : 메시지를주고받는 방식이기 때문입니다. 그것은 모두 문서에 있습니다.
gkalpak

7

이를 위해 localStorage를 사용할 수 있습니다. 브라우저 메모리에 해시 테이블 형식의 데이터를 저장 한 다음 언제든지 액세스 할 수 있습니다. 콘텐츠 스크립트 (이전에 차단됨)에서 localStorage에 액세스 할 수 있는지 잘 모르겠습니다. 직접 시도해보십시오. 백그라운드 페이지를 통해 수행하는 방법은 다음과 같습니다. 먼저 콘텐츠 스크립트에서 백그라운드 페이지로 데이터를 전달한 다음 localStorage에 저장합니다.

contentScript.js에서 :

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

eventPage.js (배경 페이지) :

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

그런 다음 localStorage [ "total_elements"]를 사용하여 popup.js에서 해당 변수에 액세스 할 수 있습니다.

최신 브라우저의 콘텐츠 스크립트에서 직접 localStorage에 액세스 할 수 있습니다. 그런 다음 배경 페이지를 통해 데이터를 전달할 필요가 없습니다.

localStorage에 대한 좋은 읽기 : http://diveintohtml5.info/storage.html


1
더 이상 사용되지 않는 chrome.extension.onRequest / sendRequest (실행 전에 비 영구 백그라운드 페이지를로드하지 않음) 의 사용을 홍보 하지 마십시오. 대신 chrome.runtime. *을 사용하십시오 .
gkalpak 2013

1
@ExpertSystem 오래된 정보가 보이면 제안 / 수정하십시오.
Xan

3
@Xan : 당신은 [Google-Chrome-Extension]의 후계자입니다. :) 저는 사람들의 게시물을 편집하는 것을 좋아하지 않습니다 (너무 방해가된다고 생각합니다). 게다가, (다음 적어도 다시) 많은 오래된 자습서 및 예제와 함께, 나는 이유에 명시 적 의견이 더 나은 그것을 발견 잘못된 사용을 .extension.xxx대신 단지 어떤 사람들은 "으로 생각할 수있는 (올바른 방법을 보여주는 똑같이 괜찮은 대안 "). 내가 생각하기에 스타일 문제에 더 가깝다. 좋은 일을 계속하십시오!
gkalpak
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.