J'apprends à créer des extensions Chrome. Je viens de commencer à en développer un pour capturer les événements YouTube. Je veux l'utiliser avec YouTube Flash Player (plus tard, je vais essayer de le rendre compatible avec HTML5).
manifest.json:
{
"name": "MyExtension",
"version": "1.0",
"description": "Gotta catch Youtube events!",
"permissions": ["tabs", "http://*/*"],
"content_scripts" : [{
"matches" : [ "www.youtube.com/*"],
"js" : ["myScript.js"]
}]
}
myScript.js:
function state() { console.log("State Changed!"); }
var player = document.getElementById("movie_player");
player.addEventListener("onStateChange", "state");
console.log("Started!");
Le problème est que la console me donne le "Démarré!" , mais il n'y a pas de "Changement d'état!" lorsque je joue / met en pause des vidéos YouTube.
Lorsque ce code est mis dans la console, cela a fonctionné. Qu'est-ce que je fais mal?
player.addEventListener("onStateChange", state);
https://
ouhttp://
, celawww.youtube.com/*
ne vous laisserait pas emballer l'extension et lancerait une erreur de séparateur de schéma manquantRéponses:
Les scripts de contenu sont exécutés dans un environnement "monde isolé" . Vous devez injecter votre
state()
méthode dans la page elle-même.Lorsque vous souhaitez utiliser l'une des
chrome.*
API du script, vous devez implémenter un gestionnaire d'événements spécial, comme décrit dans cette réponse: Extension Chrome - récupérer le message d'origine de Gmail .Sinon, si vous n'avez pas à utiliser d'
chrome.*
API, je vous recommande fortement d'injecter tout votre code JS dans la page via l'ajout d'une<script>
balise:Table des matières
Méthode 1: injecter un autre fichier
C'est la méthode la plus simple / la meilleure lorsque vous avez beaucoup de code. Incluez votre code JS réel dans un fichier au sein de votre extension, par exemple
script.js
. Ensuite, laissez votre script de contenu être le suivant (expliqué ici: Javascript personnalisé "Raccourci d'application" Google Chome ):Remarque: Si vous utilisez cette méthode, le
script.js
fichier injecté doit être ajouté à la"web_accessible_resources"
section ( exemple ). Si vous ne le faites pas, Chrome refusera de charger votre script et affichera l'erreur suivante dans la console:Méthode 2: injecter du code incorporé
Cette méthode est utile lorsque vous souhaitez exécuter rapidement un petit morceau de code. (Voir aussi: Comment désactiver les raccourcis Facebook avec l'extension Chrome? ).
Remarque: les littéraux de modèle ne sont pris en charge que dans Chrome 41 et versions ultérieures. Si vous souhaitez que l'extension fonctionne dans Chrome 40-, utilisez:
Méthode 2b: utilisation d'une fonction
Pour un gros morceau de code, il n'est pas possible de citer la chaîne. Au lieu d'utiliser un tableau, une fonction peut être utilisée et stringifiée:
Cette méthode fonctionne, car l'
+
opérateur sur les chaînes et une fonction convertit tous les objets en chaîne. Si vous avez l'intention d'utiliser le code plus d'une fois, il est sage de créer une fonction pour éviter la répétition du code. Une implémentation pourrait ressembler à:Remarque: Étant donné que la fonction est sérialisée, la portée d'origine et toutes les propriétés liées sont perdues!
Méthode 3: utiliser un événement en ligne
Parfois, vous voulez exécuter du code immédiatement, par exemple pour exécuter du code avant la création de l'
<head>
élément. Cela peut être fait en insérant une<script>
balise avectextContent
(voir méthode 2 / 2b).Une alternative, mais non recommandée, consiste à utiliser des événements en ligne. Il n'est pas recommandé car si la page définit une stratégie de sécurité du contenu qui interdit les scripts en ligne, les écouteurs d'événements en ligne sont bloqués. Les scripts en ligne injectés par l'extension, en revanche, continuent de s'exécuter. Si vous souhaitez toujours utiliser des événements en ligne, voici comment:
Remarque: Cette méthode suppose qu'aucun autre écouteur d'événement global ne gère l'
reset
événement. Si tel est le cas, vous pouvez également choisir l'un des autres événements mondiaux. Ouvrez simplement la console JavaScript (F12), saisissezdocument.documentElement.on
et sélectionnez les événements disponibles.Valeurs dynamiques dans le code injecté
Parfois, vous devez passer une variable arbitraire à la fonction injectée. Par exemple:
Pour injecter ce code, vous devez passer les variables comme arguments à la fonction anonyme. Assurez-vous de l'implémenter correctement! Les éléments suivants ne fonctionneront pas :
La solution est d'utiliser
JSON.stringify
avant de passer l'argument. Exemple:Si vous avez de nombreuses variables, il vaut la peine de les utiliser
JSON.stringify
une fois, pour améliorer la lisibilité, comme suit:la source
script-src
directive qui exclut l'origine de l'extension, la méthode 2 peut être bloquée en utilisant un CSP qui exclut "unsafe-inline" `.script.parentNode.removeChild(script);
. Je le fais parce que j'aime nettoyer mon bordel. Lorsqu'un script en ligne est inséré dans le document, il est immédiatement exécuté et la<script>
balise peut être supprimée en toute sécurité.location.href = "javascript: alert('yeah')";
n'importe où dans votre script de contenu. Il est plus facile pour les courts extraits de code et peut également accéder aux objets JS de la page.javascript:
. Le code s'étendant sur plusieurs lignes peut ne pas fonctionner comme prévu. Une ligne commentaire (//
) tronque le reste, donc ce échouera:location.href = 'javascript:// Do something <newline> alert(0);';
. Cela peut être contourné en vous assurant que vous utilisez des commentaires sur plusieurs lignes. Une autre chose à laquelle il faut faire attention est que le résultat de l'expression soit nul.javascript:window.x = 'some variable';
entraînera le déchargement du document et sera remplacé par l'expression «une variable». S'il est utilisé correctement, c'est en effet une alternative intéressante à<script>
.La seule chose
manquantcachée à l'excellente réponse de Rob W est de savoir comment communiquer entre le script de page injecté et le script de contenu.Côté réception (votre script de contenu ou le script de page injecté), ajoutez un écouteur d'événements:
Du côté initiateur (script de contenu ou script de page injecté) envoyez l'événement:
Remarques:
Dans Firefox, pour envoyer un objet (c'est-à-dire pas une valeur primitive) du script de contenu au contexte de la page, vous devez le cloner explicitement dans la cible en utilisant
cloneInto
(une fonction intégrée), sinon il échouera avec une erreur de violation de sécurité .la source
CustomEvent
constructeur remplace l'document.createEvent
API obsolète .CustomEvent
constructeur. J'ai connu 2 revers très déroutants: 1. simplement mettre des guillemets simples autour des «détails» a fait perplexe la valeurnull
lorsqu'ils sont reçus par l'auditeur de mon script de contenu. 2. Plus important encore, pour une raison quelconque, je devais le faire,JSON.parse(JSON.stringify(myData))
sinon cela deviendrait aussinull
. Compte tenu de cela, il me semble que l'affirmation suivante du développeur Chromium - que l'algorithme du "clone structuré" est utilisé automatiquement - n'est pas vraie. bugs.chromium.org/p/chromium/issues/detail?id=260378#c18J'ai également rencontré le problème de la commande des scripts chargés, qui a été résolu par le chargement séquentiel des scripts. Le chargement est basé sur la réponse de Rob W .
L'exemple d'utilisation serait:
En fait, je suis un peu nouveau pour JS, alors n'hésitez pas à me cingler vers les meilleures façons.
la source
formulaImageUrl
oucodeImageUrl
, vous détruisez efficacement la fonctionnalité de la page. Si vous souhaitez transmettre une variable à la page Web, je suggère d'attacher les données à l'élément de script (e.g. script.dataset.formulaImageUrl = formulaImageUrl;
) et d'utiliser par exemple(function() { var dataset = document.currentScript.dataset; alert(dataset.formulaImageUrl;) })();
dans le script pour accéder aux données.dataset
?document.currentScript
pointe uniquement sur la balise de script pendant son exécution. Si vous souhaitez accéder à la balise de script et / ou à ses attributs / propriétés (par exempledataset
), vous devez la stocker dans une variable. Nous avons besoin d'un IIFE pour obtenir une fermeture pour stocker cette variable sans polluer l'espace de noms global.return;
).dans le script de contenu, j'ajoute une balise de script à la tête qui lie un gestionnaire «onmessage», à l'intérieur du gestionnaire que j'utilise, eval pour exécuter le code. Dans le script de contenu de stand, j'utilise également le gestionnaire onmessage, donc je reçois une communication bidirectionnelle. Documents Google Chrome
pmListener.js est un écouteur d'URL de message
De cette façon, je peux avoir une communication bidirectionnelle entre CS et Real Dom. Son très utile par exemple si vous avez besoin d'écouter des événements de webscoket, ou à des variables ou des événements en mémoire.
la source
Vous pouvez utiliser une fonction utilitaire que j'ai créée dans le but d'exécuter du code dans le contexte de la page et de récupérer la valeur renvoyée.
Cela se fait en sérialisant une fonction dans une chaîne et en l'injectant dans la page Web.
L'utilitaire est disponible ici sur GitHub .
Exemples d'utilisation -
la source
Si vous souhaitez injecter une fonction pure, au lieu de texte, vous pouvez utiliser cette méthode:
Et vous pouvez passer des paramètres (malheureusement aucun objet et aucun tableau ne peut être stratifié) aux fonctions. Ajoutez-le dans les baréthèses, comme ceci:
la source