Как я могу получить доступ к слайдеру jQueryUI с помощью скрипта, введенного моим расширением Chrome?

#javascript #jquery #jquery-ui #google-chrome-extension

#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. Где вы инициализируете слайдер на самом деле ..?

2. Я не. Внутри страницы уже инициализирован слайдер, и я пытаюсь получить к нему доступ через внедренный js.

Ответ №1:

Из документации Chrome:

Сценарии содержимого выполняются в специальной среде, называемой изолированным миром. У них есть доступ к DOM страницы, на которую они вводятся, но не к каким-либо переменным или функциям JavaScript, созданным страницей. Для каждого сценария содержимого он выглядит так, как будто на странице, на которой он запущен, не выполняется другой JavaScript. То же самое верно и в обратном порядке: JavaScript, запущенный на странице, не может вызывать какие-либо функции или обращаться к каким-либо переменным, определенным сценариями содержимого.

На самом деле это функция безопасности, таким образом, код JavaScript веб-страницы не может испортить функциональность вашего расширения, например, путем переопределения стандартных методов DOM. Ваш сценарий содержимого просто не видит никаких свойств, добавленных / переопределенных JavaScript, запущенным на веб-странице.

Конечно, это усложняет вызов функции в коде JavaScript страницы. Ваш скрипт содержимого фактически загружает свою собственную копию jQuery, но эта копия ничего не знает о том, что сделала веб-страница, и, следовательно, она также не знает, что рассматриваемый элемент является слайдером. Связь со страницей встраивания также не помогает, потому что в этом случае вы не управляете веб-страницей.

По-видимому, наиболее надежным способом запуска кода 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 в качестве источника скрипта. Вы больше не сможете передавать параметры, изменяя источник, но вместо этого вы можете публиковать сообщения, как указано в разделе Связь со страницей встраивания (в любом случае, это лучший подход).

Обратите внимание, что асинхронный скрипт может быть добавлен на страницу и немедленно удален, к тому времени он уже выполнен. Также обратите внимание, что вам не нужен jQuery в сценарии содержимого — все вызовы jQuery выполняются на веб-странице, и на этой странице уже загружен jQuery.

Комментарии:

1. Просто хотел спросить, почему передача сообщений между скриптами не поможет в этом случае.

2. @ParagGangil: Между какими скриптами? Если вы хотите отправить сообщение скриптам, запущенным на веб-странице, — там никто не слушает. Если вы хотите обмениваться данными между скриптом содержимого и скриптом, который вы ввели — конечно, вы можете использовать передачу сообщений. Я уже добавил замечание по этому поводу.