如何在Google Chrome中制作工具栏?

26

我第一次探索Google Chrome扩展程序。我想创建一个当你点击扩展图标时出现在页面顶部的工具栏,就像StumbleUpon工具栏一样。

我不知道如何做到这一点。大多数例子都显示popup.html,而不是固定的工具栏。


虽然你无法向Chrome添加工具栏,但你可以添加按钮。这样可以实现你想要的功能。请参考这个扩展创建的例子:http://lifehacker.com/5857721/how-to-build-a-chrome-extension - Dave Alperovich
你只要求了Chrome浏览器,但你是否愿意使用跨浏览器扩展,提供一个工具栏在Chrome、IE、Firefox和Safari中,并允许您在工具栏和扩展脚本之间进行通信?如果您不希望针对所有浏览器,可以将其限制为仅Chrome扩展,但您将拥有去任何浏览器的灵活性。如果这是一种选择,我会在这里发布代码以及如何完成。我也可以提供如何进行跨域请求的示例,并为您提供浏览器按钮。如果这符合您的需求,请告诉我。 - Matt Mullens
看看这个Chrome截图:http://www.howtogeek.com/138516/the-shameful-saga-of-uninstalling-the-terrible-ask-toolbar/ - Ming-Tang
4个回答

50

尽管这个答案展示了两种在Chrome中创建工具栏的方法,但我强烈建议使用页面操作浏览器操作徽章。它们不占用像工具栏那样多的空间,还可以用于在单击时显示面板,甚至获取临时主机权限与页面交互。

chrome.infobars API

这个部分曾经展示了一个使用chrome.infobars API的演示。该API从未进入稳定频道,并且将被删除;请不要使用它。

chrome.sidebar API

2015年有一个关于侧边栏API的提议,作为chrome.infobars(上文已描述)的替代方案。但是,这个想法在2016年被拒绝,以优先考虑“Chrome的简洁核心价值”(来源)。

似乎没有办法在Chrome中创建“高级”工具栏,而不将其放置在文档窗口中。

内容脚本

使用内容脚本创建工具栏是棘手的。您必须插入页面中的代码,并甚至修改文档的结构,这可能会破坏互联网上的某些页面。

要使用内容脚本创建工具栏,必须执行以下步骤:

  1. 在页面上执行一个内容脚本,运行接下来的两个步骤。
  2. 插入工具栏(<iframe> - 以后会解释)。
  3. 移动页面的内容。

第1步很容易,可以参考我的先前示例或阅读内容脚本的文档。

第2步:插入工具栏

为了最小化样式冲突并防止页面使用您的工具栏,请插入一个iframe。与之前的方法不同,您没有直接访问扩展API(因为嵌入的页面既不是内容脚本,也不是在扩展的进程中运行的页面)。

插入工具栏:

add-toolbar.js(内容脚本)

var height = '40px';
var iframe = document.createElement('iframe');
iframe.src = chrome.runtime.getURL('toolbar.html');
iframe.style.height = height;
iframe.style.width = '100%';
iframe.style.position = 'fixed';
iframe.style.top = '0';
iframe.style.left = '0';
iframe.style.zIndex = '938089'; // Some high value
// Etc. Add your own styles if you want to
document.documentElement.appendChild(iframe);

现在创建一个名为 toolbar.html 的文件,并将其添加到您的清单文件的"web_accessible_resources"部分。这个文件将用于工具栏的位置,可以自由地进行任何非恶意操作。只需记住它的作用类似于普通网页,它实际上没有访问Chrome API的权限。

步骤3:移动内容

到目前为止,您只是在页面上添加了一个框架,但存在一个问题:页面上的内容被部分隐藏了。这不太好。有几种方法可以解决这个问题,我选择使用CSS transforms,因为它相对容易使用,并且大多数页面不会在body元素上使用此属性。

// continuing add-toolbar.js
var bodyStyle = document.body.style;
var cssTransform = 'transform' in bodyStyle ? 'transform' : 'webkitTransform';
bodyStyle[cssTransform] = 'translateY(' + height + ')';

translateY会导致页面向下移动,包括带有position:fixed属性的子元素。由于我们将iframe附加到根元素而不是<body>标签内部,所以该元素不受影响。

我想在工具栏中使用扩展API!

不幸的是,Chrome将嵌入的HTML页面视为非特权扩展页面。您只能使用一些扩展API(类似于内容脚本)。

另一个选择是从服务器加载页面,然后在该特定页面上执行内容脚本。设置缓存清单以确保如果用户断网时仍可使用您的工具栏。


@ShikataGaNai 没有问题。为什么你想要创建一个工具栏?也许有更好的选择。工具栏通常不是Chrome扩展的最佳选择。 - Rob W
@RobW,感谢您的回答!自从您关于这个实验性API的写作已经过去了半年;我有一个后续问题,如果可以的话:https://dev59.com/Rnzaa4cB1Zd3GeqPKgfO - cnst
非常感谢,我已经按照这个例子操作了,但是我不理解你最后一条评论关于使用localStorage和postMessage来使用扩展API的意思。我在我的工具栏中使用了一些Chrome API,只要在后台脚本中正确处理,chrome.runtime.sendMessage就足以获取数据或调用Chrome API。 - ekcrisp
1
很遗憾,Chrome浏览器中存在一个错误,会破坏页面主体中的每个固定元素。https://code.google.com/p/chromium/issues/detail?id=20574 - HaNdTriX
2
@HaNdTriX 这不是一个错误,而是一种特性。在这种情况下,正是你想要的,因为你想向下移动视口(包括固定大小的元素)。不幸的是,像YouTube和Facebook这样的网站使用JavaScript来实现动态顶部栏,这些计算会被变换所混淆。YouTube的工具栏消失了,Facebook的工具栏也不再粘着。 - Rob W
显示剩余7条评论

3

Chrome API没有任何工具栏小部件可以帮助您。您需要在页面上手动创建和定位工具栏div。您可以利用内容脚本来完成此操作,这允许您向页面注入javascript和css。


0

iframe 可能会受到限制,但允许发送消息。因此有一种方法可以使用 扩展 API 与 iframe。 第一步是向后端发送消息(在 Manifest V3 中使用 Service Worker)。 然后将消息发送回所有选项卡(如果没有侦听器等,则使用 try catch)。 这也会将消息发送到 add-Toolbar.js 和您的 iframe 中。(因此我在消息中有一个接收者 ID) 在 add-Toolbar.js 中处理消息并在那里进行 API 调用。由于 add-Toolbar.js 在正常范围内,所以这是允许的。如果您想在 iframe 中处理响应,请通过后端将其发送回。


0
这个工具可以为多种浏览器提供类似于StumbleUpon的浏览器扩展,但如果您希望,也可以将下载限制为仅适用于Chrome。 安装程序 一般的安装页面(如果您使用Windows系统,则提供可执行文件以便签名,以简化安装过程):

http://crossrider.com/apps/35180/install_page

具体安装:

Crossrider还可以轻松地发布到Chrome商店,并提供了一种简单的方式来为Windows上的可执行下载签署您的扩展。

信息

这里是API文档,对于跨浏览器解决方案来说非常全面:

http://docs.crossrider.com/

在下面的代码中,我没有放置HTML和CSS,因为答案的字符数有限。但是,如果看起来不错,您可以打开它(crx是zip文件,只需将扩展名改为.zip),以获取其中的CSS和HTML,或者我们可以想出一种方法让我将其发送给您。请注意,我正在将HTML和CSS注入页面中。
我通常先编写CSS和HTML,然后对两者进行缩小处理(http://cssminifier.com/http://www.willpeavy.com/minifier/),然后我使用字符串转义工具(例如http://www.htmlescape.net/stringescape_tool.html)对缩小的输出进行转义,以便将其放入扩展代码中,因为您希望它尽可能快,毕竟这是一个扩展程序,而不是网页。

如果您觉得这个看起来不错,请前往crossrider.com,设置一个账户(它是100%免费的),并将这些文件粘贴到适当的位置,并在下面的extension.js中放入所需的缩小/转义HTML和CSS,替换cssstr和htmlstr中的内容。

代码

extension.js:

appAPI.ready(function($) {
    // Place your code here (you can also define new functions above this scope)
    // The $ object is the extension's jQuery object

    // Adds a listener that handle incoming messages
    var lid = appAPI.message.addListener(function(msg) {
        switch(msg.action) {
            case 'SHOWEXAMPLEBAR': 
            $('#examplebar-toolbar').show();
                break;
            case 'HIDEEXAMPLEBAR': 
                $('#examplebar-toolbar').hide();
                break;
            default: 
                break;
         }
    });

    // Add toolbar (not included here due to size - be sure it is escaped)
    var cssstr = '/* The CSS of your toolbar */';

    // Add toolbar HTML (not included here due to size - be sure it is escaped)
    var htmlstr = '\x3C!-- the html of your toolbar --\x3E';

    $('\x3Cstyle\x3E'+cssstr+'\x3C/style\x3E' + htmlstr).prependTo('body');
    $('#examplebar-close').click(function() {
        //Tell the background to change its buttonstate:
        $('#examplebar-toolbar').hide();
        appAPI.message.toBackground({action: "HIDEEXAMPLEBAR"});
    });
});

background.js:

// Note: the $ variable that represents the jQuery object is not available
//       in the background scope
appAPI.ready(function() {
    // Global variable to hold the toggle state of the button
    var buttonState = true;

    // Sets the initial browser icon
    appAPI.browserAction.setResourceIcon('button.png');

    // Sets the tooltip for the button
    appAPI.browserAction.setTitle('Bar');

    // Sets the text and background color for the button
    if (appAPI.browser.name !== 'safari') {
        appAPI.browserAction.setBadgeText('bar');
        appAPI.browserAction.setBadgeBackgroundColor([255,0,0,50]);
    }else{
        // Safari only supports numeric characters
        // and has a fixed background color
        appAPI.browserAction.setBadgeText('1234');
    }

    // Sets the initial onClick event handler for the button
    appAPI.browserAction.onClick(function(){
        if (buttonState) {
            //Hide the toolbar by notifying the extension code:
            appAPI.message.toAllTabs({action: "HIDEEXAMPLEBAR"});
            if (appAPI.browser.name !== 'safari') {
            // Sets the text and background color for the button
            // using the optional background parameter
                appAPI.browserAction.setBadgeText('helo', [0,0,255,255]);
                // Sets the icon to use for the button.
                appAPI.browserAction.setResourceIcon('button.png');
            } else {
                // Safari only supports numeric characters,
                // has a fixed background color,
                // and can only use the extension's icon
                appAPI.browserAction.setBadgeText('4321');
            }
        } else {
            appAPI.message.toAllTabs({action: "SHOWEXAMPLEBAR"});
            // Remove the badge from the button
            appAPI.browserAction.removeBadge();

            if (appAPI.browser.name !== 'safari'){
                // Reset the icon for the image
                appAPI.browserAction.setResourceIcon('button.png');
            }
        }

        // Toggle the state
        buttonState = !buttonState;
    });

    // Adds a listener that handle incoming messages
    var lid = appAPI.message.addListener(function(msg) {
        switch (msg.action) {
            case 'HIDEEXAMPLEBAR': 
            buttonState = !buttonState;
            break;
            default:
                break;
        }
    });    
});

注意事项

请注意,jQuery自动在扩展范围内可用,因此您可以免费获得API和jQuery。如果您想要注入iframe,请确保不要忘记在设置中启用iframes。

有关社区支持网站:https://getsatisfaction.com/crossrider

他们非常负责并且可以在您遇到问题时提供帮助。


由于Cross-rider不提供内置工具栏,因此使用它与Chrome API相比几乎没有优势。Firefox、Safari、Internet Explorer和Opera(15之前的版本)提供了用于创建工具栏的本地API。本答案中的方法基本上是serg答案的应用,只是在另一个层面(框架)中。对于自定义工具栏,应该真正使用iframe,因为当前提出的解决方案容易失败,因为它可以被页面控制/样式化。 - Rob W
不管怎样,只要能够最好地解决问题就行。为所有平台开发这个应用大约需要20分钟,所以幸运的是没有浪费投资。我想说的优点有:单一代码库、所有平台使用相同的API、几乎零努力等等。但无论如何,我都追求适合工作的正确工具。而且使用crossrider简化了iframe的操作,正如我在底部的注释中提到的。如果不必要,为什么要费心去处理XPI、CRX和BHO之间的微妙差别呢?当然,如果只有Chrome才提供某些功能...但如果不需要,为什么要费事呢? - Matt Mullens

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接