动态加载JavaScript文件
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态加载JavaScript文件相关的知识,希望对你有一定的参考价值。
如何可靠地动态加载javascript文件?这将用于实现一个模块或组件,当'初始化'时,组件将按需动态加载所有需要的JavaScript库脚本。
使用该组件的客户端不需要加载实现此组件的所有库脚本文件(并手动将<script>
标记插入其网页) - 只需要“主”组件脚本文件。
主流JavaScript库如何实现这一点(Prototype,jQuery等)?这些工具是否将多个JavaScript文件合并为一个可再发行的“构建”版本的脚本文件?或者他们是否动态加载辅助“库”脚本?
这个问题的补充:有没有办法在加载动态包含的JavaScript文件后处理事件?原型有document.observe
用于文档范围的事件。例:
document.observe("dom:loaded", function() {
// initially hide all containers for tab content
$$('div.tabcontent').invoke('hide');
});
脚本元素有哪些可用事件?
您可以编写动态脚本标记(使用Prototype):
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);
}
};
刚刚发现了YUI 3的一个很棒的功能(在预览版中可用时)。您可以轻松地将依赖项插入YUI库和“外部”模块(您正在寻找的),而无需太多代码:YUI Loader。
它还会在加载外部模块后立即回答有关正在调用的函数的第二个问题。
例:
YUI({
modules: {
'simple': {
fullpath: "http://example.com/public/js/simple.js"
},
'complicated': {
fullpath: "http://example.com/public/js/complicated.js"
requires: ['simple'] // <-- dependency to 'simple' module
}
},
timeout: 10000
}).use('complicated', function(Y, result) {
// called as soon as 'complicated' is loaded
if (!result.success) {
// loading failed, or timeout
handleError(result.msg);
} else {
// call a function that needs 'complicated'
doSomethingComplicated(...);
}
});
完美地为我工作,并具有管理依赖关系的优势。有关example with YUI 2 calendar的信息,请参阅YUI文档。
如果要加载SYNC脚本,则需要将脚本文本直接添加到html HEAD标记。添加它将触发ASYNC加载。要同步从外部文件加载脚本文本,请使用XHR。下面是一个快速示例(它正在使用此帖和其他帖子中的其他部分答案):
/*sample requires an additional method for array prototype:*/
if (Array.prototype.contains === undefined) {
Array.prototype.contains = function (obj) {
var i = this.length;
while (i--) { if (this[i] === obj) return true; }
return false;
};
};
/*define object that will wrap our logic*/
var ScriptLoader = {
LoadedFiles: [],
LoadFile: function (url) {
var self = this;
if (this.LoadedFiles.contains(url)) return;
var xhr = new XMLHttpRequest();
xhr.onload = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
self.LoadedFiles.push(url);
self.AddScript(xhr.responseText);
} else {
if (console) console.error(xhr.statusText);
}
}
};
xhr.open("GET", url, false);/*last parameter defines if call is async or not*/
xhr.send(null);
},
AddScript: function (code) {
var oNew = document.createElement("script");
oNew.type = "text/javascript";
oNew.textContent = code;
document.getElementsByTagName("head")[0].appendChild(oNew);
}
};
/*Load script file. ScriptLoader will check if you try to load a file that has already been loaded (this check might be better, but I'm lazy).*/
ScriptLoader.LoadFile("Scripts/jquery-2.0.1.min.js");
ScriptLoader.LoadFile("Scripts/jquery-2.0.1.min.js");
/*this will be executed right after upper lines. It requires jquery to execute. It requires a HTML input with id "tb1"*/
$(function () { alert($('#tb1').val()); });
我们在工作中使用的技术是使用AJAX请求请求javascript文件,然后使用eval()返回。如果您正在使用原型库,则它们在Ajax.Request调用中支持此功能。
jquery用它的.append()函数解决了这个问题 - 用它来加载完整的jquery ui包
/*
* FILENAME : project.library.js
* USAGE : loads any javascript library
*/
var dirPath = "../js/";
var library = ["functions.js","swfobject.js","jquery.jeditable.mini.js","jquery-ui-1.8.8.custom.min.js","ui/jquery.ui.core.min.js","ui/jquery.ui.widget.min.js","ui/jquery.ui.position.min.js","ui/jquery.ui.button.min.js","ui/jquery.ui.mouse.min.js","ui/jquery.ui.dialog.min.js","ui/jquery.effects.core.min.js","ui/jquery.effects.blind.min.js","ui/jquery.effects.fade.min.js","ui/jquery.effects.slide.min.js","ui/jquery.effects.transfer.min.js"];
for(var script in library){
$('head').append('<script type="text/javascript" src="' + dirPath + library[script] + '"></script>');
}
要使用 - 在导入jquery.js之后在你的html / php / etc的头部,你只需要包含这样一个文件就可以加载到你的库的整个库中...
<script type="text/javascript" src="project.library.js"></script>
保持简洁,简洁,可维护! :]
// 3rd party plugins / script (don't forget the full path is necessary)
var FULL_PATH = '', s =
[
FULL_PATH + 'plugins/script.js' // Script example
FULL_PATH + 'plugins/jquery.1.2.js', // jQuery Library
FULL_PATH + 'plugins/crypto-js/hmac-sha1.js', // CryptoJS
FULL_PATH + 'plugins/crypto-js/enc-base64-min.js' // CryptoJS
];
function load(url)
{
var ajax = new XMLHttpRequest();
ajax.open('GET', url, false);
ajax.onreadystatechange = function ()
{
var script = ajax.response || ajax.responseText;
if (ajax.readyState === 4)
{
switch(ajax.status)
{
case 200:
eval.apply( window, [script] );
console.log("library loaded: ", url);
break;
default:
console.log("ERROR: library not loaded: ", url);
}
}
};
ajax.send(null);
}
// initialize a single load
load('plugins/script.js');
// initialize a full load of scripts
if (s.length > 0)
{
for (i = 0; i < s.length; i++)
{
load(s[i]);
}
}
此代码只是一个简短的功能示例,可能需要额外的功能,以便在任何(或给定)平台上提供全面支持。
有一个新的ECMA标准叫做dynamic import,最近被整合到Chrome和Safari中。
const moduleSpecifier = './dir/someModule.js';
import(moduleSpecifier)
.then(someModule => someModule.foo()); // executes foo method in someModule
有专门为此目的而设计的脚本。
yepnope.js内置于Modernizr,lab.js是一个更优化(但不太用户友好的版本)。
我不会建议通过像jquery或prototype这样的大型库来实现这一点 - 因为脚本加载器的一个主要好处是能够尽早加载脚本 - 你不必等到jquery和你所有的dom元素加载之前运行检查以查看是否要动态加载脚本。
我编写了一个简单的模块,可以自动执行在JavaScript中导入/包含模块脚本的工作。试一试,请多给一些反馈! :)有关代码的详细说明,请参阅此博客文章:http://stamat.wordpress.c 以上是关于动态加载JavaScript文件的主要内容,如果未能解决你的问题,请参考以下文章 thymeleaf 片段渲染后重新加载 javascript