【问题标题】:Dynamically load JS inside JS [duplicate]在 JS 中动态加载 JS [重复]
【发布时间】:2013-01-09 09:00:59
【问题描述】:

我有一个动态网页,我需要在另一个 javascript 文件中导入一个外部 JS 文件(在 IF 条件下)。

我试图寻找可行的解决方案,但没有奏效。

我曾尝试使用document.createElement() 将 JS 文件加载到 DOM,但它也没有成功。显然 Js 已加载到 DOM 中,但在当前 JS 文件中无法访问。

jQuery 中的解决方案也可以

【问题讨论】:

标签: javascript jquery


【解决方案1】:

我的猜测是,在您的仅 DOM 解决方案中,您执行了以下操作:

var script = document.createElement('script');
script.src = something;
//do stuff with the script

首先,这是行不通的,因为脚本没有添加到文档树中,所以它不会被加载。此外,即使您这样做了,在加载其他脚本时仍会继续执行 javascript,因此在该脚本完全加载之前,您将无法使用其内容。

您可以收听脚本的load 事件,并按照您的意愿处理结果。所以:

var script = document.createElement('script');
script.onload = function () {
    //do stuff with the script
};
script.src = something;

document.head.appendChild(script); //or something of the likes

【讨论】:

  • 没有必要把事情复杂化。太棒了
  • 确保在onload属性source之后设置src属性
  • 这确实应该是最好的答案,这样的简单任务不需要使用jQuery!
  • @woojoo666 为什么在onload 之后?只在appendchild 之前设置src 还不够吗?
  • @AliSharabiani 哎呀,你是对的,只有元素已经在页面上才重要。根据我的经验,在设置src 之前首先在页面上放置元素更为常见,主要是在您想要动态更改 src 的所有情况中,例如img标签之类的。所以我认为更好的做法是习惯将src放在onload之后
【解决方案2】:

jQuery 的 $.getScript() 有时会出错,所以我使用我自己的实现,例如:

jQuery.loadScript = function (url, callback) {
    jQuery.ajax({
        url: url,
        dataType: 'script',
        success: callback,
        async: true
    });
}

并像这样使用它:

if (typeof someObject == 'undefined') $.loadScript('url_to_someScript.js', function(){
    //Stuff to do after someScript has loaded
});

【讨论】:

  • 我稍微调整了你的脚本,让它在加载时执行,否则加载然后执行... jQuery.pluginSafe = function (name, url, callback) { if(jQuery[name]){ callback; } else { jQuery.ajax({...}); } }
  • 你能提供一些关于什么时候出现问题的信息吗?
  • 这并不理想,因为这样加载的文件没有显示在 DevTools 的 Sources 中。因为这个文件是evaled
  • 另一个问题是这会吞下任何语法错误。所以你想在fail() 中抓住他们。
【解决方案3】:

我需要经常这样做,所以我用这个:

var loadJS = function(url, implementationCode, location){
    //url is URL of external file, implementationCode is the code
    //to be called from the file, location is the location to 
    //insert the <script> element

    var scriptTag = document.createElement('script');
    scriptTag.src = url;

    scriptTag.onload = implementationCode;
    scriptTag.onreadystatechange = implementationCode;

    location.appendChild(scriptTag);
};
var yourCodeToBeCalled = function(){
//your code goes here
}
loadJS('yourcode.js', yourCodeToBeCalled, document.body);

更多信息请看本站How do I include a JavaScript file in another JavaScript file?,这是我的函数思路的来源。

【讨论】:

  • 赞成包括onload
  • 这段代码很棒。只需很少的修改即可使其在 chrome/firefox/opera 中完全正常运行。我用 6 行加载 markdown 脚本的 html 编写了自己的 markdown 重写器。对于内容,我添加带有降价的
  • 再做一些工作,我将所有 html 减少到 3 行。带有内容的
  • == 你好 ==
【解决方案4】:

您可以在页面内动态加载 js 而不是另一个 js 文件。

你必须使用getScript来加载js文件。

$.getScript("ajax/test.js", function(data, textStatus, jqxhr) {
  console.log(data); // data returned
  console.log(textStatus); // success
  console.log(jqxhr.status); // 200
  console.log('Load was performed.');
});

【讨论】:

  • 这是一个优雅的解决方案,很容易工作。它也可以很好地嵌套在其他函数中。强烈推荐这个选项。
  • 我不喜欢使用 jQuery。我需要在普通的旧 JS 中做到这一点
【解决方案5】:

亡灵术。

我用它来加载依赖脚本;
它适用于 IE8+,而无需添加对 jQuery 等其他库的任何依赖!

var cScriptLoader = (function ()
{
    function cScriptLoader(files)
    {
        var _this = this;
        this.log = function (t)
        {
            console.log("ScriptLoader: " + t);
        };
        this.withNoCache = function (filename)
        {
            if (filename.indexOf("?") === -1)
                filename += "?no_cache=" + new Date().getTime();
            else
                filename += "&no_cache=" + new Date().getTime();
            return filename;
        };
        this.loadStyle = function (filename)
        {
            // HTMLLinkElement
            var link = document.createElement("link");
            link.rel = "stylesheet";
            link.type = "text/css";
            link.href = _this.withNoCache(filename);
            _this.log('Loading style ' + filename);
            link.onload = function ()
            {
                _this.log('Loaded style "' + filename + '".');
            };
            link.onerror = function ()
            {
                _this.log('Error loading style "' + filename + '".');
            };
            _this.m_head.appendChild(link);
        };
        this.loadScript = function (i)
        {
            var script = document.createElement('script');
            script.type = 'text/javascript';
            script.src = _this.withNoCache(_this.m_js_files[i]);
            var loadNextScript = function ()
            {
                if (i + 1 < _this.m_js_files.length)
                {
                    _this.loadScript(i + 1);
                }
            };
            script.onload = function ()
            {
                _this.log('Loaded script "' + _this.m_js_files[i] + '".');
                loadNextScript();
            };
            script.onerror = function ()
            {
                _this.log('Error loading script "' + _this.m_js_files[i] + '".');
                loadNextScript();
            };
            _this.log('Loading script "' + _this.m_js_files[i] + '".');
            _this.m_head.appendChild(script);
        };
        this.loadFiles = function ()
        {
            // this.log(this.m_css_files);
            // this.log(this.m_js_files);
            for (var i = 0; i < _this.m_css_files.length; ++i)
                _this.loadStyle(_this.m_css_files[i]);
            _this.loadScript(0);
        };
        this.m_js_files = [];
        this.m_css_files = [];
        this.m_head = document.getElementsByTagName("head")[0];
        // this.m_head = document.head; // IE9+ only
        function endsWith(str, suffix)
        {
            if (str === null || suffix === null)
                return false;
            return str.indexOf(suffix, str.length - suffix.length) !== -1;
        }
        for (var i = 0; i < files.length; ++i)
        {
            if (endsWith(files[i], ".css"))
            {
                this.m_css_files.push(files[i]);
            }
            else if (endsWith(files[i], ".js"))
            {
                this.m_js_files.push(files[i]);
            }
            else
                this.log('Error unknown filetype "' + files[i] + '".');
        }
    }
    return cScriptLoader;
})();
var ScriptLoader = new cScriptLoader(["foo.css", "Scripts/Script4.js", "foobar.css", "Scripts/Script1.js", "Scripts/Script2.js", "Scripts/Script3.js"]);
ScriptLoader.loadFiles();

如果您对用于创建此内容的typescript-version 感兴趣:

class cScriptLoader {
    private m_js_files: string[];
    private m_css_files: string[];
    private m_head:HTMLHeadElement;
    
    private log = (t:any) =>
    {
        console.log("ScriptLoader: " + t);
    }
    
    
    constructor(files: string[]) {
        this.m_js_files = [];
        this.m_css_files = [];
        this.m_head = document.getElementsByTagName("head")[0];
        // this.m_head = document.head; // IE9+ only
        
        
        function endsWith(str:string, suffix:string):boolean 
        {
            if(str === null || suffix === null)
                return false;
                
            return str.indexOf(suffix, str.length - suffix.length) !== -1;
        }
        
        
        for(let i:number = 0; i < files.length; ++i) 
        {
            if(endsWith(files[i], ".css"))
            {
                this.m_css_files.push(files[i]);
            }
            else if(endsWith(files[i], ".js"))
            {
                this.m_js_files.push(files[i]);
            }
            else
                this.log('Error unknown filetype "' + files[i] +'".');
        }
        
    }
    
    
    public withNoCache = (filename:string):string =>
    {
        if(filename.indexOf("?") === -1)
            filename += "?no_cache=" + new Date().getTime();
        else
            filename += "&no_cache=" + new Date().getTime();
            
        return filename;    
    }
    

    public loadStyle = (filename:string) =>
    {
        // HTMLLinkElement
        let link = document.createElement("link");
        link.rel = "stylesheet";
        link.type = "text/css";
        link.href = this.withNoCache(filename);
        
        this.log('Loading style ' + filename);
        link.onload = () =>
        {
            this.log('Loaded style "' + filename + '".');
            
        };
        
        link.onerror = () =>
        {
            this.log('Error loading style "' + filename + '".');
        };
        
        this.m_head.appendChild(link);
    }
    
    
    public loadScript = (i:number) => 
    {
        let script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = this.withNoCache(this.m_js_files[i]);
        
        var loadNextScript = () => 
        {
            if (i + 1 < this.m_js_files.length)
            {
                this.loadScript(i + 1);
            }
        }
        
        script.onload = () =>
        {
            this.log('Loaded script "' + this.m_js_files[i] + '".');
            loadNextScript();
        };
        
        
        script.onerror = () =>
        {
            this.log('Error loading script "' + this.m_js_files[i] + '".');
            loadNextScript();
        };
        
        
        this.log('Loading script "' + this.m_js_files[i] + '".');
        this.m_head.appendChild(script);
    }
    
    public loadFiles = () => 
    {
        // this.log(this.m_css_files);
        // this.log(this.m_js_files);
        
        for(let i:number = 0; i < this.m_css_files.length; ++i)
            this.loadStyle(this.m_css_files[i])
        
        this.loadScript(0);
    }
    
}


var ScriptLoader = new cScriptLoader(["foo.css", "Scripts/Script4.js", "foobar.css", "Scripts/Script1.js", "Scripts/Script2.js", "Scripts/Script3.js"]);
ScriptLoader.loadFiles();

如果是加载脚本的动态列表,将脚本写入一个属性,例如data-main,e.g. &lt;script src="scriptloader.js" data-main="file1.js,file2.js,file3.js,etc." &gt;&lt;/script&gt;
并做一个element.getAttribute("data-main").split(',')

比如

var target = document.currentScript || (function() {
  var scripts = document.getElementsByTagName('script');
  // Note: this is for IE as IE doesn't support currentScript
  // this does not work if you have deferred loading with async
  // e.g. <script src="..." async="async" ></script>
  // https://web.archive.org/web/20180618155601/https://www.w3schools.com/TAgs/att_script_async.asp
  return scripts[scripts.length - 1];
})();

target.getAttribute("data-main").split(',')

获取列表。

【讨论】:

  • 谢谢,这太不可思议了。我认为值得添加回调选项,因为我们可能希望在加载结束时基于这些资源执行函数。
  • 你为什么在打字稿代码中使用var
  • @canbax:旧版本的 TS 没有拒绝 var - 旧习惯很难改掉。
【解决方案6】:

jQuery.getScript()方法是Ajax函数的简写(带有dataType属性:$.ajax({ url: url,dataType: "script"})

如果您希望脚本可缓存,请使用RequireJS 或按照jQuery 的示例扩展jQuery.getScript 方法,类似于以下内容。

jQuery.cachedScript = function( url, options ) {

  // Allow user to set any option except for dataType, cache, and url
  options = $.extend( options || {}, {
    dataType: "script",
    cache: true,
    url: url
  });

  // Use $.ajax() since it is more flexible than $.getScript
  // Return the jqXHR object so we can chain callbacks
  return jQuery.ajax( options );
};

// Usage
$.cachedScript( "ajax/test.js" ).done(function( script, textStatus ) {
  console.log( textStatus );
});

参考:jQuery.getScript() | jQuery API Documentation

【讨论】:

    【解决方案7】:

    jQuery 有$.getScript():

    说明:使用 GET HTTP 请求从服务器加载一个 JavaScript 文件,然后执行它。

    【讨论】:

      【解决方案8】:

      您可以使用 JQuery 来完成:

      $.getScript("ajax/test.js", function(data, textStatus, jqxhr) {
        console.log(data); //data returned
        console.log(textStatus); //success
        console.log(jqxhr.status); //200
        console.log('Load was performed.');
      });
      

      此链接应该会有所帮助: http://api.jquery.com/jQuery.getScript/

      【讨论】:

        【解决方案9】:

        我建议将 requirejs 与 AMD javascript 类文件一起使用

        如何在这里使用它的好例子

        http://www.sitepoint.com/understanding-requirejs-for-effective-javascript-module-loading/

        【讨论】:

          【解决方案10】:

          要创作我的插件,我需要在 JS 文件中加载外部脚本和样式,所有这些都是预定义的。为此,我做了以下工作:

              this.loadRequiredFiles = function (callback) {
                  var scripts = ['xx.js', 'yy.js'];
                  var styles = ['zz.css'];
                  var filesloaded = 0;
                  var filestoload = scripts.length + styles.length;
                  for (var i = 0; i < scripts.length; i++) {
                      log('Loading script ' + scripts[i]);
                      var script = document.createElement('script');
                      script.type = 'text/javascript';
                      script.src = scripts[i];
                      script.onload = function () {
                          log('Loaded script');
                          log(this);
                          filesloaded++;  // (This means increment, i.e. add one)
                          finishLoad();
                      };
                      document.head.appendChild(script);
                  }
                  for (var i = 0; i < styles.length; i++) {
                      log('Loading style ' + styles[i]);
                      var style = document.createElement('link');
                      style.rel = 'stylesheet';
                      style.href = styles[i];
                      style.type = 'text/css';
                      style.onload = function () {
                          log('Loaded style');
                          log(this);
                          filesloaded++;
                          finishLoad();
                      };
                      document.head.appendChild(style);
                  }
                  function finishLoad() {
                      if (filesloaded === filestoload) {
                          callback();
                      }
                  }
              };
          

          上下文中的更多脚本:

          function myPlugin() {
          
              var opts = {
                  verbose: false
              };                          ///< The options required to run this function
              var self = this;            ///< An alias to 'this' in case we're in jQuery                         ///< Constants required for this function to work
          
              this.getOptions = function() {
                  return opts;
              };
          
              this.setOptions = function(options) {
                  for (var x in options) {
                      opts[x] = options[x];
                  }
              };
          
              /**
               * @brief Load the required files for this plugin
               * @param {Function} callback A callback function to run when all files have been loaded
               */
              this.loadRequiredFiles = function (callback) {
                  var scripts = ['xx.js', 'yy.js'];
                  var styles = ['zz.css'];
                  var filesloaded = 0;
                  var filestoload = scripts.length + styles.length;
                  for (var i = 0; i < scripts.length; i++) {
                      log('Loading script ' + scripts[i]);
                      var script = document.createElement('script');
                      script.type = 'text/javascript';
                      script.src = scripts[i];
                      script.onload = function () {
                          log('Loaded script');
                          log(this);
                          filesloaded++;
                          finishLoad();
                      };
                      document.head.appendChild(script);
                  }
                  for (var i = 0; i < styles.length; i++) {
                      log('Loading style ' + styles[i]);
                      var style = document.createElement('link');
                      style.rel = 'stylesheet';
                      style.href = styles[i];
                      style.type = 'text/css';
                      style.onload = function () {
                          log('Loaded style');
                          log(this);
                          filesloaded++;
                          finishLoad();
                      };
                      document.head.appendChild(style);
                  }
                  function finishLoad() {
                      if (filesloaded === filestoload) {
                          callback();
                      }
                  }
              };
          
              /**
               * @brief Enable user-controlled logging within this function
               * @param {String} msg The message to log
               * @param {Boolean} force True to log message even if user has set logging to false
               */
              function log(msg, force) {
                  if (opts.verbose || force) {
                      console.log(msg);
                  }
              }
          
              /**
               * @brief Initialise this function
               */
              this.init = function() {
                  self.loadRequiredFiles(self.afterLoadRequiredFiles);
              };
          
              this.afterLoadRequiredFiles = function () {
                  // Do stuff
              };
          
          }
          

          【讨论】:

            【解决方案11】:

            这是一个动态加载 javascript 和 CSS 文件的小库:

            https://github.com/todotresde/javascript-loader

            我想按顺序动态加载css和js文件很有用。

            支持扩展以加载您想要的任何库,而不仅仅是主文件,您可以使用它来加载自定义文件。

            IE:

            <html>
            <head>
                <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
                <script src="scripts/javascript-loader.js" type="text/javascript" charset="utf-8" ></script>    
                <script type="text/javascript">
                    $(function() {
            
                        registerLib("threejs", test);
            
                        function test(){
                            console.log(THREE);
                        }
            
                        registerLib("tinymce", draw);
            
                        function draw(){
                            tinymce.init({selector:'textarea'});
                        }
            
                    }); 
                </script>
            </head>
            <body>
                <textarea>Your content here.</textarea>
            </body>
            

            【讨论】:

              【解决方案12】:

              如果您有 许多文件 具有 依赖项,请使用 AMD/RequireJS。 http://requirejs.org/

              【讨论】:

                猜你喜欢
                • 2016-09-26
                • 1970-01-01
                • 2015-10-05
                • 2016-05-11
                • 1970-01-01
                • 1970-01-01
                • 2012-11-29
                相关资源
                最近更新 更多