动态加载 JavaScript 文件

IT技术 javascript file import include
2021-01-25 00:49:21

如何可靠且动态地加载 JavaScript 文件?这将用于实现一个module或组件,当“初始化”该组件将根据需要动态加载所有需要的 JavaScript 库脚本。

使用该组件的客户端不需要加载<script>实现该组件的所有库脚本文件(并手动将标签插入到他们的网页中)——只需加载“主要”组件脚本文件。

主流 JavaScript 库如何实现这一点(Prototype、jQuery 等)? 这些工具是否将多个 JavaScript 文件合并到脚本文件的单个可重新分发的“构建”版本中?或者他们是否对辅助“库”脚本进行任何动态加载?

这个问题的补充:有没有办法在加载动态包含的 JavaScript 文件后处理事件? Prototypedocument.observe用于文档范围的事件。例子:

document.observe("dom:loaded", function() {
  // initially hide all containers for tab content
  $$('div.tabcontent').invoke('hide');
});

脚本元素有哪些可用事件?

6个回答

您可以使用Prototypes动态创建脚本元素

new Element("script", {src: "myBigCodeLibrary.js", type: "text/javascript"});

这里的问题是我们不知道外部脚本文件何时完全加载。

我们经常希望我们的依赖代码在下一行,并且喜欢写这样的东西:

if (iNeedSomeMore) {
    Script.load("myBigCodeLibrary.js"); // includes code for myFancyMethod();
    myFancyMethod(); // cool, no need for callbacks!
}

有一种无需回调即可注入脚本依赖项的智能方法。您只需通过同步 AJAX 请求拉取脚本并在全局级别评估脚本。

如果您使用 Prototype,则 Script.load 方法如下所示:

var Script = {
    _loadedScripts: [],
    include: function(script) {
        // include script only once
        if (this._loadedScripts.include(script)) {
            return false;
        }
        // request file synchronous
        var code = new Ajax.Request(script, {
            asynchronous: false,
            method: "GET",
            evalJS: false,
            evalJSON: false
        }).transport.responseText;
        // eval code on global level
        if (Prototype.Browser.IE) {
            window.execScript(code);
        } else if (Prototype.Browser.WebKit) {
            $$("head").first().insert(Object.extend(
                new Element("script", {
                    type: "text/javascript"
                }), {
                    text: code
                }
            ));
        } else {
            window.eval(code);
        }
        // remember included script
        this._loadedScripts.push(script);
    }
};
2021-03-15 00:49:21
然后,您必须使用其他程序抓取要访问的数据并将其提供给自己
2021-03-19 00:49:21
我该怎么做才能让它跨域工作?(从 加载脚本http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js
2021-04-06 00:49:21
@Ciastopiekarz:我无法控制web.archive.org
2021-04-09 00:49:21

javascript 中没有 import / include / require ,但是有两种主要方法可以实现您想要的:

1 - 您可以使用 AJAX 调用加载它,然后使用 eval。

这是最直接的方法,但由于 Javascript 安全设置,它仅限于您的域,并且使用 eval 为错误和黑客打开了大门。

2 - 在 HTML 中添加带有脚本 URL 的脚本元素。

绝对是最好的出行方式。您甚至可以从外部服务器加载脚本,并且在您使用浏览器解析器评估代码时它很干净。您可以将script元素放在head网页元素中,也可以放在body.

此处讨论和说明了这两种解决方案。

现在,有一个你必须知道的大问题。这样做意味着您远程加载代码。现代 Web 浏览器将加载文件并继续执行您当前的脚本,因为它们异步加载所有内容以提高性能。

这意味着如果您直接使用这些技巧,您将无法在要求加载后的下一行使用新加载的代码,因为它仍然会加载。

EG:my_lovely_script.js 包含 MySuperObject

var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);

var s = new MySuperObject();

Error : MySuperObject is undefined

然后您按 F5 重新加载页面。它有效!令人困惑...

那么该怎么办呢?

好吧,您可以使用作者在我给您的链接中建议的 hack。综上所述,对于赶时间的人来说,他使用en事件在脚本加载时运行一个回调函数。所以你可以把所有使用远程库的代码放在回调函数中。EG :

function loadScript(url, callback)
{
    // adding the script element to the head as suggested before
   var head = document.getElementsByTagName('head')[0];
   var script = document.createElement('script');
   script.type = 'text/javascript';
   script.src = url;

   // then bind the event to the callback function 
   // there are several events for cross browser compatibility
   script.onreadystatechange = callback;
   script.onload = callback;

   // fire the loading
   head.appendChild(script);
}

然后编写要在脚本加载到 lambda 函数后使用的代码:

var myPrettyCode = function() {
    // here, do what ever you want
};

然后你运行所有这些:

loadScript("my_lovely_script.js", myPrettyCode);

好,我知道了。但是写所有这些东西很痛苦。

那么,在这种情况下,您可以像往常一样使用出色的免费 jQuery 框架,它可以让您在一行中完成相同的事情:

$.getScript("my_lovely_script.js", function() {
    alert("Script loaded and executed.");
    // here you can use anything you defined in the loaded script
});
有用。最后我用它解决了我的 CSP nonce 问题。谢谢你。
2021-03-20 00:49:21
对于角度中的“$”,我遵循了这个:stackoverflow.com/questions/32050645/...
2021-03-21 00:49:21
这有效。我希望在这里分享我的经验可以节省您的时间,因为我花了很多时间在这上面。我正在使用 Angular 6 和应用模板 (html,css,jquery) 问题是模板有一个 js 文件,它在加载 html 元素以附加侦听器事件后加载。加载 angular 应用程序后,该 js 文件很难执行。将它添加到 angular app ( angular.json) 脚本标签将捆绑它们但在加载后不执行该 js 文件。用typescript重写的代码太多,所以这很有帮助。下一条评论我会放这个例子,因为评论长度
2021-03-22 00:49:21
这篇文章的部分内容似乎抄袭了stackoverflow.com/a/950146/6243352
2021-03-28 00:49:21
我简单地使用了这个代码如下: ngAfterViewInit() { debugger; $.getScript("/assets/js/jquery.app.js", function() { alert("脚本加载并执行。"); // 这里你可以使用你在加载脚本中定义的任何东西 }); }
2021-03-29 00:49:21

最近jQuery使用了一个不太复杂的版本

<script src="scripts/jquery.js"></script>
<script>
  var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"];
  var $head = $("head");
  for (var i = 0; i < js.length; i++) {
    $head.append("<script src=\"" + js[i] + "\"></scr" + "ipt>");
  }
</script>

它在我测试过的所有浏览器中都运行良好:IE6/7、Firefox、Safari、Opera。

更新:无jQuery 版本:

<script>
  var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"];
  for (var i = 0, l = js.length; i < l; i++) {
    document.getElementsByTagName("head")[0].innerHTML += ("<script src=\"" + js[i] + "\"></scr" + "ipt>");
  }
</script>
太好了……除非您尝试加载 jquery。
2021-03-13 00:49:21
Modernizr (yepnope.js) 或 lab.js 是合适的解决方案。使用繁重的脚本库(必须首先加载)并不是最适合移动设备或许多其他情况的答案。
2021-03-15 00:49:21
@MaulikGangani 较旧的浏览器和 html 验证器会将其解释为结束脚本的令牌。
2021-03-21 00:49:21
使用 jQuery 的更好方法是使用$.getScript. 看我的回答。
2021-03-23 00:49:21
看起来 jQuery 将在未来版本中将 Require 插件引入 jQuery Core:plugins.jquery.com/project/require
2021-03-25 00:49:21

我做了与你做 Adam 的基本相同的事情,但稍作修改以确保我附加到head元素以完成工作。我只是创建了一个include函数(下面的代码)来处理脚本和 CSS 文件。

此函数还会检查以确保尚未动态加载脚本或 CSS 文件。它不检查手动编码的值,可能有更好的方法来做到这一点,但它达到了目的。

function include( url, type ){
    // First make sure it hasn't been loaded by something else.
    if( Array.contains( includedFile, url ) )
        return;
     
    // Determine the MIME type.
    var jsExpr = new RegExp( "js$", "i" );
    var cssExpr = new RegExp( "css$", "i" );
    if( type == null )
        if( jsExpr.test( url ) )
            type = 'text/javascript';
        else if( cssExpr.test( url ) )
            type = 'text/css';
            
    // Create the appropriate element.
    var element = null;
    switch( type ){
        case 'text/javascript' :
            element = document.createElement( 'script' );
            element.type = type;
            element.src = url;
            break;
        case 'text/css' :
            element = document.createElement( 'link' );
            element.rel = 'stylesheet';
            element.type = type;
            element.href = url;
            break;
    }
    
    // Insert it to the <head> and the array to ensure it is not
    // loaded again.
    document.getElementsByTagName("head")[0].appendChild( element );
    Array.add( includedFile, url );
}
@palehorse,Mike 和 Muhd 是对的,它可能在您的项目中工作,但那是因为必须在项目的其他地方定义“includedFile”和“Array”变量,此代码本身不会运行,它可能是最好编辑它,以便它可以在您的项目上下文之外工作,或者至少添加一个注释来解释那些未定义的变量是什么(类型等)
2021-03-26 00:49:21
没有比那个泡菜更多的背景,恐怕我没有任何建议。上面的代码按原样工作,它是直接从一个正在运行的项目中提取的。
2021-03-31 00:49:21

另一个很棒的答案

$.getScript("my_lovely_script.js", function(){


   alert("Script loaded and executed.");
  // here you can use anything you defined in the loaded script

 });

https://stackoverflow.com/a/950146/671046

我该怎么做才能让它跨域工作?(从 加载脚本http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js
2021-03-14 00:49:21