Uczę się, jak tworzyć rozszerzenia Chrome. Właśnie zacząłem opracowywać taki, aby rejestrować wydarzenia na YouTube. Chcę go używać z odtwarzaczem flash YouTube (później postaram się uczynić go kompatybilnym z 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!");
Problem polega na tym, że konsola daje mi komunikat „Rozpoczęto!” , ale nie ma „Zmienionego stanu!” kiedy odtwarzam / wstrzymuję filmy z YouTube.
Po umieszczeniu tego kodu w konsoli działało. Co ja robię źle?
player.addEventListener("onStateChange", state);
https://
lubhttp://
,www.youtube.com/*
co nie pozwoli ci spakować rozszerzenia i wyrzuci błąd separatora brakującego schematuOdpowiedzi:
Skrypty zawartości są wykonywane w środowisku „odizolowanego świata” . Musisz wstrzyknąć swoją
state()
metodę do samej strony.Jeśli chcesz użyć jednego z
chrome.*
interfejsów API w skrypcie, musisz zaimplementować specjalną procedurę obsługi zdarzeń, zgodnie z opisem w odpowiedzi: Rozszerzenie Chrome - pobieranie oryginalnej wiadomości Gmaila .W przeciwnym razie, jeśli nie musisz używać
chrome.*
interfejsów API, zdecydowanie zalecamy wstrzyknięcie całego kodu JS na stronę poprzez dodanie<script>
tagu:Spis treści
Metoda 1: Wstrzyknięcie innego pliku
Jest to najłatwiejsza / najlepsza metoda, gdy masz dużo kodu. Powiedzmy, że dołączasz swój rzeczywisty kod JS do pliku w swoim rozszerzeniu
script.js
. Następnie pozwól, aby Twój skrypt treści wyglądał następująco (wyjaśniono tutaj: Google Chome „Skrót aplikacji” Niestandardowy Javascript ):Uwaga: Jeśli używasz tej metody, wstrzyknięty
script.js
plik należy dodać do"web_accessible_resources"
sekcji ( przykład ). Jeśli tego nie zrobisz, Chrome odmówi załadowania skryptu i wyświetli następujący błąd w konsoli:Metoda 2: Wstrzyknięcie osadzonego kodu
Ta metoda jest przydatna, gdy chcesz szybko uruchomić mały fragment kodu. (Zobacz też: Jak wyłączyć klawisze skrótu Facebooka z rozszerzeniem Chrome? ).
Uwaga: literały szablonów są obsługiwane tylko w Chrome 41 i nowszych wersjach. Jeśli chcesz, aby rozszerzenie działało w Chrome 40-, użyj:
Metoda 2b: Korzystanie z funkcji
W przypadku dużej części kodu cytowanie ciągu nie jest możliwe. Zamiast używać tablicy, można użyć funkcji i skreślić:
Ta metoda działa, ponieważ
+
operator ciągów i funkcja konwertuje wszystkie obiekty na ciąg. Jeśli zamierzasz używać kodu więcej niż jeden raz, dobrze jest stworzyć funkcję, aby uniknąć powtórzenia kodu. Implementacja może wyglądać następująco:Uwaga: Ponieważ funkcja jest serializowana, oryginalny zakres i wszystkie powiązane właściwości zostają utracone!
Metoda 3: Wykorzystanie zdarzenia wbudowanego
Czasami chcesz uruchomić jakiś kod natychmiast, np. Aby uruchomić jakiś kod przed utworzeniem
<head>
elementu. Można to zrobić, wstawiając<script>
znacznik za pomocątextContent
(patrz metoda 2 / 2b).Alternatywą, ale niezalecaną, jest użycie zdarzeń wbudowanych. Nie jest to zalecane, ponieważ jeśli strona definiuje zasadę Content Security, która zabrania wbudowanych skryptów, wówczas wbudowane detektory zdarzeń są blokowane. Z drugiej strony skrypty wbudowane wstrzykiwane przez rozszerzenie nadal działają. Jeśli nadal chcesz korzystać ze zdarzeń wbudowanych, wykonaj następujące czynności:
Uwaga: Ta metoda zakłada, że nie ma innych globalnych detektorów zdarzeń, które obsługiwałyby
reset
zdarzenie. Jeśli tak, możesz wybrać jedno z innych wydarzeń globalnych. Wystarczy otworzyć konsolę JavaScript (F12), wpiszdocument.documentElement.on
i wybrać dostępne zdarzenia.Wartości dynamiczne we wstrzykiwanym kodzie
Czasami musisz przekazać dowolną zmienną do wstrzykiwanej funkcji. Na przykład:
Aby wstrzyknąć ten kod, musisz przekazać zmienne jako argumenty do funkcji anonimowej. Pamiętaj, aby poprawnie go wdrożyć! Następujące elementy nie będą działać:
Rozwiązaniem jest użycie
JSON.stringify
przed przekazaniem argumentu. Przykład:Jeśli masz wiele zmiennych, warto
JSON.stringify
raz użyć , aby poprawić czytelność, jak następuje:źródło
script-src
dyrektywy, która wyklucza pochodzenie rozszerzenia, metodę 2 można zablokować za pomocą CSP, który wyklucza „niebezpieczne wstawianie”.script.parentNode.removeChild(script);
. Moim powodem jest to, że lubię sprzątać bałagan. Po wstawieniu skryptu wbudowanego do dokumentu jest on natychmiast wykonywany, a<script>
znacznik można bezpiecznie usunąć.location.href = "javascript: alert('yeah')";
dowolnym miejscu w skrypcie zawartości. Jest to łatwiejsze w przypadku krótkich fragmentów kodu, a także może uzyskać dostęp do obiektów JS strony.javascript:
. Kod obejmujący wiele wierszy może nie działać zgodnie z oczekiwaniami. Liniowego komentarz (//
) spowoduje obcinania pozostałej więc będzie ustałalocation.href = 'javascript:// Do something <newline> alert(0);';
. Można to obejść, zapewniając stosowanie komentarzy wieloliniowych. Kolejną rzeczą, na którą należy uważać, jest to, że wynik wyrażenia powinien być nieważny.javascript:window.x = 'some variable';
spowoduje rozładowanie dokumentu i zastąpienie go zwrotem „jakaś zmienna”. Przy właściwym zastosowaniu jest to rzeczywiście atrakcyjna alternatywa dla<script>
.Jedyną rzeczą
brakującydoskonałą odpowiedzią Roba W jest to, jak komunikować się między skryptem wstrzykiwanej strony a skryptem treści.Po stronie odbierającej (skrypt treści lub skrypt strony wstrzykniętej) dodaj detektor zdarzeń:
Po stronie inicjatora (skrypt treści lub skrypt wstrzykiwanej strony) wyślij zdarzenie:
Uwagi:
W Firefoksie, aby wysłać obiekt (tj. Nie prymitywną wartość) ze skryptu zawartości do kontekstu strony, musisz jawnie sklonować go w celu za pomocą
cloneInto
(funkcji wbudowanej), w przeciwnym razie zakończy się niepowodzeniem z błędem naruszenia zabezpieczeń .źródło
CustomEvent
Konstruktor zastępuje przestarzałydocument.createEvent
interfejs API.CustomEvent
konstruktora. Doświadczyłem dwóch bardzo mylących niepowodzeń: 1. po prostu umieszczenie pojedynczych cudzysłowów wokół „szczegółów” wprawiło w zakłopotanie wartość,null
gdy otrzymałem je od słuchacza mojego skryptu treści. 2. Co ważniejsze, z jakiegoś powodu musiałem, boJSON.parse(JSON.stringify(myData))
inaczej też się stanienull
. Biorąc to pod uwagę, wydaje mi się, że następujące twierdzenie twórcy Chromium - że algorytm „klonowania strukturalnego” jest używany automatycznie - nie jest prawdziwe. bugs.chromium.org/p/chromium/issues/detail?id=260378#c18Stałem także przed problemem porządkowania załadowanych skryptów, który został rozwiązany poprzez sekwencyjne ładowanie skryptów. Obciążenie jest na podstawie odpowiedzi Rob W w .
Przykładem użycia byłoby:
Właściwie jestem trochę nowy w JS, więc zachęcaj mnie do pingowania na lepsze sposoby.
źródło
formulaImageUrl
lubcodeImageUrl
, to skutecznie niszczysz funkcjonalność strony. Jeśli chcesz przekazać zmienną do strony internetowej, proponuję dołączyć dane do elementu skryptu (e.g. script.dataset.formulaImageUrl = formulaImageUrl;
) i użyć np.(function() { var dataset = document.currentScript.dataset; alert(dataset.formulaImageUrl;) })();
W skrypcie, aby uzyskać dostęp do danych.dataset
?document.currentScript
wskazuje tylko na znacznik skryptu podczas jego wykonywania. Jeśli kiedykolwiek chcesz uzyskać dostęp do znacznika skryptu i / lub jego atrybutów / właściwości (np.dataset
), Musisz zapisać go w zmiennej. Potrzebujemy IIFE, aby uzyskać zamknięcie do przechowywania tej zmiennej bez zanieczyszczania globalnej przestrzeni nazw.return;
).w skrypcie Content dodaję znacznik script do nagłówka, który wiąże moduł obsługi „onmessage”, wewnątrz modułu obsługi, którego używam, eval do wykonania kodu. W skrypcie zawartości stoiska używam również modułu obsługi onmessage, więc otrzymuję dwukierunkową komunikację. Dokumenty Chrome
pmListener.js to odbiornik adresu URL wiadomości
W ten sposób mogę mieć dwukierunkową komunikację między CS a Real Dom. Jest to bardzo przydatne na przykład, jeśli chcesz odsłuchiwać zdarzenia Webscoket lub dowolne zmienne lub zdarzenia pamięci.
źródło
Możesz użyć funkcji narzędzia, którą utworzyłem, w celu uruchomienia kodu w kontekście strony i odzyskania zwróconej wartości.
Odbywa się to poprzez serializację funkcji do ciągu i wstrzykiwanie jej do strony internetowej.
Narzędzie jest dostępne tutaj na GitHub .
Przykłady użycia -
źródło
Jeśli chcesz wstawić czystą funkcję zamiast tekstu, możesz użyć tej metody:
Do funkcji można przekazywać parametry (niestety nie można strugować żadnych obiektów i tablic). Dodaj go do baretheses w następujący sposób:
źródło