3.5 Omnibox

Chrome和其他浏览器相比一个最大的区别就是地址栏——其实不仅仅是地址栏,而是一个多功能的输入框,Google将其称为omnibox(中文为“多功能框”)。我们熟悉的一个功能就是用户可以直接在omnibox搜索关键字,Chrome也将omnibox开放给开发者,这使得omnibox更加强大。

要使用omnibox需要在Manifest的omnibox域指定keyword

"omnibox": { "keyword" : "hamster" }

同时最好指定一个16像素的图标,当用户键入关键字后,这个图标会显示在地址栏的前端。

"icons": {
    "16": "icon16.png"
}

Chrome会自动将这个图标渲染成灰度图标,而无需开发者指定一个灰度的图标,由于右键菜单等其他地方也会用到16像素的图标,所以应该指定一个彩色的图标。

Omnibox只提供了一个方法,就是setDefaultSuggestion,这个方法用来定义默认建议。对于这个默认建议用文字怎么讲解恐怕都不容易讲清楚,那么不妨来看一看设置了默认建议和不设置默认建议的对比:

enter image description here
未设置默认建议和设置了默认建议的对比

上图中左侧为未设置默认建议,显示为“运行 XXX 命令:XXX”,这样显然看起来不够友好。右侧则用更加友好的方式显示查询当前美元价格。

默认建议会在用户输入keyword之后一直显示在地址栏下方并且紧挨着地址栏,所以设定一个默认建议是必要的,否则简单地显示“运行 XXX 命令:XXX”会让用户摸不到头脑。

Omnibox有四种事件:onInputStartedonInputChangedonInputEnteredonInputCancelled,分别用于监听用户开始输入、输入变化、执行指令和取消输入行为。其中执行指令是指用户敲击回车键或用鼠标点击建议结果。

onInputStarted(function(){console.log('Input started.')});
onInputCancelled(function(){console.log('Input cancelled.')});

上面的代码执行后,用户开始输入和取消输入时,都会在控制台记录相应日志。下面我们重点来讲一讲另外两个事件。

onInputChanged事件所承接的只有一个function类型的参数,这个function参数又有两个承接参数,第一个参数是字符串型,值为用户当前的输入值,第二个参数还是function型,用于返回建议结果,建议的结果为数组型数据,数组中的元素是建议结果对象。

chrome.omnibox.onInputChanged.addListener(function(text, suggest){
    suggest([{
        content: text,
        description: 'Search '+text+' in Wikipedia'
    }]);
});

onInputEntered事件同样只有一个function类型的承接参数,这个function有两个承接参数,第一个是用户输入的值,字符串型,第二个是对结果的建议打开方式,字符串型,但取值范围固定。

chrome.omnibox.onInputEntered.addListener(function(text, disposition){
    switch(disposition){
        case 'currentTab': //do something in the current tab
                 break;
        case 'newForegroundTab': //do something in a new tab and active it
                 break;
        case 'newBackgroundTab': //do something in a new tab
                 break;
    }
});

下面来制作一款实时查询美元价格的扩展。首先通过异步请求获取Yahoo上美元的价格,对这部分不熟悉的读者可以参考前面2.2节的内容。获取到数据后我们就要开始编写提供建议的函数了。

function updateAmount(amount, exchange){
    amount = Number(amount);
    if(isNaN(amount) || !amount){
        exchange([{
            'content': '$1 = ¥'+price,
            'description': '$1 = ¥'+price
        },{
            'content': '¥1 = $'+(1/price).toFixed(6),
            'description': '¥1 = $'+(1/price).toFixed(6)
        }]);
    }
    else{
        exchange([{
            'content': '$'+amount+' = ¥'+(amount*price).toFixed(2),
            'description': '$'+amount+' = ¥'+(amount*price).toFixed(2)
        },{
            'content': '¥'+amount+' = $'+(amount/price).toFixed(6),
            'description': '¥'+amount+' = $'+(amount/price).toFixed(6)
        }]);
    }
}

var url = 'http://query.yahooapis.com/v1/public/yql?'+
          'q=select%20Rate%20from%20'+
          'yahoo.finance.xchange%20'+
          'where%20pair%20in%20(%22USDCNY%22)&'+
          'env=store://datatables.org/alltableswithkeys&'+
          'format=json';
var price;

httpRequest(url, function(r){
    price = JSON.parse(r);
    price = price.query.results.rate.Rate;
    price = Number(price);
});

chrome.omnibox.onInputChanged.addListener(updateAmount);

大家可以对照前面所讲解的部分来看这段代码,代码中的每个部分都与前面的讲解有所对应。接下来编写用户执行指令时所运行的函数。

function gotoYahoo(text, disposition){
    window.open('http://finance.yahoo.com/q?s=USDCNY=X');
}

chrome.omnibox.onInputEntered.addListener(gotoYahoo);

此例中并没有理会disposition的取值,Chrome官方也指出disposition只是给出结果呈现的建议方式,而非必须遵循的方式,所以是否理会这个值由你自己说了算。

最后就像前面所说的那样,记得设定一个默认的建议,这样会使你的扩展看起来更加友好。

前面讲解默认建议的截图就是这个例子运行的结果,所以在此就不重复贴图了。本例的完整代码可以通过https://github.com/sneezry/chrome_extensions_and_apps_programming/tree/master/usd_price下载,载入扩展后在浏览器地址栏中输入“usd”后按空格键或Tab键就可以使用。