Ответ 1
Сценарии содержимого выполняются в среде "изолированного мира". Вы должны внедрить свой метод state()
в саму страницу.
Если вы хотите использовать в сценарии один из API chrome.*
, Вам необходимо реализовать специальный обработчик событий, как описано в этом ответе: Расширение Chrome - получение исходного сообщения Gmail.
В противном случае, если вам не нужно использовать API-интерфейсы chrome.*
, Я настоятельно рекомендую добавить весь код JS на страницу, добавив <script>
:
Оглавление
- Способ 1: добавить другой файл
- Способ 2: внедрить встроенный код
- Способ 2b: использование функции
- Способ 3: использование встроенного события
- Динамические значения в введенном коде
Способ 1: добавить другой файл
Это самый простой/лучший метод, когда у вас много кода. Включите ваш фактический код JS в файл в вашем расширении, скажем, script.js
. Затем пусть ваш контент-скрипт будет следующим (объяснено здесь: Google Chome "Ярлык приложения", Пользовательский Javascript):
var s = document.createElement('script');
// TODO: add "script.js" to web_accessible_resources in manifest.json
s.src = chrome.runtime.getURL('script.js');
s.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(s);
Примечание. Если вы используете этот метод, добавленный файл script.js
должен быть добавлен в раздел "web_accessible_resources"
(пример). Если вы этого не сделаете, Chrome откажется загружать ваш скрипт и отобразит в консоли следующую ошибку:
Запрещение загрузки chrome-extension://[EXTENSIONID]/script.js. Ресурсы должны быть перечислены в ключе манифеста web_accessible_resources, чтобы их могли загружать страницы за пределами расширения.
Способ 2: внедрить встроенный код
Этот метод полезен, когда вы хотите быстро запустить небольшой фрагмент кода. (См. Также: Как отключить горячие клавиши facebook с расширением Chrome?).
var actualCode = '// Code here.
// If you want to use a variable, use $ and curly braces.
// For example, to use a fixed random number:
var someFixedRandomValue = ${ Math.random() };
// NOTE: Do not insert unsafe variables in this way, see below
// at "Dynamic values in the injected code"
';
var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.remove();
Примечание: литералы шаблона поддерживаются только в Chrome 41 и выше. Если вы хотите, чтобы расширение работало в Chrome 40-, используйте:
var actualCode = ['/* Code here. Example: */' + 'alert(0);',
'// Beware! This array have to be joined',
'// using a newline. Otherwise, missing semicolons',
'// or single-line comments (//) will mess up your',
'// code ----->'].join('\n');
Способ 2b: использование функции
Для большой части кода цитирование строки неосуществимо. Вместо использования массива можно использовать функцию и строку:
var actualCode = '(' + function() {
// All code is executed in a local scope.
// For example, the following does NOT overwrite the global 'alert' method
var alert = null;
// To overwrite a global variable, prefix 'window':
window.alert = null;
} + ')();';
var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.remove();
Этот метод работает, потому что оператор +
в строках и функция преобразуют все объекты в строку. Если вы намерены использовать код более одного раза, целесообразно создать функцию, чтобы избежать повторения кода. Реализация может выглядеть так:
function injectScript(func) {
var actualCode = '(' + func + ')();'
...
}
injectScript(function() {
alert("Injected script");
});
Примечание. Поскольку функция сериализована, исходная область действия и все связанные свойства теряются!
var scriptToInject = function() {
console.log(typeof scriptToInject);
};
injectScript(scriptToInject);
// Console output: "undefined"
Способ 3: использование встроенного события
Иногда вы хотите сразу запустить некоторый код, например, запустить некоторый код перед созданием элемента <head>
. Это можно сделать, вставив <script>
с textContent
(см. Метод 2/2b).
Альтернативой, но не рекомендуется, является использование встроенных событий. Это не рекомендуется, поскольку, если на странице определена политика безопасности содержимого, которая запрещает встроенные сценарии, тогда прослушиватели встроенных событий блокируются. С другой стороны, встроенные сценарии, введенные расширением, все еще работают. Если вы все еще хотите использовать встроенные события, вот как:
var actualCode = '// Some code example \n' +
'console.log(document.documentElement.outerHTML);';
document.documentElement.setAttribute('onreset', actualCode);
document.documentElement.dispatchEvent(new CustomEvent('reset'));
document.documentElement.removeAttribute('onreset');
Примечание. Этот метод предполагает, что нет других глобальных прослушивателей событий, которые обрабатывают событие reset
. Если есть, вы также можете выбрать одно из других глобальных событий. Просто откройте консоль JavaScript (F12), введите document.documentElement.on
и выберите доступные события.
Динамические значения в введенном коде
Иногда вам нужно передать произвольную переменную введенной функции. Например:
var GREETING = "Hi, I'm ";
var NAME = "Rob";
var scriptToInject = function() {
alert(GREETING + NAME);
};
Чтобы внедрить этот код, вам нужно передать переменные в качестве аргументов анонимной функции. Будьте уверены, чтобы реализовать это правильно! Следующее не будет работать:
var scriptToInject = function (GREETING, NAME) { ... };
var actualCode = '(' + scriptToInject + ')(' + GREETING + ',' + NAME ')';
// The previous will work for numbers and booleans, but not strings.
// To see why, have a look at the resulting string:
var actualCode = "(function(GREETING, NAME) {...})(Hi I'm,Rob)";
// ^^^^^^ ^^^ No string literals!
Решением является использование JSON.stringify
перед передачей аргумента. Пример:
var actualCode = '(' + function(greeting, name) { ...
} + ')(' + JSON.stringify(GREETING) + ',' + JSON.stringify(NAME) + ')';
Если у вас много переменных, стоит использовать JSON.stringify
один раз, чтобы улучшить читабельность, как JSON.stringify
ниже:
...
} + ')(' + JSON.stringify([arg1, arg2, arg3, arg4]) + ')';