2015-04-03 31 views
0

我有这个想法传递数据形成注入脚本(getDOM.js)我background.js从执行的脚本将数据传递到后台的Chrome扩展

bacgkround.js

chrome.contextMenus.onClicked.addListener(function(info, tab){ 
    chrome.tabs.executeScript(tab.id, {file: "getDOM.js"}) 
}); 


chrome.contextMenus.onClicked.addListener(function(info, tab){ 
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs) { 
      chrome.tabs.sendMessage(tabs[0].id, {greeting: "GetURL"}, function(response) { 
      alert(response.navURL); 
     }); 
     }); 
}); 

getDOM.js

chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse) { 

    if (request.greeting === "GetURL") 
     sendResponse({navURL:'test'}); 
    }); 

,你可以看到我用按摩功能来传递数据,而T3这是一个问题。我不能在正确的时间获得数据,我会通过background.js以前的数据

内容必须是动态的(不是特定的“测试”),每次它会提醒以前的数据。想象一下,getDOM.js会传递选定的文本,这个代码将会通过先前选择的文本。我怎样才能解决这个问题 ?

我的动态数据,例如:

function getHTMLOfSelection() { 
     var range; 
     if (document.selection && document.selection.createRange) { 
     range = document.selection.createRange(); 
     return range.htmlText; 
     } 
     else if (window.getSelection) { 
     var selection = window.getSelection(); 
     if (selection.rangeCount > 0) { 
      range = selection.getRangeAt(0); 
      var clonedSelection = range.cloneContents(); 
      var div = document.createElement('div'); 
      div.appendChild(clonedSelection); 
      return div.innerHTML; 
     } 
     else { 
      return ''; 
     } 
     } 
     else { 
     return ''; 
     } 
} 

var dom = getHTMLOfSelection(); 
chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse) { 

    if (request.greeting === "getDom") 
     sendResponse({DOM:dom}); 
    }); 

它会通过选择DOM来这里background.js

+0

请问您可以添加一个示例,显示问题?即动态数据。 – Xan 2015-04-03 09:40:10

+0

我刚更新了这个问题。我再也无法重现这个问题,我不知道如何可能,但现在问题已经消失了!!但问题可能会回来(我不知道如何!),还有另一个问题:上下文菜单应该被激发一次后,工作正常 – 2015-04-03 09:48:17

+0

我认为问题是与时间,JS将被注入,它应该被注入在开始。你能帮助我吗? – 2015-04-03 09:49:18

回答

0

很多问题。让我们来看看。

  1. 在脚本注入时执行getHTMLOfSelection()没有意义。您可能应该将其放入消息处理程序中:当询问时,可以选择

  2. 更大的问题是每次注入脚本时都会出现这样的情况。这和1一起,导致各种好玩。让我们更详细地看看!

    • 用户触发上下文菜单。
    • 您的第一个contextMenu.onClicked处理程序运行。脚本注入是计划的。它是异步的,所以你不知道什么时候它会完成,除非你使用回调。你不这样做。
    • 您的第二个contextMenu.onClicked处理程序运行。它将消息发送给可能尚未完成执行的脚本。如果你幸运的话,你会得到回应。
    • 用户在同一页面上再次触发上下文菜单。
    • 您的第一个contextMenu.onClicked处理程序再次运行。脚本将再次注入,创建一个第二个收听者将与第一个竞争的消息。它又是异步的,所以也许到您的消息到达dom是最新的。也许不会。
    • 您的第二个contextMenu.onClicked处理程序再次运行。这次肯定有一个消息监听器(可能是两个!),它返回或许是最新的数据。

    等。你看到问题了吗?

  3. 此外,你不能通过与sendResponse的DOM对象。该对象需要是JSON序列化的,并且DOM对象包含循环引用,这是一个禁忌。您需要在内容脚本一侧提取所需的数据,并仅传递该数据。

因此,我们试着解决这些问题。

有两种处理方法。我将介绍这两个,选择一个你喜欢的。这两个会照顾的问题1和2

第一种方式是确保你的消息处理程序只能由包括某种形式的保护变量添加一次:

// getDOM.js 

if(!getDOM_ready) { // This will be undefined the first time around 
    getDOM_ready = true; 
    chrome.runtime.onMessage.addListener(
    function(request, sender, sendResponse) { 
     // If only you knew how I hate this "greeting" example copied over 
     if (request.command === "GetURL") { 
     var dom = getHTMLOfSelection(); 
     sendResponse({DOM: dom}); 
     } 
    } 
); 
} 

function getHTMLOfSelection() { 
    /* ... */ 
} 

然后在背景方面,我们需要确保我们发送脚本执行完毕后,才一则消息:

chrome.contextMenus.onClicked.addListener(function(info, tab){ 
    chrome.tabs.executeScript(tab.id, {file: "getDOM.js"}, function() { 
    // This only executes after the content script runs 
    // Oh, and you most certainly don't need to query for tabs, 
    // you already have a tab and its id in `onClicked` 
    chrome.tabs.sendMessage(tab.id, {command: "GetURL"}, function(response) { 
     alert(response.navURL); 
    }); 
}); 

第二种方式是完全放弃消息。 executeScript实际上返回内容脚本评估的最后一个值。这使得内容脚本琐碎,不留下一个消息监听器:

// getDOM.js 
function getHTMLOfSelection() { 
    /* ... */ 
} 

getHTMLOfSelection(); // Yes, that's it 

在背景方面,你需要适应听众:这里

chrome.contextMenus.onClicked.addListener(function(info, tab){ 
    chrome.tabs.executeScript(tab.id, {file: "getDOM.js"}, function(results) { 
    // results is an array, because it can be executed in more than one frame 
    alert(results[0]); 
}); 

的代码要简单得多,而且它不会留下活动事件侦听器。

至于问题3,你需要从选择中提取你需要的信息(比如说一个链接),只传递该信息而不是对象。


最后,这不是一个完整的解决方案。问题是,您的选择可能在iframe之内,并且此解决方案仅将代码注入顶部框架。解决这个问题的方式只是给读者一个练习。在内容脚本选项中使用all_frames: true将注入所有框架,其中一个框架将具有非空选择。你只需要看看哪一个。

+0

这真是太好了!奇迹般有效 – 2015-04-03 19:10:35

相关问题