chrome扩展程序
构建Chrome扩展程序很容易,而且从很多方面来说都是如此。 该文档确实做得很好,并且包含大量示例。 另外,检查已安装的任何组件以查看其背后的魔力很容易。 另一个很大的优点是,它全都是Javascript,CSS和HTML,并带有Chrome API的额外奖励,可让您额外获得一点点魔术。
最近,我不得不为我的公司开发一个工具栏,该工具栏必须阅读当前查看的页面,显示一些SEO信息,进行一些AJAX调用等。 并不是很困难,但是我确实发现了一个没有得到充分记录的问题(如果有的话)。
在继续进行之前,如果您对Chrome扩展程序的开发不完全了解,建议您阅读本概述 。 您将了解有关架构多层之间的复杂性的更多信息。
我决定通过在每个网页中注入iframe来加载扩展程序的UI元素(如工具栏和其他弹出窗口)。 考虑到这一点,在多个iframe ,当前DOM,Chrome后台Javascript文件和Chrome提供的其他层之间进行通信并不是一件容易的事。
实际上,问题出在使用iframe上 。 我必须通过JSON对象从Background层向任何iframe发送大量数据,反之亦然。 由于跨域限制,无法通过页面中插入的内容脚本来操纵iframe 。
例如,当前查看的页面URL是
http://www.example.com
并且注入的iframe URL是
chrome-extensions:// uniqueidmadeoutoflotsandlotsofletters
两者之间的通信是不可能的,因为跨域通信是一个很大的问题。
好吧, iframe是(当前)隔离大量Javascript,CSS和HTML的唯一方法,而不受当前网页样式和行为的影响。
另外,我很固执,以为可能存在一种以优雅的方式在所有层之间进行通信的方法。 即使我在Google或StackOverflow上找不到答案。
使用Chrome API方法chrome.tabs.sendMessage从“背景”层发送消息时,该消息将发送到所有帧,而不仅仅是发送了ContentScript的消息。
我不知道为什么我没有想到这一点!
由于它的ContentScript内喷射的内部框架 ,而且也能获得到Chrome API。
因此, iframe可以使用默认的DOM方法window.parent.postMessage与其父ContentScript进行对话,并通过chrome.extension.sendRequest与Background层进行对话,并且还可以使用chrome.extension.onMessage来监听Background层消息。 addListener方法。
这个想法很简单:我创建了一组接待员 ,负责处理从一层到另一层的所有消息传输。
当前,这是我设置各层角色的方式:
可以从ContentScript接收消息,然后将它们重定向到适当的iframe或处理消息。
全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。
原价$ 11.95 您的完全免费
可以将消息发送到所有框架(ContentScript和iframe )。
可以同时从Background层和iframe接收消息。
当来自iframe时 (通过默认的window.postMessage方法),它将消息重定向到Background(如果指定)。 如果未指定,它将处理该消息。
只能将消息发送到后台。
可以从唯一的Background层接收消息,然后检查它是否适合他,然后处理该消息。
可以使用window.parent.postMessage将消息发送到ContentScript。
换句话说:
–背景与ContentScript和iframe对话,但仅收听ContentScript。
– ContentScript侦听Background和iframe ,但仅侦听Background。
– iframe与ContentScript对话并收听背景。
旁注:我知道Background也可以侦听iframe消息,但是在我的示例中,由于没有必要,因此我跳过了这个概念。
每个iframe都有一个唯一的ID(在下面的示例中称为View ),因此很容易将消息重定向到特定的iframe 。 一种简单的方法是在加载iframe时在URL中添加一个属性,如下所示:
chrome.extension.getURL('html/iframe/comment.html?view=comment’);
讯息设定
传递的消息是包含两个属性的简单对象:
- 信息
–数据
每层(背景,ContentScript和IFrame)都有一个tell方法,该方法发送带有两个属性的消息。
tell(‘tell-something’, {attribute1:’a’, attribute2:’b’});
当iframe发送消息时,当前iframe 视图ID也会作为data中的源属性发送 。
tell(‘tell-parent-something’, {source:’comment’});
当需要将消息发送到特定的iframe时 ,将在数据中添加带有正确视图ID的view属性。
tell(‘tell-to-an-iframe’, {
view:’comment’,
title:’hello world!’
});
如果需要将邮件发送到所有iframe ,则可以使用“ *”通配符。
tell(‘tell-to-all-iframes’, {view:’*’, title:’foo bar’});
如果未指定视图,则应由ContentScript / Background处理消息。
我为喜欢我称为iHeart的页面创建了一个简单的扩展名(您可以在github上找到源代码)。
这是一个简单的按钮,在屏幕左侧有一个心形。 单击后,用户可以添加评论并保存。 保存的页面将在扩展弹出按钮中列出:
每层都有自己的告诉和监听方法:
讲
_this.tell = function (message, data){
var data = data || {};
chrome.tabs.getSelected(null, function (tab){
if (!tab) return;
chrome.tabs.sendMessage(tab.id, {
message : message,
data : data
});
});
};
倾听
function onPostMessage (request, sender, sendResponse){
if (!request.message) return;
if (request.data.view){
_this.tell(request.message, request.data);
return;
}
processMessage(request);
};
讲
function tell (message, data){
var data = data || {};
// send a message to "background.js"
chrome.extension.sendRequest({
message : message,
data : data
});
};
倾听
// messages coming from iframes and the current webpage
function dom_onMessage (event){
if (!event.data.message) return;
// tell another iframe a message
if (event.data.view){
tell(event.data);
}else{
processMessage(event.data);
}
};
// messages coming from "background.js"
function background_onMessage (request, sender, sendResponse){
if (request.data.view) return;
processMessage(request);
};
讲
_this.tell = function (message, data){
var data = data || {};
data.source = _view;
window.parent.postMessage({
message : message,
data : data
}, '*');
};
倾听
function background_onMessage (request, sender, sendResponse){
// make sure the message was for this view (you can use the "*" wildcard to target all views)
if (
!request.message ||
!request.data.view ||
(request.data.view != _view && request.data.view != '*')
) return;
// call the listener callback
if (_listener) _listener(request);
};
通信过程非常简单。 当您访问网页并看到所看到的内容时(它可以是任何东西,这是您想要的,我不会判断),然后单击iHeart按钮。 然后,该按钮指示打开评论iframe。
function heart_onClick (event){
$('.heart').addClass('active');
_iframe.tell('heart-clicked');
};
然后,它在ContentScript中处理消息并打开注释弹出窗口。
function processMessage (request){
if (!request.message) return;
switch (request.message){
case 'iframe-loaded':
message_onIframeLoaded(request.data);
break;
case 'heart-clicked':
message_onHeartClicked(request.data);
break;
case 'save-iheart':
message_onSaved(request.data);
break;
}
};
...
function message_onHeartClicked (data){
var comment = getView('comment');
comment.iframe.show();
tell('open-comment', {
view:'comment',
url:window.location.href,
title:document.title
});
};
出现注释弹出窗口,并在注释框下方显示当前网页标题。
js / iframe / comment.js
function onMessage (request){
switch (request.message){
case 'open-comment':
message_onOpenComment(request.data);
break;
case 'website-is-hearted':
message_onIsHearted(request.data);
break;
}
};
...
function message_onOpenComment (data){
$('.page-title').html(data.title);
};
按下保存按钮后,注释iframe会将信息发送回ContentScript。
js / iframe / comment.js
function save_onClick (event){
var comment = $('#comment').val() || '';
_iframe.tell('save-iheart', {
comment : comment
});
};
ContentScript隐藏注释iframe,并告诉Background保存整个内容。
js / inject.js
function message_onSaved (data){
var comment = getView('comment');
comment.iframe.hide();
tell('save-iheart', {
url:window.location.href,
title:document.title,
comment:data.comment
});
};
最后,Background通过将网站保存为数组来最终确定所有细节。
js / background.js
function onPostMessage (request, sender, sendResponse){
if (!request.message) return;
if (request.data.view){
_this.tell(request.message, request.data);
return;
}
switch (request.message){
case 'save-iheart':
message_onSaved(request.data);
break;
case 'all-iframes-loaded':
message_allIframesLoaded(request.data);
break;
}
};
…
function message_onSaved (data){
_websites.push({
url : data.url,
title : data.title,
comment : data.comment
});
};
就是这样。 那是我解决多种类型的层之间的通信问题的解决方案,这并不难……
现在,如果我可以轻松解决个人关系中的沟通问题,那就太好了,谢谢:P
通过处理数据验证,将喜欢的网页保存在数据库中,动态调整iframe内容的大小,为扩展添加一些动画以使其使用更加有趣,可以进一步处理该示例。 所有这些都很棒,并且已经可以实现,但这超出了本文的范围。
翻译自: https://www.sitepoint.com/chrome-extensions-bridging-the-gap-between-layers/
chrome扩展程序