6

Доступ к переменным и функциям, определённым в контексте страницы, из расширения

1

Я пытаюсь управлять плеером youtube.com с помощью моего расширения. Вот как выглядит мой manifest.json:

{
    "name": "MyExtension",
    "version": "1.0",
    "description": "Готов поймать события Youtube!",
    "permissions": ["tabs", "http://*/*"],
    "content_scripts" : [{
        "matches" : [ "www.youtube.com/*"],
        "js" : ["myScript.js"]
    }]
}

И вот код в myScript.js:

function state() { console.log("Состояние изменилось!"); }
var player = document.getElementById("movie_player");
player.addEventListener("onStateChange", "state");
console.log("Запуск!");

Проблема в том, что в консоли я вижу сообщение "Запуск!", но нет сообщения "Состояние изменилось!" при воспроизведении/пауза видео на YouTube.

Когда я выполняю этот код напрямую в консоли разработчика, он работает. Что я делаю не так?

3 ответ(ов)

0

Если вы хотите внедрить чистую функцию вместо текста, вы можете использовать следующий метод:

function inject(){
    document.body.style.backgroundColor = 'blue';
}

// Здесь функция включена как текст, а скобки заставляют её выполниться.
var actualCode = "("+inject+")()"; 

document.documentElement.setAttribute('onreset', actualCode);
document.documentElement.dispatchEvent(new CustomEvent('reset'));
document.documentElement.removeAttribute('onreset');

Кроме того, вы можете передавать параметры (к сожалению, объекты и массивы не могут быть приведены к строке) в функции. Просто добавьте их в скобки, как показано ниже:

function inject(color){
    document.body.style.backgroundColor = color;
}

// Здесь функция включена как текст, а скобки заставляют её выполниться.
var color = 'yellow';
var actualCode = "("+inject+")("+color+")"; 

Не забудьте, что передавать переменные нужно обязательно в виде строк, так как в приведённом примере параметр color будет интерпретироваться как строка, а не как переменная.

0

Вот улучшенный вариант ответа на ваш вопрос, основанный на решении Али Зареи, но с использованием синтаксиса ES6.

Вы можете создать и вставить скрипт в контентном скрипте вашего расширения Chrome следующим образом:

// content-script.js
const scriptElement = document.createElement('script');
scriptElement.src = chrome.runtime.getURL(`injected-script.js?extensionId=${chrome.runtime.id}`);
scriptElement.type = 'module';
scriptElement.onload = () => {
    scriptElement.remove(); // Удаляем элемент после загрузки
};
document.head.append(scriptElement); // Добавляем скрипт в head документа

А вот код для вашего инъектируемого скрипта:

// injected-script.js
const extensionId = new URL(import.meta.url).searchParams.get("extensionId"); // Получаем ID расширения из URL

Этот способ позволяет удобно использовать ES6 и современные возможности JavaScript при работе с расширениями для Chrome. Обратите внимание, что import.meta.url возвращает URL текущего модуля, что делает его идеальным для получения параметров запроса.

0

Если вы хотите использовать динамические значения в вашем внедренном коде (Manifest V3), и тип вашего внедренного скрипта — модуль, вы не сможете использовать document.currentScript.dataset, как описано в отличном ответе Роба. Вместо этого вы можете передать параметры в качестве URL-параметров и извлечь их в внедренном коде. Вот пример:

Скрипт контента:

var s = document.createElement('script');
s.src = chrome.runtime.getURL('../override-script.js?extensionId=' + chrome.runtime.id);
s.type = 'module';
s.onload = function () {
    this.remove();
};
(document.head || document.documentElement).appendChild(s);

Внедренный код (в моем случае это override-script.js):

let extensionId = new URL(import.meta.url).searchParams.get("extensionId");

Таким образом, вы можете легко извлекать динамические значения, передавая их через параметры URL.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь