在 JS 中动态加载 JS

IT技术 javascript jquery
2021-01-12 19:31:41

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

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

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

jQuery 中的解决方案也可以

6个回答

我的猜测是,在您的 DOM-only 解决方案中,您做了类似的事情:

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
@AliSharabiani oop,你说得对,只有元素已经在页面上才重要。根据我的经验,在设置 之前首先在页面上拥有元素更为常见src,主要是在您想要动态更改所有情况下src,例如img标签等。所以我认为更好的做法是习惯src之后onload
2021-03-24 19:31:41
没有必要把事情复杂化。布拉沃
2021-03-25 19:31:41
@woojoo666 为什么之后onload是不是src设置之前就appendchild足够了?
2021-03-30 19:31:41
这真的应该是最好的答案,不需要使用 jQuery 来完成这样的简单任务!
2021-04-06 19:31:41
确保srconload属性之后设置属性
2021-04-06 19:31:41

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
});
你能提供一些关于什么时候有问题的信息吗?
2021-03-14 19:31:41
这并不理想,因为这样加载的文件未显示在 DevTools 的 Sources 中。这是因为这个文件被eval编辑了
2021-03-23 19:31:41
另一个问题是这会吞掉任何语法错误。所以你想抓住他们fail()
2021-04-03 19:31:41
我稍微调整了你的脚本,让它在加载时执行,否则加载然后执行... jQuery.pluginSafe = function (name, url, callback) { if(jQuery[name]){ callback; } else { jQuery.ajax({...}); } }
2021-04-05 19:31:41

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

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);

有关详细信息,请参阅此站点如何在另一个 JavaScript 文件中包含 JavaScript 文件?,这就是我的函数思想的来源。

这段代码很棒。只需很少的修改即可使其在 chrome/firefox/opera 中完全发挥作用。我用 6 行 html 编写了自己的 Markdown 重写器,它加载了 Markdown 脚本。对于内容,我添加了带有 Markdown 的 <template> 标签。重写器将转换 Markdown 的结果附加到 HTML。简直美极了。谢谢你。
2021-03-11 19:31:41
做更多的工作,我将所有的 html 减少到 3 行。带有内容的 <template> 标签被转换和附加。比我之前的任何努力都要好。
2021-03-14 19:31:41
<!DOCTYPE html> <html lang="en"><head><meta charset="utf-8" /></head><body> <nav></nav> <template class="markdown"> = = hello == </template> <template id="Spanish" class="markdown"> == hola == </template> </body><script type="text/javascript" src="/js/rewrite .js"></script> </html>
2021-03-16 19:31:41
赞成包括onload.
2021-04-01 19:31:41

您可以在页面内动态加载 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 中执行此操作
2021-03-11 19:31:41
这是一个优雅的解决方案,很容易工作。它也可以很好地嵌套在其他函数中。强烈推荐这个选项。
2021-03-31 19:31:41

死灵法术。

我用它来加载依赖脚本;
它适用于 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,eg <script src="scriptloader.js" data-main="file1.js,file2.js,file3.js,etc." ></script>
并做一个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(',')

以获取列表。

@canbax:旧版本的 TS 没有拒绝 var - 旧习惯很难改掉。
2021-03-21 19:31:41
谢谢,太不可思议了。我认为值得添加回调选项,因为我们可能希望在加载结束时根据这些资源执行函数。
2021-03-24 19:31:41
你为什么var在typescript代码中使用?
2021-03-25 19:31:41