Passez un paramètre à un script de contenu injecté à l'aide de chrome.onglet.exécutescript()

Comment puis-je passer un paramètre au JavaScript dans un fichier de script de contenu qui est injecté en utilisant:

chrome.tabs.executeScript(tab.id, {file: "content.js"});
37
demandé sur Makyen 2013-07-10 13:55:18

2 réponses

il n'y a pas de "passer un paramètre à un fichier".

Ce que vous faire est d'insérer un contenu script avant exécuter le fichier, ou envoyer un message après insertion du fichier. Je vais montrer un exemple pour ces méthodes distinctes ci-dessous.

Définir les paramètres avant l'exécution du fichier JS

si vous voulez définir quelques variables avant d'insérer le fichier, il vous suffit de faire un nid chrome.tabs.executeScript appels:

chrome.tabs.executeScript(tab.id, {
    code: 'var config = 1;'
}, function() {
    chrome.tabs.executeScript(tab.id, {file: 'content.js'});
});

Si la variable n'est pas aussi simple, alors je vous recommande d'utiliser JSON.stringify pour transformer un objet en chaîne:

var config = {somebigobject: 'complicated value'};
chrome.tabs.executeScript(tab.id, {
    code: 'var config = ' + JSON.stringify(config)
}, function() {
    chrome.tabs.executeScript(tab.id, {file: 'content.js'});
});

Avec la méthode précédente, les variables peuvent être utilisées dans content.js de la façon suivante:

// content.js
alert('Example:' + config);

Définir les paramètres après l'exécution du fichier JS

La méthode précédente peut être utilisée pour définir les paramètres après le fichier JS. Au lieu de définir directement les variables dans le contexte global, vous pouvez utiliser le passage de messages API pour passer les paramètres:

chrome.tabs.executeScript(tab.id, {file: 'content.js'}, function() {
    chrome.tabs.sendMessage(tab.id, 'whatever value; String, object, whatever');
});

dans le script de contenu (content.js), vous pouvez écouter ces messages en utilisant le chrome.runtime.onMessage événement, et de gérer le message:

chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
    // Handle message.
    // In this example, message === 'whatever value; String, object, whatever'
});
74
répondu Rob W 2013-07-11 12:24:30

il y a cinq façons générales de passer des données à un script de contenu injecté avec tabs.executeScript() ( MDN):

  • Définir les données avant injection du script
    1. Utiliser chrome.storage.local ( MDN) pour transmettre les données (défini avant l'injection de votre script).
    2. injectez du code avant votre script qui définit une variable avec les données (voir discussion détaillée pour un problème de sécurité possible).
    3. définir un cookie pour le domaine dans lequel le script de contenu est injecté. Cette méthode peut également être utilisée pour transmettre des données à manifeste.json scripts de contenu injectés à document_start, sans avoir besoin du script de contenu pour exécuter une requête asynchrone.
  • Envoyer/définir les données après injection du script
    1. Utilisation passage de messages ( MDN) pour transmettre les données après votre script est injecté.
    2. Utiliser chrome.storage.onChanged ( MDN) dans votre script de contenu pour écouter le script d'arrière-plan pour définir une valeur en utilisant chrome.storage.local.set() ( MDN).

Utiliser chrome.storage.local (défini avant l'exécution de votre script)

L'utilisation de cette méthode maintient le paradigme d'exécution que vous utilisez pour injecter un script qui exécute une fonction et qui sort ensuite. Il n'a pas non plus le problème de sécurité potentiel d'utiliser une valeur dynamique pour construire le code d'exécution, ce qui est fait dans la deuxième option ci-dessous.

à Partir de votre popup script:

  1. stocker les données en utilisant chrome.storage.local.set() ( MDN).
  2. Dans la fonction de rappel pour l' chrome.storage.local.set(), appeler tabs.executeScript() ( MDN).
var updateTextTo = document.getElementById('comments').value;
chrome.storage.local.set({
    updateTextTo: updateTextTo
}, function () {
    chrome.tabs.executeScript({
        file: "content_script3.js"
    });
});

à Partir de votre contenu script:

  1. lire les données de chrome.storage.local.get() ( MDN).
  2. apporter les modifications à la DOM.
  3. Invalider les données dans storage.local (par exemple, supprimer la touche avec: chrome.storage.local.remove() ( MDN)).
chrome.storage.local.get('updateTextTo', function (items) {
    assignTextToTextareas(items.updateTextTo);
    chrome.storage.local.remove('updateTextTo');
});
function assignTextToTextareas(newText){
    if (typeof newText === 'string') {
        Array.from(document.querySelectorAll('textarea.comments')).forEach(el => {
            el.value = newText;
        });
    }
}

Voir Notes 1 Et 2.

injectez du code avant votre script pour définir une variable

avant d'exécuter votre script, vous pouvez injecter du code qui définit une variable dans le contexte de script de contenu que votre script primaire peut ensuite utiliser:

Sécurité question:

Les utilisations suivantes "'" + JSON.stringify().replace(/\/g,'\\').replace(/'/g,"\'") + "'" pour encoder les données dans un texte qui sera JSON approprié lorsqu'il est interprété comme du code, avant de le mettre dans le code chaîne de caractères. .replace() les méthodes sont nécessaires pour A) avoir le texte correctement interprété comme une chaîne lorsqu'il est utilisé comme code, et B) citer tout ' qui existent dans les données. Il utilise ensuite JSON.parse() pour retourner les données à une chaîne dans votre script de contenu. Bien que cet encodage ne soit pas strictement obligatoire, c'est une bonne idée que vous ne connaissez pas le contenu de la valeur que vous allez envoyer le contenu du script. Cette valeur pourrait facilement être quelque chose qui corromprait le code que vous injectez (i.e. l'utilisateur peut utiliser ' et/ou " dans le texte qu'ils ont entré). Si vous n'échappez pas d'une certaine manière à la valeur, il y a un trou de sécurité qui pourrait entraîner l'exécution de code arbitraire.

à Partir de votre popup script:

  1. Injecter un simple morceau de code qui définit une variable pour contenir les données.
  2. Dans la fonction de rappel pour l' chrome.tabs.executeScript() ( MDN), appeler tabs.executeScript() pour injecter votre script (Note:tabs.executeScript() va exécuter les scripts dans l'ordre dans lequel vous appeler tabs.executeScript(), tant qu'ils ont la même valeur pour runAt. Ainsi, en attendant le rappel du petit code n'est pas strictement nécessaire).
var updateTextTo = document.getElementById('comments').value;
chrome.tabs.executeScript({
    code: "var newText = JSON.parse('" + encodeToPassToContentScript(updateTextTo) + "');"
}, function () {
    chrome.tabs.executeScript({
        file: "content_script3.js"
    });
});

function encodeToPassToContentScript(obj){
    //Encodes into JSON and quotes \ characters so they will not break
    //  when re-interpreted as a string literal. Failing to do so could
    //  result in the injection of arbitrary code and/or JSON.parse() failing.
    return JSON.stringify(obj).replace(/\/g,'\\').replace(/'/g,"\'")
}

D'après votre contenu script:

  1. modifier le DOM en utilisant les données stockées dans la variable
if (typeof newText === 'string') {
    Array.from(document.querySelectorAll('textarea.comments')).forEach(el => {
        el.value = newText;
    });
}

Voir Les Notes 1, 2 Et 3.

Utiliser passage de messages ( MDN)(envoyer des données après contenu du script est injecté)

cela nécessite que votre code de script de contenu installe un écouteur pour un message envoyé par le popup, ou peut-être le script de fond (si le l'interaction avec L'UI provoque la fermeture de la fenêtre popup). C'est un peu plus complexe.

à Partir de votre popup script:

  1. déterminer l'onglet actif en utilisant 'tabs.query() (MDN).
  2. Appel tabs.executeScript() ( MDN)
  3. Dans la fonction de rappel pour l' tabs.executeScript(), utilisez

    tabs.sendMessage() ( MDN) (ce qui exige de connaître le tabId), pour envoyer les données sous forme de message.

var updateTextTo = document.getElementById('comments').value;
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
    chrome.tabs.executeScript(tabs[0].id, {
        file: "content_script3.js"
    }, function(){
        chrome.tabs.sendMessage(tabs[0].id,{
            updateTextTo: updateTextTo
        });
    });
});

à Partir de votre contenu script:

  1. Ajouter un écouteur en utilisant chrome.runtime.onMessage.addListener() ( MDN).
  2. Quitter votre code principal, laissant l'auditeur actif. Vous pouviez retourner un indicateur de succès, si vous choisir.
  3. dès réception d'un message contenant les données:
    1. faire les changements au DOM.
    2. retirez votre runtime.onMessage listener

#3.2 est facultatif. Vous pouvez garder votre code actif en attente d'un autre message, mais cela changerait le paradigme que vous utilisez pour celui où vous chargez votre code et il reste résident en attente de messages pour initier des actions.

chrome.runtime.onMessage.addListener(assignTextToTextareas);
function assignTextToTextareas(message){
    newText = message.updateTextTo;
    if (typeof newText === 'string') {
        Array.from(document.querySelectorAll('textarea.comments')).forEach(el => {
            el.value = newText;
        });
    }
    chrome.runtime.onMessage.removeListener(assignTextToTextareas);  //optional
}

Voir Notes 1 & 2.


Note 1: Utiliser Array.from() est très bien si vous ne le faites pas beaucoup de temps et sont à l'aide d'un version de navigateur qui l'a (Chrome > = version 45, Firefox > = 32). Dans Chrome et Firefox,Array.from() est lent comparé à d'autres méthodes pour obtenir un tableau à partir d'une NodeList. Pour une conversion plus rapide et plus compatible vers un tableau, vous pouvez utiliser le asArray() code cette réponse. La deuxième version de asArray() fourni dans la réponse est également plus robuste.

Note 2: Si vous êtes prêt à limitez votre code à la version Chrome > = 51 ou à la version Firefox > = 50, Chrome a un forEach() méthode élément nodelists à partir de v51. Ainsi, vous n'avez pas besoin de convertir un tableau. Évidemment, vous n'avez pas besoin de convertir en tableau si vous utilisez un type différent de boucle.

Note 3: alors que j'ai déjà utilisé cette méthode (injecter un script avec le variable value) dans mon propre code, on m'a rappelé que j'aurais dû l'inclure ici en lisant cette réponse.

11
répondu Makyen 2017-11-26 05:47:08