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

2020/10/03 18:21 · javascript ·  · 0评论

如何引用加载了当前正在运行的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>

“ scripts.js”中有一个脚本,该脚本需要能够按需加载其他脚本。普通方法对我来说不太有效,因为我需要添加新脚本而不引用HEAD标签,因为HEAD元素尚未完成渲染:

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

我想做的是引用加载了当前脚本的script元素,以便随后可以将新的动态加载的脚本标签附加到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>

如何获取当前脚本元素:

1.使用 document.currentScript

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

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

好处

  • 简单明了。可靠。
  • 不需要修改脚本标签
  • 适用于异步脚本(deferasync
  • 与动态插入的脚本一起使用

问题

  • 在较旧的浏览器和IE中将无法使用。
  • 不适用于模块 <script type="module">

2.按编号选择脚本

为脚本提供id属性可以让您轻松地通过使用id通过id选择它document.getElementById()

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

好处

  • 简单明了。可靠。
  • 几乎得到普遍支持
  • 适用于异步脚本(deferasync
  • 与动态插入的脚本一起使用

问题

  • 需要向脚本标签添加自定义属性
  • id 属性在某些情况下可能会导致某些浏览器中脚本的怪异行为

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

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

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

与以前的选择相比,这没有什么好处。

好处

  • 简单明了。
  • 适用于异步脚本(deferasync
  • 与动态插入的脚本一起使用

问题

  • 需要向脚本标签添加自定义属性
  • 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"]');

好处

  • 可靠
  • 适用于异步脚本(deferasync
  • 与动态插入的脚本一起使用
  • 无需自定义属性或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>
var scripts = document.getElementsByTagName( 'script' );
var me = scripts[ scripts.length - 1 ];
</script>

好处

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

问题

  • 难道不是异步脚本工作(deferasync
  • 难道不是与动态插入脚本工作

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

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

可能最简单的方法是为您的脚本标签赋予id属性。

这是一个polyfill,可以利用document.CurrentScript它的存在,并且可以通过ID查找脚本。

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

        // your code referencing thisScript here
    ());
</script>

如果您将其包含在每个脚本标签的顶部,我相信您将能够一致地知道正在触发哪个脚本标签,并且还可以在异步回调的上下文中引用该脚本标签。

未经测试,因此请尝试给他人留下反馈。

仅当脚本没有“ defer”或“ async”属性时,才按顺序执行脚本。在这些情况下,了解脚本标签的可能的ID / SRC / TITLE属性之一也可能有效。因此,格雷格和贾斯汀的建议都是正确的。

document.currentScript在WHATWG清单上已经有一个建议

编辑:Firefox> 4已经实现了这个非常有用的属性,但是我上次检查它在IE11中不可用,并且仅在Chrome 29和Safari 8中可用。

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

var me = document.scripts[document.scripts.length -1];

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

<script id="currentScript">
var $this = document.getElementById("currentScript");
$this.setAttribute("id","");
//...
</script>

请按照以下简单步骤获取对当前正在执行的脚本块的引用:

  1. 在脚本块中放置一些随机的唯一字符串(每个脚本块中必须唯一/不同)
  2. 迭代document.getElementsByTagName('script')的结果,从它们的每个内容中查找唯一的字符串(从innerText / textContent属性获得)。

示例(ABCDE345678是唯一ID)

<script type="text/javascript">
var A=document.getElementsByTagName('script'),i=count(A),thi$;
for(;i;thi$=A[--i])
  if((thi$.innerText||thi$.textContent).indexOf('ABCDE345678'))break;
// Now thi$ is refer to current script block
</script>

顺便说一句,对于您的情况,您可以简单地使用老式的document.write()方法来包含另一个脚本。正如您提到的DOM尚未呈现一样,您可以利用浏览器始终按线性顺序执行脚本的优势(除了延迟的脚本将在以后呈现),因此文档的其余部分仍然“不存在”。您通过document.write()编写的所有内容都将放在调用者脚本之后。

原始HTML页面示例

<!doctype html>
<html><head>
<script src="script.js"></script>
<script src="otherscript.js"></script>
<body>anything</body></html>

script.js的内容

document.write('<script src="inserted.js"></script>');

渲染后,DOM结构将变为:

HEAD
  SCRIPT script.js
  SCRIPT inserted.js
  SCRIPT otherscript.js
BODY

处理异步和延迟脚本的一种方法是利用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);
});

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

var thisScript = document.currentScript;

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

var url = thisScript.src

考虑这个算法。当脚本加载时(如果有多个相同的脚本),请浏览document.scripts,找到第一个具有正确“ src”属性的脚本,然后保存并使用数据属性或唯一的className将其标记为“已访问”。

当下一个脚本加载时,再次浏览document.scripts,越过任何已标记为已访问的脚本。取得该脚本的第一个未访问实例。

假设相同的脚本可能会按照从头到正文,从上到下,从同步到异步的加载顺序执行。

(function () {
  var scripts = document.scripts;

  // Scan for this data-* attribute
  var dataAttr = 'data-your-attribute-here';

  var i = 0;
  var script;
  while (i < scripts.length) {
    script = scripts[i];
    if (/your_script_here\.js/i.test(script.src)
        && !script.hasAttribute(dataAttr)) {

        // A good match will break the loop before
        // script is set to null.
        break;
    }

    // If we exit the loop through a while condition failure,
    // a check for null will reveal there are no matches.
    script = null;
    ++i;
  }

  /**
   * This specific your_script_here.js script tag.
   * @type {Element|Node}
   */
  var yourScriptVariable = null;

  // Mark the script an pass it on.
  if (script) {
    script.setAttribute(dataAttr, '');
    yourScriptVariable = script;
  }
})();

这将在所有脚本中进行扫描,以查找未使用special属性标记的第一个匹配脚本。

然后,如果找到该节点,则将其标记为数据属性,以便后续扫描不会选择它。这类似于图遍历BFS和DFS算法,其中可以将节点标记为“已访问”以防止重新访问。

我已经知道了,它可以在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 );
}

如果可以假定脚本的文件名,则可以找到它。到目前为止,我仅在Firefox中真正测试了以下功能。

  function findMe(tag, attr, file) {
    var tags = document.getElementsByTagName(tag);
    var r = new RegExp(file + '$');
    for (var i = 0;i < tags.length;i++) {
      if (r.exec(tags[i][attr])) {
        return tags[i][attr];
      }
    }
  };
  var element = findMe('script', 'src', 'scripts.js');

script使用这种通常的替代方法动态地插入标签,evalcurrentComponentScript在添加到DOM之前直接设置了一个全局属性

  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是上一个段落之后的下一个段落即链接setTimeouts,而不仅仅是setTimeout从循环中连续调用多次。

我发现以下代码是最一致,最有效和最简单的。

var scripts = document.getElementsByTagName('script');
var thisScript = null;
var i = scripts.length;
while (i--) {
  if (scripts[i].src && (scripts[i].src.indexOf('yourscript.js') !== -1)) {
    thisScript = scripts[i];
    break;
  }
}
console.log(thisScript);
本文地址:http://javascript.askforanswer.com/ruheyinyongjiazailedangqianzhengzaizhixingdejiaobendejiaobenbiaoqian.html
文章标签: ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!