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

В принципе мы можем создать объект весеннего контейнера двумя способами

  1. с использованием BeatFactory
  2. с использованием ApplicationContext

оба являются интерфейсами

с использованием классов реализации мы можем создать объект для весеннего контейнера

, приходя к различиям

BeanFactory

  1. Не поддерживает аннотацию основанная на зависимостях Injection.
  2. Не поддерживает I18N
  3. По умолчанию его поддержка Lazy loading
  4. не позволяет настроить несколько файлов конфигурации.

ex: BeanFactory context = new XmlBeanFactory (новый ресурс ("applicationContext.xml"));

ApplicationContext

  1. Поддержка зависимостей на основе аннотаций Инъекция .- @ Autowired, @PreDestroy
  2. Поддержка I18N
  3. its По умолчанию поддерживается загрузка Aggresive.
  4. позволяет настраивать несколько файлов конфигурации.

ex: ApplicationContext context = new ClasspathXmlApplicationContext ("applicationContext.xml");

29
задан Nakilon 8 April 2013 в 11:21
поделиться

8 ответов

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

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

64
ответ дан Community 8 April 2013 в 11:21
поделиться

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

для извлечения переменных окна «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» .

18
ответ дан Liran Brimer 8 April 2013 в 11:21
поделиться

Используя решение Лиран, я добавляю исправление для 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;
}
13
ответ дан Dovydas Šopa 8 April 2013 в 11:21
поделиться

Документация 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
ответ дан CTS_AE 8 April 2013 в 11:21
поделиться

На самом деле я работал над этим, используя 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
ответ дан Elia Grady 8 April 2013 в 11:21
поделиться

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

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

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

0
ответ дан serg 8 April 2013 в 11:21
поделиться

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

В 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
ответ дан victor 8 April 2013 в 11:21
поделиться

Как объяснено частично в других ответах, переменные 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
ответ дан SHamel 8 April 2013 в 11:21
поделиться
Другие вопросы по тегам:

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