Переменные страницы в скрипте контента

Я полагаю, класс ComparatorChain взят из библиотеки Apache commons. Вы можете посмотреть документацию здесь . Вы также можете скачать банку здесь .

30
задан 09.03.2020, 19:43

8 ответов

Если вам действительно нужно, вы можете вставить элемент <script> в DOM страницы; код внутри вашего элемента <script> будет выполнен, и этот код будет иметь доступ к переменным JavaScript в области видимости окна. Затем вы можете передать их обратно в скрипт контента, используя атрибуты data- и вызывая пользовательские события.

Звучит неловко? Почему да, и намеренно по всем причинам в документации, которую цитировал serg. Но если вам действительно нужно это сделать, это можно сделать. См. здесь и здесь для получения дополнительной информации. И удачи!

63
ответ дан 09.03.2020, 19:47
  • 1
    @Mike F: от того, что я могу сказать, это doesn' t, кажется, выбирают операции SSE. Don' t заключают мне в кавычки на этом, которое является только от какой I' ve замеченный JIT' d в моем коде. Я могу спросить microsoftie и узнать. – user7116 02.10.2008, 08:35
  • 2
    Хорошо that' s лучше отвечают, чем мой. – serg 09.03.2020, 19:47

Документация Chrome дает вам хорошую отправную точку: https://developer.chrome.com/extensions/content_scripts#host-page-communication

Этот метод позволяет вам извлечь Глобальная переменная страницы в вашем скрипте контента. Он также использует идею, чтобы принимать только входящие сообщения, которые вы узнаете, учитывая ваше рукопожатие. Вы также можете просто использовать Math.random() для рукопожатия, но мне было весело.

Объяснение

  1. Этот метод создает тег сценария
  2. Он переводит в строку функцию propagateVariable и передает текущее handShake и имя целевой переменной в строку для сохранения, так как функция будет не имеют доступа к нашей области содержимого скрипта.
  3. Затем он вставляет этот тег сценария на страницу.
  4. Затем мы создаем слушателя в нашем скрипте контента, ожидая ответа от страницы, чтобы передать переменную, которую мы ищем.
  5. К настоящему времени введённый скрипт попал на страницу.
  6. Внедренный код был обернут в IIFE , поэтому он сам запускает передачу данных слушателю.
  7. Необязательно: слушатель проверяет, что у него было правильное рукопожатие, и вуаля, мы можем доверять источнику данных (на самом деле это не безопасно, но в этом случае помогает создать идентификатор, который дает нам некоторый уровень доверия).

Раунд 1

v1.0

const globalToExtract = 'someVariableName';
const array = new Uint32Array(5);
const handShake = window.crypto.getRandomValues(array).toString();

function propagateVariable(handShake, variableName) {
  const message = { handShake };
  message[variableName] = window[variableName];
  window.postMessage(message, "*");
}

(function injectPropagator() {
  const script = `( ${propagateVariable.toString()} )('${handShake}', '${globalToExtract}');`
  const scriptTag = document.createElement('script');
  const scriptBody = document.createTextNode(script);
  
  scriptTag.id = 'chromeExtensionDataPropagator';
  scriptTag.appendChild(scriptBody);
  document.body.append(scriptTag);
})();

window.addEventListener("message", function({data}) {
  console.log("INCOMINGGGG!", data);
  // We only accept messages from ourselves
  if (data.handShake != handShake) return;

  console.log("Content script received: ", data);
}, false);

v1.1 с обещанием!

function extractGlobal(variableName) {

  const array = new Uint32Array(5);
  const handShake = window.crypto.getRandomValues(array).toString();

  function propagateVariable(handShake, variableName) {
    const message = { handShake };
    message[variableName] = window[variableName];
    window.postMessage(message, "*");
  }

  (function injectPropagator() {
    const script = `( ${propagateVariable.toString()} )('${handShake}', '${variableName}');`
    const scriptTag = document.createElement('script');
    const scriptBody = document.createTextNode(script);

    scriptTag.id = 'chromeExtensionDataPropagator';
    scriptTag.appendChild(scriptBody);
    document.body.append(scriptTag);
  })();

  return new Promise(resolve => {
    window.addEventListener("message", function({data}) {
      // We only accept messages from ourselves
      if (data.handShake != handShake) return;
      resolve(data);
    }, false);
  });
}

extractGlobal('someVariableName').then(data => {
  // Do Work Here
});

Раунд 2 - Класс & amp; Promises

v2.0

Я бы порекомендовал добавить класс в его собственный файл и экспортировать его по умолчанию, если используются модули es. Тогда это просто становится:

ExtractPageVariable('someGlobalPageVariable').data.then(pageVar => {
  // Do work here                   
2
ответ дан 09.03.2020, 19:44
  • 1
    @DeveloperInToronto: Много операций с плавающей точкой требуют нескольких циклов. И несколько целочисленных операций - также. Кроме того, базовая линия для сравнения isn' t даже " 1 cycle" но часть, так как современные центральные процессоры имеют несколько ALUs. – Ben Voigt 05.01.2013, 03:38

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

В popup.js:

chrome.tabs.executeScript(null, {code: 'var name = "property"'}, function() {
    chrome.tabs.executeScript(null, {file: "retrieveValue.js"}, function(ret) {
        for (var i = 0; i < ret.length; i++) {
            console.log(ret[i]); //prints out each returned element in the array
        }
    });
});

В retrieveValue.js:

function returnValues() {
    return document.getElementById("element")[name];
    //return any variables you need to retrieve
}
returnValues();

Вы можете изменить код для возврата массивов или других объектов.

1
ответ дан 09.03.2020, 19:44
  • 1
    Я предположил бы из-за части Вашего кода, бросающего назад и вперед между float-> double-> плавание, например, с функциями математики, которые возвращаются дважды, так устранение кастинга, ответственно за скорость; не обязательно, потому что удваивается, врожденно быстрее. – HoboBen 11.10.2010, 20:11

Используя решение Лиран, я добавляю исправление для Objects, вот правильное решение:

function retrieveWindowVariables(variables) {
    var ret = {};

    var scriptContent = "";
    for (var i = 0; i < variables.length; i++) {
        var currVariable = variables[i];
        scriptContent += "if (typeof " + currVariable + " !== 'undefined') $('body').attr('tmp_" + currVariable + "', JSON.stringify(" + currVariable + "));\n"
    }

    var script = document.createElement('script');
    script.id = 'tmpScript';
    script.appendChild(document.createTextNode(scriptContent));
    (document.body || document.head || document.documentElement).appendChild(script);

    for (var i = 0; i < variables.length; i++) {
        var currVariable = variables[i];
        ret[currVariable] = $.parseJSON($("body").attr("tmp_" + currVariable));
        $("body").removeAttr("tmp_" + currVariable);
    }

     $("#tmpScript").remove();

    return ret;
}
14
ответ дан 09.03.2020, 19:45
  • 1
    Я согласовываю инструкцию относительно плавания, дважды, целого числа, короткого и символ, или даже 1 бит берет один цикл ЦП, игнорируя тип. Но делает различие, возникают, если Вы рассматриваете сравнение обращения, местности, параллельной обработки. Мне кажется, что обработка двойной точности имеет больше служебное. Не очень легко сделать реальный тест. Компиляторы умны и оптимизируют наверху, таким образом, реальная проблема может остаться скрытой если тест, делающий относительно немую работу. – DeveloperInToronto 21.05.2011, 08:38

На самом деле я работал над этим, используя API localStorge. Примечание: чтобы использовать это, наш contentcript должен быть в состоянии прочитать localStorage. В файле manifest.json просто добавьте строку «storage»:

"permissions": [...,"storage"]

Функция hijack находится в скрипте содержимого:

function hijack(callback) {
    "use strict";
    var code = function() {
      //We have access to topframe - no longer a contentscript          
      var ourLocalStorageObject = {
        globalVar: window.globalVar,
        globalVar2: window.globalVar2
      };
      var dataString = JSON.stringify(ourLocalStorageObject);
      localStorage.setItem("ourLocalStorageObject", dataString);
    };
    var script = document.createElement('script');
    script.textContent = '(' + code + ')()';
    (document.head||document.documentElement).appendChild(script);
    script.parentNode.removeChild(script);
    callback();
  }

Теперь мы можем вызывать из contentcript

document.addEventListener("DOMContentLoaded", function(event) { 
    hijack(callback);
});

или если вы используете jQuery в вашем файле содержания, как я:

$(document).ready(function() { 
    hijack(callback);
});

, чтобы извлечь содержимое:

function callback() {
    var localStorageString = localStorage.getItem("ourLocalStorageObject");
    var ourLocalStorageObject= JSON.parse(localStorageString);

    console.log("I can see now on content script", ourLocalStorageObject);
    //(optional cleanup):
    localStorage.removeItem("ourLocalStorageObject");
}

Это может быть вызвано несколько раз поэтому, если ваша страница изменяет элементы или внутренний код, вы можете добавить прослушиватели событий для обновления вашего расширения новыми данными.

Редактировать: я добавил обратные вызовы, чтобы вы могли быть уверены, что ваши данные не будут недействительными (была эта проблема сама)

1
ответ дан 09.03.2020, 19:45
  • 1
    Дело обстоит так с C#, где весь возврат математических операций удваивается. Для литеральных значений можно использовать f, и т.д. для самого значения. – Joan Venge 07.01.2009, 06:56

Я создал небольшой вспомогательный метод, получайте удовольствие:)

для извлечения переменных окна «lannister», «always», «pays», «his», «долгов» , вы выполняете следующее:

var windowVariables = retrieveWindowVariables(["lannister", "always", "pays", "his", "debts"]);
console.log(windowVariables.lannister);
console.log(windowVariables.always);

мой код:

function retrieveWindowVariables(variables) {
    var ret = {};

    var scriptContent = "";
    for (var i = 0; i < variables.length; i++) {
        var currVariable = variables[i];
        scriptContent += "if (typeof " + currVariable + " !== 'undefined') $('body').attr('tmp_" + currVariable + "', " + currVariable + ");\n"
    }

    var script = document.createElement('script');
    script.id = 'tmpScript';
    script.appendChild(document.createTextNode(scriptContent));
    (document.body || document.head || document.documentElement).appendChild(script);

    for (var i = 0; i < variables.length; i++) {
        var currVariable = variables[i];
        ret[currVariable] = $("body").attr("tmp_" + currVariable);
        $("body").removeAttr("tmp_" + currVariable);
    }

    $("#tmpScript").remove();

    return ret;
}

обратите внимание, что я использовал jQuery .. вы можете легко использовать нативный js «removeAttribute» и вместо «removeChild» .

20
ответ дан 09.03.2020, 19:46
  • 1
    @sixlettervariables: I' d очень быть интересно слышать ответ, если Вы когда-нибудь получаете один и испытываете желание отправлять его здесь. –  02.10.2008, 08:43
  • 2
    Действительно ли этот ответ применим в контексте сценария содержания? – esqew 09.03.2020, 19:46
  • 3
    да, это.. просто используйте его прямо от Вашего плагина js – Liran Brimer 09.03.2020, 19:47

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

Изолированные миры позволяют каждому скрипту контента вносить изменения в свою среду JavaScript, не беспокоясь о конфликте со страницей или другими скриптами контента. Например, сценарий контента может включать JQuery v1, а страница может включать JQuery v2, и они не будут конфликтовать друг с другом.

Другим важным преимуществом изолированных миров является то, что они полностью отделяют JavaScript на странице от JavaScript в расширениях. Это позволяет нам предлагать дополнительные функции сценариям содержимого, которые не должны быть доступны с веб-страниц, не беспокоясь о доступе к ним веб-страниц.

0
ответ дан 09.03.2020, 19:47
  • 1
    На самом деле я забираю это. Я просто протестировал с простым на цикл, и это кажется по любой причине, удваивается , быстрее! – HoboBen 11.10.2010, 23:15

Как объяснено частично в других ответах, переменные JS со страницы изолированы от вашего скрипта содержимого расширения Chrome. Обычно нет никакого доступа к ним.

Но если вы вставите тег JavaScript на страницу, у вас будет доступ к тем переменным, которые там определены.

Я использую служебную функцию для ввода моего скрипта на странице:

/**
 * inject - Inject some javascript in order to expose JS variables to our content JavaScript
 * @param {string} source - the JS source code to execute
 * Example: inject('(' + myFunction.toString() + ')()');
 */
function inject(source) {
  const j = document.createElement('script'),
    f = document.getElementsByTagName('script')[0];
  j.textContent = source;
  f.parentNode.insertBefore(j, f);
  f.parentNode.removeChild(j);
}

Затем вы можете сделать:

function getJSvar(whichVar) {
   document.body.setAttribute('data-'+whichVar,whichVar);
}
inject('(' + getJSvar.toString() + ')("somePageVariable")');

var pageVar = document.body.getAttribute('data-somePageVariable');

Обратите внимание, что если переменная представляет собой сложный тип данных ( object, array ...), вам нужно будет сохранить значение в виде строки JSON в getJSvar (), и JSON.parse вернуть его в свой скрипт контента.

0
ответ дан 09.03.2020, 19:48
  • 1
    Процессор не важен. Делаете ли Вы это на медленном или быстром ПК..., 5%-е улучшение является 5%-м улучшением:-), – z0mbi3 16.10.2015, 10:46

Теги

Похожие вопросы