2016-11-11 58 views
0

我正在研究一种Google Chrome浏览器扩展,该扩展将所有段落(p标记内容)并将每个单词放入按钮中。这是我正在开发的一个更大程序的一部分。我在JSFiddle上有该应用程序部分的工作副本。用包含该文本的按钮替换网页段落中的每个词

现在,我试图将该代码移植到Chrome扩展程序中。但是,我无法从后台脚本访问DOM,因此可以使用我的代码操作它(在我的函数中)。我还没有调用该函数,因为我无法弄清楚我应该如何在background.js内首先编辑DOM。

这里是我的代码:

manifest.json的

{ 
    "manifest_version": 2, 
    "name": "Test Extension", 
    "version": "1", 
    "background": { 
    "persistent": false, 
    "scripts": ["background.js","jquery-3.0.0.min.js","TextSplitter.js"] 
    }, 
    "content_scripts": [{ 
    "matches": ["<all_urls>"], 
    "js": ["content.js"] 
    }], 
    "browser_action": { 
    "default_title": "Test Extension" 
    }, 
    "permissions": ["activeTab","tabs"] 
} 

content.js

// Listen for messages 
chrome.runtime.onMessage.addListener(function (msg, sender, sendResponse) { 
    // If the received message has the expected format... 
    if (msg.text === 'report_back') { 
     // Call the specified callback, passing 
     // the web-page's DOM content as argument 
     sendResponse(document); 
    } 
}); 

background.js

// A function to use as callback 
function doStuffWithDom(domContent) { 
    console.log('I received the following DOM content:\n'); 
    console.log(JSON.stringify(domContent)); 
    var domAccess = $(domContent); 
    var myText = $(domAccess).find("p").text(); 
    console.log("THIS IS MY TEXT: " + myText); 
} 

chrome.tabs.onUpdated.addListener(function (tabID, info, tab) { 
    console.log("Status: " + info.status); 
    if (info.status == "complete") { 
     chrome.tabs.sendMessage(tab.id, { text: 'report_back' }, doStuffWithDom); 
    } 
}); 

TextSplitter.js

function FormatText(domObject) { 
    var pElements = []; // Holds the split paragraphs for each p tag 
    var pElementIndex = 0; 

    //Loop through each p tag in web page 
    $("p").each(function (webPElementIndex, webPElement) { 
     var jQObjWebPElement = $(webPElement);// Convert p element to jQuery Obj 
     // split current paragraph element text into an array of seperate words 
     pElements[webPElementIndex] = jQObjWebPElement.text().split(" "); 
    }); 

    //Clear text out of all p elements 
    $("p").empty(); 

    //Loop through p elements in the webpage to add back text with spans around each word 
    $("p").each(function (webPElementIndex, webPElement) { 
     // convert current web page element to jQuery Obj 
     var jQObjWebPElement = $(webPElement); 
     // Loop through each word stored in each stored paragraph element 
     $.each(pElements[pElementIndex], function (pElementWordIndex, pElementWord) { 
      var jQObjPElementWord = $(pElementWord); // convert element to jQuery object 
      jQObjWebPElement.append($("<button>") 
          .text(pElements[pElementIndex][pElementWordIndex])); 
     }); 
     pElementIndex = pElementIndex + 1; 
    }); 
} 

请原谅我的无知,我是很新的,在一般的DOM的工作,特别是在浏览器扩展程序。

+2

请参阅[扩展概述](https://developer.chrome.com/extensions/overview#arch):您需要一个内容脚本。 – wOxxOm

+0

删除您的后台脚本并将您的功能转移到您的内容脚本。处理和修改html应该在内容脚本中完成,因为你的后台脚本不能直接访问dom。无需传递消息 – nick

回答

3

您的代码在几个区域显得过于复杂。特别是,DOM只能从内容脚本中操作。正如wOxxOm在评论中提到的那样,阅读Chrome extension architecture overview将是一个好主意。它具有整体架构信息,可以帮助您了解事物通常是如何完成/组织的。

以下完整扩展(在Chrome和Firefox上测试)会将空白字符(或行/段落的开头或结尾)包围的所有非空格字符更改为<button>。它在浏览器用户界面中单击actionButton时执行此操作。

单击actionButton时,将注入contentScript.js文件。内容脚本进行更改并退出。对于此功能,不需要位于页面中的内容脚本等待获取消息以执行简单功能。您实际上可能做的比您使用代码描述/展示的要多,但对于问题中提到的功能,使用tabs.executeScript()注入脚本是一种更好,更简单,更高效的选择。

我选择不使用jQuery。 jQuery对很多事情都有好处。在这种情况下,我不喜欢加载90 KiB代码来节省几个字符,而不是用股票JavaScript来完成同样的事情。

我没有仔细看看用于执行按钮化的代码。我已经有another answer的代码可以很容易地适应执行这项任务。鉴于你的问题是关于如何操作DOM,而不是关于你的按钮代码的功能,我选择使用我已经熟悉的代码。

扩展在行动:

button-izing example.com

的manifest.json

{ 
    "description": "Inject content script to make all words in <p> elements buttons", 
    "manifest_version": 2, 
    "name": "Button all words in <p>", 
    "version": "0.1", 

    "permissions": [ 
     "activeTab" 
    ], 

    "background": { 
     "scripts": [ 
      "background.js" 
     ] 
    }, 

    "browser_action": { 
     "default_icon": { 
      "32": "myIcon.png" 
     }, 
     "default_title": "Make Buttons" 
    } 
} 

background.js

chrome.browserAction.onClicked.addListener(function(tab) { 
    //Inject the script to change the text in <p> to buttons 
    chrome.tabs.executeScript(tab.id,{file: 'contentScript.js'}); 
}); 

contentScript.js

(function(){ 
    function handleTextNode(textNode) { 
     if(textNode.nodeName !== '#text' 
      || textNode.parentNode.nodeName === 'SCRIPT' 
      || textNode.parentNode.nodeName === 'STYLE' 
     ) { 
      //Don't do anything except on text nodes, which are not children 
      // of <script> or <style>. 
      return; 
     } 
     let origText = textNode.textContent; 
     let newHtml=origText.replace(/(^|\s)(\S+)(?=\s|$)/mg, '$1<button>$2</button>'); 
     //Only change the DOM if we actually made a replacement in the text. 
     //Compare the strings, as it should be faster than a second RegExp operation and 
     // lets us use the RegExp in only one place for maintainability. 
     if(newHtml !== origText) { 
      let newSpan = document.createElement('span'); 
      newSpan.innerHTML = newHtml; 
      textNode.parentNode.replaceChild(newSpan,textNode); 
     } 
    } 

    //Find all text node descendants of <p> elements: 
    let allP = document.querySelectorAll('p'); // Get all <p> 
    let textNodes = []; 
    for (let p of allP) { 
     //Create a NodeIterator to get the text nodes descendants of each <p> 
     let nodeIter = document.createNodeIterator(p,NodeFilter.SHOW_TEXT); 
     let currentNode; 
     //Add text nodes found to list of text nodes to process below. 
     while(currentNode = nodeIter.nextNode()) { 
      textNodes.push(currentNode); 
     } 
    } 
    //Process each text node 
    textNodes.forEach(function(el){ 
     handleTextNode(el); 
    }); 
})(); 

myIcon.png

Icojam-Weathy-24-tornado.png

handleTextNode的代码进行修改,文本节点从代码another answer of mine修改。