如何通过我的chrome扩展注入的脚本访问jQueryUI滑块?

时间:2014-06-26 11:29:23

标签: javascript jquery jquery-ui google-chrome-extension

我制作了一个Chrome扩展程序,可以将键盘控件添加到Earbits radio

我正在尝试让鼠标滚轮改变音量。我已成功绑定鼠标滚轮事件,但我无法访问音量滑块选择器中的.slider()属性(我得到undefined is not a function)。奇怪的是,我可以从网页上的开发者控制台访问它。

这是我的manifest.json:

{
    "name": "Earbits Keyboard Controls",
    "version": "0.1",
    "description": "Adds basic keyboard controls to Earbits radio",

    "permissions": [
        "http://www.earbits.com/*"
    ],

    "content_scripts": [{
        "matches": ["http://www.earbits.com/*"],
        "js": ["jquery.js", "jquery.mousewheel.js", "jquery-ui-1.10.4.custom.min.js", "controls.js"]
    }],

    "manifest_version": 2
}

我的主脚本的相关位(我在一个区间中放置绑定的原因是我认为我无法访问该属性,因为它懒得加载):

var options = {
    keys: {
        SPACE: 32,
        LEFT: 37,
        RIGHT: 39,
        F: 70
    },
    volumeIncrement: 5
} 

function setVolume(value) {
    var volSlider = $('.volume-slider');

    volSlider.slider('value', value);
    volSlider.slider('option', 'slide')(null, {value: volSlider.slider('value')});
}

function adjustVolume(delta) {
    var volSlider = $('.volume-slider');
    console.log(volSlider.slider('value'));
    var value = Math.min(Math.max(volSlider.slider('value') + delta, 0), 100);;

    setVolume(value);
}

$(window).load(function() {  
    var bindVolumeInterval = setInterval(function() {
        if(typeof $('.volume-slider').slider != 'undefined') {
            $('#menu, #audio-controls').on('mousewheel', function(e) {
                e.preventDefault();
                // console.log(e);
                if(parseInt(e.deltaY) > 0) {
                    adjustVolume(options.volumeIncrement);
                } else {
                    adjustVolume(-options.volumeIncrement);
                }
            });
            clearInterval(bindVolumeInterval);
            console.log('volume-bind ok');
        } else {
            console.log('volume-bind fail');
        }
    }, 1000);
});

1 个答案:

答案 0 :(得分:3)

来自Chrome documentation

  

内容脚本在称为隔离的特殊环境中执行   世界。他们可以访问他们注入的页面的DOM,   但不是页面创建的任何JavaScript变量或函数。   它将每个内容脚本视为没有其他JavaScript   在正在运行的页面上执行。反过来也是如此:   页面上运行的JavaScript无法调用任何函数或访问任何函数   由内容脚本定义的变量。

这实际上是一种安全功能,这样网页的JavaScript代码就不会破坏您的扩展程序的功能,例如通过重新定义标准DOM方法。您的内容脚本根本看不到网页中运行的JavaScript添加/覆盖的任何属性。

当然,这使得调用页面JavaScript代码中的函数变得更加复杂。您的内容脚本实际上加载了自己的jQuery副本 - 但该副本对网页的功能一无所知,因此它也不知道所讨论的元素是滑块。 Communicating with the embedding page无法提供帮助,因为在这种情况下您无法控制网页。

运行可与该网页的JavaScript对话的JavaScript代码的最强大方法似乎是添加了<script>代码:

function setVolume(value)
{
  // Sanitize parameter, to make sure it doesn't need any escaping
  value = parseInt(value, 10);

  var script = document.createElement("script");
  script.async = false;
  script.textContent = "(function() {" +
      "var value = " + value + ";" +
      "var volSlider = $('.volume-slider');" +
      "volSlider.slider('value', value);" +
      "volSlider.slider('option', 'slide')(null, {value: volSlider.slider('value')});" +
    "})()";
  document.documentElement.appendChild(script);
  document.documentElement.removeChild(script);
}

这是一种相当丑陋的方法,特别是对于冗长的脚本 - 您必须将整个脚本放入字符串中。因此,如果您注入网页的逻辑变得更复杂,您可能需要考虑为扩展添加脚本文件。您必须将此文件添加到web_accessible_resources并将其URL用作脚本源。您将无法再通过更改来源传递参数,但您可以按照Communication with the embedding page下的概述发布消息(无论如何,这是一种更好的方法)。

请注意,可以将异步脚本添加到页面中并立即删除,然后它就已经执行了。另请注意,您不需要在内容脚本中使用jQuery - 所有jQuery调用都发生在网页中,并且已经加载了jQuery。