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

情况是这样的。我有一个“主”脚本被加载在页面的高,第一件事下的头标签。

<!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>

在“scripts.js”中有一个脚本,需要能够按需加载其他脚本。正常的方法不太适合我,因为我需要添加新的脚本而不引用HEAD标记,因为HEAD元素还没有完成渲染:

document.getElementsByTagName('head')[0].appendChild(v);

我要做的是引用加载当前脚本的脚本元素,这样我就可以在它之后将新的动态加载的脚本标记追加到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>

当前回答

我用这个通常的eval替代方法动态地插入脚本标记,并在添加到DOM之前简单地设置一个全局属性currentComponentScript。

  const old = el.querySelector("script")[0];
  const replacement = document.createElement("script");
  replacement.setAttribute("type", "module");
  replacement.appendChild(document.createTextNode(old.innerHTML));
  window.currentComponentScript = replacement;
  old.replaceWith(replacement);

但在循环中不能工作。DOM直到下一个宏任务才运行脚本,因此其中的一批脚本只能看到最后一个值集。你必须setTimeout整个段落,然后在前一段结束后setTimeout下一段。例如,将setTimeout链接起来,而不是在循环中在一行中多次调用setTimeout。

其他回答

我用这个通常的eval替代方法动态地插入脚本标记,并在添加到DOM之前简单地设置一个全局属性currentComponentScript。

  const old = el.querySelector("script")[0];
  const replacement = document.createElement("script");
  replacement.setAttribute("type", "module");
  replacement.appendChild(document.createTextNode(old.innerHTML));
  window.currentComponentScript = replacement;
  old.replaceWith(replacement);

但在循环中不能工作。DOM直到下一个宏任务才运行脚本,因此其中的一批脚本只能看到最后一个值集。你必须setTimeout整个段落,然后在前一段结束后setTimeout下一段。例如,将setTimeout链接起来,而不是在循环中在一行中多次调用setTimeout。

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

var thisScript = document.currentScript;

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

var url = thisScript.src

如何获取当前脚本元素:

1. 使用document.currentScript

文档。currentScript将返回当前正在处理的<script>元素。

<script>
var me = document.currentScript;
</script>

好处

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

问题

不能在旧的浏览器和IE中工作。 <script type="module">

2. 按id选择脚本

给脚本一个id属性可以让您使用document.getElementById()从内部通过id轻松地选择它。

<script id="myscript">
var me = document.getElementById('myscript');
</script>

好处

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

问题

需要向脚本标记添加自定义属性 Id属性在某些边缘情况下可能会导致某些浏览器中的脚本出现奇怪的行为

3.使用data-*属性选择脚本

给脚本一个data-*属性可以让您轻松地从内部选择它。

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

与前一个选项相比,这几乎没有什么好处。

好处

简单明了。 使用异步脚本(defer & async) 使用动态插入的脚本

问题

需要向脚本标记添加自定义属性 HTML5和querySelector()在所有浏览器中都不兼容 与使用id属性相比,支持较少 将绕过<script>与id边缘情况。 如果页面上的另一个元素具有相同的数据属性和值,则可能会混淆。

4. 根据src选择脚本

不使用数据属性,你可以使用选择器根据源来选择脚本:

<script src="//example.com/embed.js"></script>

在embed.js:

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

好处

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

问题

不工作的本地脚本 会在不同的环境中造成问题,比如开发和生产 静止而脆弱。更改脚本文件的位置需要修改脚本 与使用id属性相比,支持较少 是否会导致问题,如果你加载相同的脚本两次

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>

这让我们可以在不很好地支持querySelector()属性的旧浏览器中使用上述两种技术。例如:

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

这继承了采用任何方法的优点和问题,但不依赖于querySelector(),因此可以在旧的浏览器中工作。

6. 获取最后执行的脚本

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

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

好处

简单。 几乎得到了普遍支持 不需要自定义属性或id

问题

不能使用异步脚本(defer & async) 不与动态插入的脚本一起工作

我有这个,它在FF3, IE6和7中工作。按需加载脚本中的方法直到页面加载完成才可用,但这仍然非常有用。

//handle on-demand loading of javascripts
makescript = function(url){
    var v = document.createElement('script');
    v.src=url;
    v.type='text/javascript';

    //insertAfter. Get last <script> tag in DOM
    d=document.getElementsByTagName('script')[(document.getElementsByTagName('script').length-1)];
    d.parentNode.insertBefore( v, d.nextSibling );
}

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