JavaScript - Як отримати URL-адресу викликаного сценарію?


81

Я включаю myscript.js у файл http://site1.com/index.htmlтак:

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

Усередині "myscript.js" я хочу отримати доступ до URL-адреси " http://site2.com/myscript.js ". Я хотів би мати щось подібне:

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

alert(getScriptURL());

Що сповіщатиме " http://site2.com/myscript.js ", якщо буде викликано з вказаного вище index.html.




На основі ваших прикладів URL-адрес, ви можете зауважити, яку поведінку ви очікуєте, якщо браузер налаштований на блокування сторонніх сценаріїв.

Відповіді:


58

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

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

Тепер у змінної myScriptє елемент dom сценарію. Ви можете отримати URL-адресу src, використовуючи myScript.src.

Зверніть увагу, що це потрібно виконати як частину початкової оцінки сценарію. Якщо ви хочете не забруднювати простір імен Javascript, ви можете зробити щось на зразок:

var getScriptURL = (function() {
    var scripts = document.getElementsByTagName('script');
    var index = scripts.length - 1;
    var myScript = scripts[index];
    return function() { return myScript.src; };
})();

23
Чи завжди це буде повертати URL-адресу потрібного сценарію у всіх браузерах? Схоже, він поверне останній тег сценарію, але що, якщо в документі є більше одного тегу сценарію?
MikeC8

3
Гаразд ... моє запитання тоді стає, чи всі браузери завжди повністю завантажують виконати повний вміст віддаленого сценарію перед переходом до наступного тегу сценарію? Наскільки суворо це стандартизовано? Я міг уявити, що це відбувається паралельно ...
MikeC8

1
Потрібно, щоб сценарії працювали повністю і в порядку, через те, що могло б статися, якщо тег сценарію містив document.write. Це є причиною рекомендацій розміщувати сценарії внизу сторінки, оскільки вони фактично блокують завантаження іншого вмісту. Тим не менш, HTML5 модифікує це за допомогою атрибутів async і defer
lambacck

9
Це не спрацьовує, якщо ви завантажуєте сценарій після завантаження сторінки, використовуючи щось подібне: document.getElementsByTagName("head")[0].appendChild(scriptElement);
Seanonymous

16
Я стикався з випадком, коли цей алгоритм не працює надійно. Інші теги скриптів, для яких встановлено асинхронізацію, можуть запускатись між вашим сценарієм, який запитується, і запускатись. Ці скрипти можуть додавати інші сценарії до DOM, які з’являються після вашого. Коли ваш сценарій запущений, останній скрипт на сторінці вже не ваш, і неправильний srcповертається.
Карл

54

Ви можете додати атрибут id до тегу сценарію (навіть якщо він знаходиться всередині тегу head):

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

а потім доступ до його src таким чином:

document.getElementById("myscripttag").src

звичайно, значення ідентифікатора повинно бути однаковим для кожного документа, що включає ваш сценарій, але я не думаю, що це для вас великих незручностей.


1
Цю відповідь слід позначити як "прийняту", оскільки вона охоплює випадки, коли ви викликаєте метод не в контексті "глобального" сценарію або в "асинхронному" сценарії, і це не залежить від реалізації браузера.
Сергій Коваленко

Зверніть увагу, що .srcможе повертати абсолютний шлях, навіть якщо вказано відносний шлях. Ви можете використовувати.getAttribute('src')
Илья Зеленько


18

Я написав клас, щоб знайти шлях до скриптів, який працює із затримкою завантаження та тегами асинхронних скриптів.

У мене було кілька файлів шаблонів, які були відносно моїх сценаріїв, тому замість жорсткого їх кодування я створив клас для автоматичного створення шляхів. Повне джерело знаходиться тут на github.

Деякий час тому мені довелося використовувати аргументи.callee, щоб спробувати зробити щось подібне, але нещодавно я прочитав у MDN, що це не дозволено в суворому режимі .

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('.');
  };
}

1
Трохи запізнився на вечірку тут, але я пробував цей фрагмент коду і виявив, що частина, де він додає 2 до поточного індексу в циклі for "callerIndex = Number (i) + 2;" здається, розрив є непотрібним, і він не працює. Просто усунення "+ 2" спрацьовує. Чи є щось, що я неправильно тлумачу, чи якийсь інший сценарій, для якого було б потрібно + 2?
Скотт Сміт

2
вам не потрібно кидати "Помилка" таким чином (щоб отримати її ".stack"), це просто об'єкт, як інші: console.log (new Error (). stack);
Абдулла

1
Дякую за цю ідею та дякую @ AbdullahAydın за ідею запобігти кидку. Тоді, гадаю, наступний однокласник зробив би трюк, чи не так? var scriptUrl = new Error (). stack.match (/ @ (https?: \ / \ /.+): \ d +: \ d + /) [1]
П'єр-Антуан,

1
Також @ Pierre-Antoine пам’ятайте, що властивість Error.prototype.stack є нестандартною: / ви повинні використовувати її обережно. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Абдулла

3
@ AbdullahAydın: Зверніть увагу, що властивість стека нової помилки не заповнюється у браузерах IE та Edge, доки помилка не буде видалена.
Боб Арлоф

15

якщо у вас є можливість використовувати jQuery, код буде виглядати так:

$('script[src$="/myscript.js"]').attr('src');

Чи працює це зі сценаріями відкладання, асинхронізації та лінивого завантаження?
Stephan

Це просто пошук у DOM для тегу сценарію з src "/myscript.js". інші атрибути не матимуть значення
Ребс

Щоб використовувати це з wordpress у будь-якому іншому місці, що додає версію, слід використовувати $ ('script [src * = "/ myscript.js"]'). Attr ('src'); таким чином він буде ігнорувати? ver = 2.3.3 в кінці сценарію. Значок * продовжуватиме працювати незалежно від того, що в кінці.
Mav2287,

15

Просте і зрозуміле рішення, яке працює дуже добре:

Якщо це не IE, ви можете використовувати document.currentScript
для IE ви можете зробити document.querySelector('script[src*="myscript.js"]')
це:

function getScriptURL(){
 var script =  document.currentScript || document.querySelector('script[src*="myscript.js"]')
 return script.src
}

2

Наступний код дозволяє знайти елемент сценарію із заданою назвою

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;
            }
        }

-6

Ви не можете використовувати location.href або location.host, а потім додати ім'я сценарію?


1
Це не спрацює, оскільки сценарій працює на сторінці site1.com/index.html . Отже, навіть через скрипт, завантажений з site2.com, якщо ви отримаєте доступ до розташування всередині сценарію, він поверне " site1.com/index.html " ...
MikeC8
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.