我如何引用加载当前正在执行的脚本的脚本标记?

275 javascript element parent

如何引用加载当前运行的javascript的脚本元素?

这是情况.我在页面中加载了一个"主"脚本,首先是在HEAD标记下.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript" src="scripts.js"></script>
Run Code Online (Sandbox Code Playgroud)

"scripts.js"中有一个脚本,它需要能够按需加载其他脚本.普通方法对我来说并不适用,因为我需要添加新脚本而不引用HEAD标记,因为HEAD元素还没有完成渲染:

document.getElementsByTagName('head')[0].appendChild(v);
Run Code Online (Sandbox Code Playgroud)

我想要做的是引用加载当前脚本的脚本元素,以便然后我可以将新的动态加载的脚本标记添加到DOM之后.

<script type="text/javascript" src="scripts.js"></script>
loaded by scripts.js--><script type="text/javascript" src="new_script1.js"></script>
loaded by scripts.js --><script type="text/javascript" src="new_script2.js"></script>
Run Code Online (Sandbox Code Playgroud)

bri*_*ice 602

如何获取当前脚本元素:

1.使用 document.currentScript

document.currentScript将返回<script>其脚本当前正在处理的元素.

<script>
var me = document.currentScript;
</script>
Run Code Online (Sandbox Code Playgroud)

优点

  • 简单明了.可靠.
  • 不需要修改脚本标记
  • 使用异步脚本(defer&async)
  • 使用动态插入的脚本

问题

  • 将无法在旧版浏览器和IE中使用.

2.按ID选择脚本

为脚本提供id属性将允许您在使用中通过id轻松选择它<script type="module">.

<script id="myscript">
var me = document.getElementById('myscript');
</script>
Run Code Online (Sandbox Code Playgroud)

优点

  • 简单明了.可靠.
  • 几乎得到普遍支持
  • 使用异步脚本(document.getElementById()&defer)
  • 使用动态插入的脚本

问题

  • 需要向脚本标记添加自定义属性
  • async 对于某些边缘情况,属性可能会在某些浏览器中导致脚本的奇怪行为

3.使用id属性选择脚本

为脚本提供data-*属性将允许您从内部轻松选择它.

<script data-name="myscript">
var me = document.querySelector('script[data-name="myscript"]');
</script>
Run Code Online (Sandbox Code Playgroud)

这比以前的选项几乎没有什么好处.

优点

  • 简单明了.
  • 使用异步脚本(data-*&defer)
  • 使用动态插入的脚本

问题

  • 需要向脚本标记添加自定义属性
  • HTML5,async并不适用于所有浏览器
  • 支持不如使用querySelector()属性
  • 会得到解决id<script>边缘情况.
  • 如果另一个元素在页面上具有相同的数据属性和值,可能会感到困惑.

4.按src选择脚本

您可以使用选择器按源选择脚本,而不是使用数据属性:

<script src="//example.com/embed.js"></script>
Run Code Online (Sandbox Code Playgroud)

在embed.js中:

var me = document.querySelector('script[src="//example.com/embed.js"]');
Run Code Online (Sandbox Code Playgroud)

优点

  • 可靠
  • 使用异步脚本(id&defer)
  • 使用动态插入的脚本
  • 无需自定义属性或ID

问题

  • 难道不是对本地脚本工作
  • 会在开发和生产等不同环境中引发问题
  • 静而脆弱.更改脚本文件的位置将需要修改脚本
  • 支持不如使用async属性
  • 如果两次加载相同的脚本,将导致问题

5.遍历所有脚本以找到所需的脚本

我们还可以遍历每个脚本元素并单独检查每个脚本元素以选择我们想要的那个:

<script>
var me = null;
var scripts = document.getElementsByTagName("script")
for (var i = 0; i < scripts.length; ++i) {
    if( isMe(scripts[i])){
      me = scripts[i];
    }
}
</script>
Run Code Online (Sandbox Code Playgroud)

这使我们可以在不支持id属性的旧浏览器中使用以前的技术.例如:

function isMe(scriptElem){
    return scriptElem.getAttribute('src') === "//example.com/embed.js";
}
Run Code Online (Sandbox Code Playgroud)

这继承了所采取的任何方法的好处和问题,但不依赖querySelector()于此将在旧版浏览器中工作.

6.获取最后执行的脚本

由于脚本是按顺序执行的,因此最后一个脚本元素通常是当前运行的脚本:

<script>
var scripts = document.getElementsByTagName( 'script' );
var me = scripts[ scripts.length - 1 ];
</script>
Run Code Online (Sandbox Code Playgroud)

优点

  • 简单.
  • 几乎得到普遍支持
  • 无需自定义属性或ID

问题

  • 难道不是异步脚本工作(querySelector()&defer)
  • 难道不是与动态插入脚本工作

  • 谢谢大家,但是你知道我接受了4*年*后接受了答案,对:) (24认同)
  • 这应该是答案. (4认同)
  • "document.currentScript"对我来说不适用于动态加载脚本,在最新的chrome/firefox中返回null,"最后执行的脚本"工作正常 (4认同)
  • 当`script`位于插入Shadow DOM的`template`中时不起作用 (3认同)
  • 完全尊重 @brice 在接受答案大约 4 年后对他的评论保持谦虚(我在发布后_9_年发表此评论,不知道那个接受的答案去了哪里......)。这是一个极好的答案,对我帮助很大。_这_是使它运作得如此顺利的 SO 社区 - 制作人用这些类型的答案重新回答旧帖子有利于像我这样的消费者,他们偶然发现这些过时的帖子并收集有价值的金块。谢谢你,先生! (3认同)
  • 同意@RoyiNamir 的观点。这是最好的答案。 (2认同)

Cof*_*ite 85

由于脚本是按顺序执行的,因此当前执行的脚本标记始终是页面上的最后一个脚本标记.因此,要获取脚本标记,您可以执行以下操作:

var scripts = document.getElementsByTagName( 'script' );
var thisScriptTag = scripts[ scripts.length - 1 ];
Run Code Online (Sandbox Code Playgroud)

  • 我可以想到一个可能会返回错误结果的实例是将脚本标记异步添加到DOM中. (52认同)
  • 是的,这可能有不可预测的结果,所以你可以尝试使用选择器:$('script [src*="/ mysource.js"]')??? (9认同)
  • 在页面加载后加载脚本时,它不起作用.您可能无法获得正确的标签. (6认同)
  • 这很简单而优雅.如果您解压缩javascript,新的Google Charts/Visualizations API就会有一个例子.他们从脚本标记中加载JSON数据,请参阅:http://ajax.googleapis.com/ajax/static/modules/gviz/1.0/chart.js (3认同)
  • 这是个好主意,通常对我有用。但我应该补充一点,有时我发现它返回对不同脚本的引用。不知道为什么 - 一直无法追踪到。因此,我通常采用不同的方法,例如,我对脚本文件的名称进行硬编码,然后查找具有该文件名的脚本标记。 (2认同)

Gre*_*reg 11

可能最简单的方法是给你的scrip标签一个id属性.

  • 虽然你是对的,但在很多情况下 OP 的问题是有效的,有几种情况:1)当你爬行时 2)当你使用客户端的 DOM 时,他不愿意改变 (3认同)

小智 10

仅当脚本没有"延迟"或"异步"属性时,才会按顺序执行脚本.知道脚本标记的一个可能的ID/SRC/TITLE属性也可以在这些情况下工作.所以格雷格和贾斯汀的建议都是正确的.

document.currentScript关于WHATWG清单的提案已经提出.

编辑:Firefox> 4已经实现了这个非常有用的属性,但它在IE11中不可用,最后我检查过,仅在Chrome 29和Safari 8中可用.

编辑:没有人提到"document.scripts"集合,但我相信以下可能是一个很好的跨浏览器替代方案来获取当前正在运行的脚本:

var me = document.scripts[document.scripts.length -1];
Run Code Online (Sandbox Code Playgroud)


小智 9

这里有一些polyfill,document.CurrentScript如果它存在则会利用它并回退到通过ID查找脚本.

<script id="uniqueScriptId">
    (function () {
        var thisScript = document.CurrentScript || document.getElementByID('uniqueScriptId');

        // your code referencing thisScript here
    ());
</script>
Run Code Online (Sandbox Code Playgroud)

如果将其包含在每个脚本标记的顶部,我相信您将能够始终知道正在触发哪个脚本标记,并且您还能够在异步回调的上下文中引用脚本标记.

未经测试,如果您尝试,请留下反馈给其他人.

  • @nr - 不,**所有** 元素都可以有一个 `id` 属性。`id`、`class` 和 `slot` 定义在 DOM 级别,而不是 HTML 级别。如果您转到 [HTML 中的全局属性](https://html.spec.whatwg.org/multipage/dom.html#global-attributes) 并滚动列表,您会发现 *"DOM 标准定义了用户代理对任何命名空间中任何元素的 class、id 和 slot 属性的要求。"* 后跟 *"可以在所有 HTML 元素上指定 class、id 和 slot 属性。"* DOM 规范涵盖了它 [here ](https://html.spec.whatwg.org/multipage/dom.html#global-attributes)。 (2认同)

小智 6

它必须在页面加载时以及使用javascript添加脚本标记时(例如,使用ajax)

<script id="currentScript">
var $this = document.getElementById("currentScript");
$this.setAttribute("id","");
//...
</script>
Run Code Online (Sandbox Code Playgroud)


小智 6

要获取当前加载的脚本,您可以使用脚本

var thisScript = document.currentScript;
Run Code Online (Sandbox Code Playgroud)

您需要在脚本的开头保留引用,以便稍后调用

var url = thisScript.src
Run Code Online (Sandbox Code Playgroud)


Pet*_*ois 5

处理异步和延迟脚本的一种方法是利用 onload 处理程序 - 为所有脚本标记设置一个 onload 处理程序,第一个执行的应该是您的。

function getCurrentScript(callback) {
  if (document.currentScript) {
    callback(document.currentScript);
    return;
  }
  var scripts = document.scripts;
  function onLoad() {
    for (var i = 0; i < scripts.length; ++i) {
      scripts[i].removeEventListener('load', onLoad, false);
    }
    callback(event.target);
  }
  for (var i = 0; i < scripts.length; ++i) {
    scripts[i].addEventListener('load', onLoad, false);
  }
}

getCurrentScript(function(currentScript) {
  window.console.log(currentScript.src);
});
Run Code Online (Sandbox Code Playgroud)