#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:
Сценарии содержимого выполняются в специальной среде, называемой изолированным миром. У них есть доступ к 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: Между какими скриптами? Если вы хотите отправить сообщение скриптам, запущенным на веб-странице, — там никто не слушает. Если вы хотите обмениваться данными между скриптом содержимого и скриптом, который вы ввели — конечно, вы можете использовать передачу сообщений. Я уже добавил замечание по этому поводу.