JavaScript - jak uzyskać adres URL wywoływanego skryptu?

81

Dołączam myscript.js do pliku w http://site1.com/index.htmlten sposób:

<script src=http://site2.com/myscript.js></script>

Wewnątrz „myscript.js” chcę uzyskać dostęp do adresu URL „ http://site2.com/myscript.js ”. Chciałbym mieć coś takiego:

function getScriptURL() {
    // something here
    return s
}

alert(getScriptURL());

Który ostrzegłby „ http://witryna2.com/myscript.js ”, gdyby został wywołany z pliku index.html wspomnianego powyżej.

MikeC8
źródło
możliwy duplikat What is my script src URL?
ripper234,
Na podstawie przykładowych adresów URL możesz chcieć zanotować oczekiwane zachowanie, jeśli przeglądarka jest ustawiona na blokowanie skryptów innych firm.

Odpowiedzi:

58

Z http://feather.elektrum.org/book/src.html :

var scripts = document.getElementsByTagName('script');
var index = scripts.length - 1;
var myScript = scripts[index];

Zmienna myScriptma teraz element script dom. Adres URL src można uzyskać za pomocą myScript.src.

Należy pamiętać, że musi to zostać wykonane jako część wstępnej oceny skryptu. Jeśli nie chcesz zanieczyszczać przestrzeni nazw Javascript, możesz zrobić coś takiego:

var getScriptURL = (function() {
    var scripts = document.getElementsByTagName('script');
    var index = scripts.length - 1;
    var myScript = scripts[index];
    return function() { return myScript.src; };
})();
lambacck
źródło
23
Czy to jednak zawsze zwróci adres URL właściwego skryptu we wszystkich przeglądarkach? Wygląda na to, że zwróci ostatni znacznik script, ale co się stanie, jeśli dokument zawiera więcej niż jeden znacznik script?
MikeC8
3
Ok ... moje pytanie brzmi: czy wszystkie przeglądarki zawsze w pełni ładują i wykonują całą zawartość zdalnego skryptu przed przejściem do następnego znacznika skryptu? Jak rygorystycznie jest to znormalizowane? Mogę sobie wyobrazić, że dzieje się to równolegle ...
MikeC8
1
Wymagane jest, aby skrypty działały w całości i w odpowiedniej kolejności, ze względu na to, co by się stało, gdyby tag script zawierał plik document.write. Z tego powodu zaleca się umieszczanie skryptów na dole strony, ponieważ w rzeczywistości będą one blokować ładowanie innych treści. To powiedziawszy, HTML5 modyfikuje to za pomocą atrybutów async i defer
lambacck
9
To nie zadziała, jeśli załadujesz skrypt po załadowaniu strony, używając czegoś takiego: document.getElementsByTagName("head")[0].appendChild(scriptElement);
Seanonymous,
16
Trafiłem na przypadek, w którym ten algorytm nie działa niezawodnie. Inne tagi skryptów, które są ustawione na asynchroniczne, mogą działać między żądaniem a uruchomieniem skryptu. Te skrypty mogą dodawać inne skrypty do DOM, które pojawiają się po Twoim. Kiedy Twój skrypt uruchamia ostatni skrypt na stronie, nie należy już do Ciebie i srczwracany jest nieprawidłowy .
Karl
54

Możesz dodać atrybut id do swojego tagu skryptu (nawet jeśli znajduje się wewnątrz tagu head):

<script id="myscripttag" src="http://site2.com/myscript.js"></script>

a następnie uzyskaj dostęp do jego źródła w następujący sposób:

document.getElementById("myscripttag").src

oczywiście wartość id powinna być taka sama dla każdego dokumentu zawierającego twój skrypt, ale nie sądzę, żeby była to dla ciebie duża niedogodność.

tsds
źródło
1
Ta odpowiedź powinna być oznaczona jako „zaakceptowana”, ponieważ obejmuje przypadki, gdy wywołujesz metodę poza „globalnym” kontekstem skryptu lub w skrypcie „async” i nie zależy to od implementacji przeglądarki.
Siergiej Kowalenko
Zauważ, że .srcmoże zwrócić ścieżkę bezwzględną, nawet jeśli została określona ścieżka względna. Możesz użyć.getAttribute('src')
Илья Зеленько
18

Napisałem klasę, aby znaleźć ścieżkę skryptów, które działają z opóźnionym ładowaniem i tagami skryptu asynchronicznego.

Miałem kilka plików szablonów, które były względne w stosunku do moich skryptów, więc zamiast na sztywno je kodować, stworzyłem klasę do automatycznego tworzenia ścieżek. Pełne źródło jest tutaj na github.

Jakiś czas temu użyłem arguments.callee, aby spróbować zrobić coś podobnego, ale ostatnio przeczytałem w MDN, że nie jest to dozwolone w trybie ścisłym .

function ScriptPath() {
  var scriptPath = '';
  try {
    //Throw an error to generate a stack trace
    throw new Error();
  }
  catch(e) {
    //Split the stack trace into each line
    var stackLines = e.stack.split('\n');
    var callerIndex = 0;
    //Now walk though each line until we find a path reference
    for(var i in stackLines){
      if(!stackLines[i].match(/http[s]?:\/\//)) continue;
      //We skipped all the lines with out an http so we now have a script reference
      //This one is the class constructor, the next is the getScriptPath() call
      //The one after that is the user code requesting the path info (so offset by 2)
      callerIndex = Number(i) + 2;
      break;
    }
    //Now parse the string for each section we want to return
    pathParts = stackLines[callerIndex].match(/((http[s]?:\/\/.+\/)([^\/]+\.js)):/);
  }

  this.fullPath = function() {
    return pathParts[1];
  };

  this.path = function() {
    return pathParts[2];
  };

  this.file = function() {
    return pathParts[3];
  };

  this.fileNoExt = function() {
    var parts = this.file().split('.');
    parts.length = parts.length != 1 ? parts.length - 1 : 1;
    return parts.join('.');
  };
}
QueueHammer
źródło
1
Trochę za późno na imprezę tutaj, ale próbowałem tego fragmentu kodu i stwierdziłem, że część, w której dodaje 2 do bieżącego indeksu w pętli for "callerIndex = Number (i) + 2;" wydaje się, że pęknięcie jest niepotrzebne i powoduje, że nie działa. Po prostu wyeliminowanie „+ 2” powoduje, że działa. Czy jest coś, co źle interpretuję lub jakiś inny scenariusz, do którego to + 2 byłoby konieczne?
Scott Smith
2
nie musisz w ten sposób wyrzucać „Error” (aby otrzymać „.stack”), jest to po prostu obiekt taki jak inne: console.log (new Error (). stack);
Abdullah
1
Dzięki za ten pomysł i @ AbdullahAydın za pomysł zapobiegania rzutowi. W takim razie myślę, że poniższy jednoliniowiec załatwi sprawę, prawda? var scriptUrl = new Error (). stack.match (/ @ (https?: \ / \ /.+): \ d +: \ d + /) [1]
Pierre-Antoine
1
Również @ Pierre-Antoine pamiętaj, że właściwość Error.prototype.stack jest niestandardowa: / powinieneś używać jej ostrożnie. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Abdullah
3
@ AbdullahAydın: Zwróć uwagę, że właściwość stosu nowego błędu nie jest wypełniana w przeglądarkach IE i Edge, dopóki błąd nie zostanie zgłoszony.
Bob Arlof,
15

jeśli masz szansę skorzystać z jQuery, kod wyglądałby tak:

$('script[src$="/myscript.js"]').attr('src');
Mr. Pumpkin
źródło
Czy działa ze skryptami odroczenia, asynchronicznego i leniwego ładowania?
Stephan
Po prostu przeszukuje DOM w poszukiwaniu tagu skryptu z src „/myscript.js”. inne atrybuty nie będą miały znaczenia
Rebs
Aby użyć tego z wordpress w jakimkolwiek innym miejscu, które dołącza wersję, należy użyć $ ('script [src * = "/ myscript.js"]'). Attr ('src'); w ten sposób zignoruje? ver = 2.3.3 na końcu skryptu. * Sprawi, że będzie działać niezależnie od tego, co zostanie na końcu.
Mav2287
15

Proste i nieskomplikowane rozwiązanie, które działa bardzo dobrze:

Jeśli nie jest to IE, możesz użyć document.currentScript
dla IE, możesz to zrobić document.querySelector('script[src*="myscript.js"]')
:

function getScriptURL(){
 var script =  document.currentScript || document.querySelector('script[src*="myscript.js"]')
 return script.src
}
pery mimon
źródło
2

Poniższy kod pozwala znaleźć element skryptu o podanej nazwie

var scripts = document.getElementsByTagName( 'script' );
        var len = scripts.length
        for(var i =0; i < len; i++) {
            if(scripts[i].src.search("<your JS file name") > 0 && scripts[i].src.lastIndexOf("/") >= 0) {
                absoluteAddr = scripts[i].src.substring(0, scripts[i].src.lastIndexOf("/") + 1);
                break;
            }
        }
Varun Bhatia
źródło
-6

Nie możesz użyć pliku location.href lub location.host, a następnie dołączyć nazwę skryptu?

Paweł
źródło
1
To nie zadziała, ponieważ skrypt działa na stronie site1.com/index.html . Tak więc, nawet przez skrypt jest ładowany z site2.com, jeśli masz dostęp do lokalizacji z poziomu skryptu, to wróci „ site1.com/index.html ” ...
MikeC8