我正在开发一个Google Chrome扩展程序,它会记录所有段落(p标记内容),并将每个单词放在一个按钮中。这是我正在开展的一个更大的计划的一部分。我在JSFiddle上有应用程序该部分的工作副本。
现在,我正在尝试将该代码移植到Chrome扩展程序中。但是,我无法从后台脚本访问DOM,因此我可以使用我的代码(在我的函数FormatText()
中)操作它。我还没有调用该函数,因为我无法弄清楚我应该如何在 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,特别是在Chrome扩展程序中。
答案 0 :(得分:3)
您的代码在某些方面显得过于复杂。特别是,DOM只能从内容脚本中操作。正如评论中提到的wOxxOm,您最好阅读Chrome extension architecture overview。它具有整体架构信息,可以帮助您了解事情通常如何完成/组织。
以下完整扩展程序(在Chrome和Firefox上测试)会将由空白字符(或行/段落的开头或结尾)包围的所有非空白字符更改为<button>
。当在浏览器用户界面中单击actionButton
时,它会执行此操作。
单击actionButton
时,会注入 contentScript.js 文件。内容脚本进行更改和退出。对于此功能,不需要位于页面中的内容脚本等待获取消息以执行简单功能。实际上,您可能做的事情比您用代码描述/显示的要多,但是对于问题中提到的功能,使用tabs.executeScript()
注入脚本是一种更好,更简单,更有效的选择。
我选择不使用jQuery。 jQuery很适合很多东西。在这种情况下,我不喜欢加载90 KiB代码以节省几个字符而不是用库存JavaScript完成同样的事情。
我没有仔细查看您用于执行按钮化的代码。我已经在another answer中有了代码,可以很容易地适应这项任务。鉴于您的问题是关于如何操作DOM,而不是关于按钮化代码的功能,我选择使用我已经熟悉的代码。
行动中的扩展:
的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 :
handleTextNode
中用于修改文本节点的代码已从another answer of mine中的代码修改。