2016-11-11 21 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修改。