我正在构建Chrome扩展程序。我正在尝试让我的应用与扩展程序中的每个页面以及用户在浏览器中查看的页面进行通信。我需要从扩展名访问dom,然后对其进行更新。
manifest.json
popup.html
popup.js
background.js
content.js
以及用户正在查看的当前页面。
我的目标是在页面加载中修改dom,并在用户看到页面之前向其显示页面的新版本。在popup.js
中,允许用户在弹出窗口中输入关键字。关键字被保存到localStorage
,并且在他们查看网页时,如果隐藏关键字的父级div(如果在他们正在查看的任何页面上都可以找到),则该关键字将被隐藏。
我需要帮助让每个页面进行交流,我认为我在popup.js中隐藏父div的方式将行不通。我对如何从正面对dom进行操作感到困惑。
将dom发送到background.js在页面上找到关键字,然后将其父div更改为隐藏。将dom推回查看页面。
我认为这行是在说我是否匹配任何URL,然后运行我的应用程序,但不确定。
"matches": ["*://*/*"],
我的manifest.json
{
"name": "Wuno Zensoring",
"version" : "1.0",
"permissions": [
"activeTab",
"tabs",
"storage"
],
"description": "This extension will search the document file for keywords and hide their parent div.",
"icons": {
"19": "icon19.png",
"38": "icon38.png",
"48": "icon48.png",
"128": "icon128.png"
},
"background": {
"persistent": false,
"scripts": ["jquery-1.11.3.min.js","background.js"]
},
"content_scripts": [{
"matches": ["*://*/*"],
"js": ["content.js"],
"run_at": "document_end",
"all_frames": true
}],
"web_accessible_resources": [
"popup.js", "content.js"
],
"browser_action": {
"default_icon": "icon.png128",
"default_popup": "popup.html",
"default_icon": {
"19": "icon19.png",
"38": "icon38.png",
"48": "icon48.png",
"128": "icon128.png"
}
},
"manifest_version": 2
}
popup.html
<!doctype html>
<html>
<head>
<title>Wuno Zensorship</title>
<script src="jquery-1.11.3.min.js"></script>
<script src="popup.js"></script>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<img src="icon48.png">
<section>
<form id="form" action="#" method="POST">
<input id="description" name="description" type="text" />
<input id="add" type="submit" value="Add" />
<button id="clearChecked">Clear Checked Items</button>
<button id="clear">Clear All</button>
</form>
<div id="alert"></div>
<ul id="keyWords"></ul>
</body>
</html>
popup.js
$(document).ready(function () {
localArray = [];
if (!localStorage.keyWords) {
localStorage.setItem('keyWords', JSON.stringify(localArray));
}
loadKeyWords();
function loadKeyWords() {
$('#keyWords').html('');
localArray = JSON.parse(localStorage.getItem('keyWords'));
for(var i = 0; i < localArray.length; i++) {
$('#keyWords').prepend('<li><input class="check" name="check" type="checkbox">'+localArray[i]+'</li>');
}
}
$('#add').click( function() {
var Description = $('#description').val();
if($("#description").val() === '') {
$('#alert').html("<strong>Warning!</strong> You left the to-do empty");
$('#alert').fadeIn().delay(1000).fadeOut();
return false;
}
$('#form')[0].reset();
var keyWords = $('#keyWords').html();
localArray.push(Description);
localStorage.setItem('keyWords', JSON.stringify(localArray));
loadKeyWords();
return false;
});
$('#clear').click( function() {
window.localStorage.clear();
location.reload();
return false;
});
$('#clearChecked').click(function() {
currentArray = [];
$('.check').each(function() {
var $curr = $(this);
if (!$curr.is(':checked')) {
var value = $curr.parent().text();
currentArray.push(value);
localStorage.setItem('keyWords', JSON.stringify(currentArray));
loadKeyWords();
} else {
$curr.parent().remove();
}
});
});
// Update the relevant fields with the new data
function setDOMInfo(info) {
$("div p:contains(localStorage.getItem('keyWords')).parent('div').hide()");
}
// Once the DOM is ready...
window.addEventListener('DOMContentLoaded', function () {
// ...query for the active tab...
chrome.tabs.query({
active: true,
currentWindow: true
}, function (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);
});
});
}); // End of document ready function
background.js
chrome.runtime.onMessage.addListener(function (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(function (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);
}
});
您需要使用此查询将数据从正在查看的当前选项卡发送到DOM。
chrome.tabs.executeScript(null, {
code: 'var config = ' + JSON.stringify(getKeywords)
}, function() {
chrome.tabs.executeScript(null, {file: 'custom.js'});
});
并且在custom.js
文件中,您可以编写要应用于DOM元素的函数。例如,如果您想隐藏某些东西,而不需要custom.js
中的查询。因此,如果您想使用该示例,则需要根据需要对其进行修改。
var all = document.getElementsByTagName("div");
var searchValue=config.toString().split(',');
alert('Example:' + searchValue[0]);
for(j=0; j < searchValue.length; j++) {
for(i=0; i < all.length; i++) {
if(all[i].innerHTML.indexOf(searchValue[j]) > -1){
all[i].innerHTML = ""
}
}
}
您应该从background.js或popup.js发送命令,接收该命令并更改content.js中的dom。下面的代码演示了一个简单的场景:单击browserAction并将div附加到当前页面。您可以使用相同的逻辑来显示/隐藏任何元素。
manifest.json
{
"name": "Test",
"version": "1.0",
"permissions": [
"tabs"
],
"description": "Test",
"background": {
"persistent": false,
"scripts": [
"background.js"
]
},
"content_scripts": [
{
"matches": [
"*://*/*"
],
"js": [
"content.js"
],
"run_at": "document_end",
"all_frames": true
}
],
"browser_action": {
"title": "Test"
},
"manifest_version": 2
}
background.js
chrome.browserAction.onClicked.addListener(function() {
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {command: "append"}, function(response) {
console.log(response.result);
});
});
});
content.js
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
console.log(request.command);
var div = document.createElement('div');
var label = document.createElement('span');
label.textContent = "Hello, world";
div.appendChild(label);
document.body.appendChild(div);
sendResponse({result: "success"});
});
我试图像以往一样简单地回答这个问题,因为对代码的更改较少,您将很快学习遵循的方法。
通常,当最终用户在弹出窗口上按下“开始”按钮时,请编写以下代码行(请参阅您的popup.js):
chrome.runtime.sendMessage({key:'popupInit'},function(response){;});window.close(); //此行关闭弹出窗口
非常重要的是要了解响应不是通信系统,而只是来自相应侦听器的即时响应。对我来说,监听器是background.js。在此文件中,您可以利用localStorage的优势,这样您可以拥有类似的东西:
chrome.tabs.onUpdated.addListener(function(tabid, changeInfo, tab) {
if (typeof changeInfo.status == 'string' && changeInfo.status == 'complete') {
chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
var keyString = JSON.parse(localStorage.getItem('keyWords'));
chrome.tabs.sendMessage(tabs[0].id, {key: 'init', wordToHide: keyString}, function (response) {
;
});
});
}
});
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
var rq = request.key;
if (rq != undefined && typeof rq == 'string') {
switch (rq) {
case 'popupInit':
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
var keyString = JSON.parse(localStorage.getItem('keyWords'));
chrome.tabs.sendMessage(tabs[0].id, msgToSend, function(response) {
;
});
});
break;
}
}
});
chrome.tabs.onUpdated.addListener很重要,因为每次更新当前活动页面时,您都可以将消息发送到获取本地存储中的值的内容脚本,当弹出窗口关闭并且有单词时也会发生同样的情况在localstorage中,您可以使用chrome.runtime.onMessage.addListener侦听信号:弹出窗口已关闭,因此在内容脚本中开始工作,向其发送包含单词数组的消息。
现在让我们看一下您的content.js文件。
// Listen for messages from the backgound.js
chrome.runtime.onMessage.addListener(function (msg, sender, response) {
// First, validate the message's structure
if ((msg.key === 'init') && (Object.prototype.toString.call(msg.wordToHide) === '[object Array]')) {
var elements = document.querySelectorAll("body, body *");
var results = [];
var child;
var regwordToHide = [];
if (msg.wordToHide.length > 0) {
msg.wordToHide.forEach(function(element, index, array) {
regwordToHide.push(new RegExp('\\b' + element + '\\b', 'g'));
});
}
for(var i = 0; i < elements.length; i++) {
child = elements[i].childNodes[0];
if (elements[i].hasChildNodes() && child.nodeType == 3) {
var nodeStr = child.textContent;
if (nodeStr.trim().replace(/\n\r\t/g, '').length > 0 && nodeStr.trim().charAt(0) != '<') {
regwordToHide.forEach(function(element, index, array) {
nodeStr = nodeStr.replace(element, '');
});
child.textContent = nodeStr;
}
}
}
document.getElementsByTagName("html")[0].style.visibility = "visible";
}
});
document.getElementsByTagName("html")[0].style.visibility = "hidden";
我尝试隐藏整个页面:请注意这一点,因为它可能很复杂(请记住,最终用户在页面加载时必须始终看到某些东西。...。]]
[之后,content.js等待来自后台的消息,当这种情况发生时,内容脚本开始工作!仅此而已。
对不起,我的写作混乱。如果您需要其他帮助,请告诉我。我测试了您的分机,并在您可以看到的地方对其进行了更正。
对于Chrome扩展程序中组件之间的通信,您需要记住:
要发送/接收消息,您可以看一下Chrome messaging
sendResponse和response仅用于即时检查通信:类似:Hello->好的,我明白了,现在我自己继续。
我也完成了您的文字替换部分!
如@SølveTornøe所说: