Load jQuery in a js, then execute a script that depends on it
I have a unique issue -
I am designing a web application that creates widgets that a user can then embed in their own page (blog posts, mostly). I want them to just have to embed one line, so I just had that line be an include statement, to pull a Javascript off my server.
The problem is, I am building the widget code using jQuery, and I need to load the jQuery plugin, since I obviously don't know whether or not my users will have it available. I thought 'this should be pretty simple'....
function includeJavaScript(jsFile) {
var script = document.createElement('script');
script.src = jsFile;
script.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(script);
}
includeJavaScript('http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js');
jQuery();
So, I am appending the jQuery file to the head, then afterwards, trying to run a jQuery function. Trouble is, this doesn't work! Everytime I run it, I get the error that variable jQuery is not defined. I have tried a few things. I tried putting the jQuery functions in an onLoad t开发者_开发技巧rigger, so that the whole page (including, presumably, the jQuery file) would load before it called my script. I tried putting the jQuery function in a seperate file, and loading it after loading the jQuery lib file. But I get the idea I'm missing something simple - I'm new to jQuery, so if I'm missing something obvious, I apologize...
EDIT
OK,I tried the suggestion offered by digitalFresh, as follows (using Safari 5, if that helps), but I still get the same error?
function test() {
jQuery()
}
var script = document.createElement("script");
script.type = "text/javascript";
script.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js';
script.onload = test(); //execute
document.body.appendChild(script);
EDIT
OK, I FINALLY got it to work, in an offhand suggestion from Brendan, by putting the call ITSELF in an 'onload' handler, like so:
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
addLoadEvent( function() {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js';
document.body.appendChild(script);
jQuery();
});
At this point, as you can see, I don't even have to put it in an 'onload' - it just works. Though I have to admit, I still don't understand WHY it works, which bothers me...
The solution you end up using works but slow to start, and not 100% fail proof. If someone rewrites window.onload your code will not run. Also window.onload happens when all the content on the page is loaded (including images) which is not exactly what you want. You don't want your script to wait that long.
Fortunately <script> elements have their own onload (ready) event, which can be used to couple other scripts with them.
function include(file, callback) {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = file;
script.onload = script.onreadystatechange = function() {
// execute dependent code
if (callback) callback();
// prevent memory leak in IE
head.removeChild(script);
script.onload = null;
};
head.appendChild(script);
}
include('http://ajax.googleapis.com/.../jquery.min.js', myFunction);
In this case the function will be called exactly when jquery is available. Your code is fail proof and starts quickly.
The script is not loaded or executed when you call the jQuery function. Thats why you get the error that jQuery is not defined.
I answered this problem on Loading Scripts Dynamically. The script is simple for all browsers except IE. Just add an onload event listener
You should first check to make sure they do not already use jquery so something like:
if (jQuery) {
// jQuery is loaded
} else {
// jQuery is not loaded
}
Secondly, you should make sure you use jQuery in no conflict mode and do not use the $ operator as it may be claimed by another script library.
Then to embed, declare this function:
function load_script (url)
{
var xmlhttp;
try {
// Mozilla / Safari / IE7
xmlhttp = new XMLHttpRequest();
} catch (e) {
//Other IE
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
}
xmlhttp.open('GET', url, false); x.send('');
eval(xmlhttp.responseText);
var s = xmlhttp.responseText.split(/\n/);
var r = /^function\s*([a-z_]+)/i;
for (var i = 0; i < s.length; i++)
{
var m = r.exec(s[i]);
if (m != null)
window[m[1]] = eval(m[1]);
}
}
Then call it:
load_script('http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js');
Hope this helps.
Use LABjs. Embedding <script>
tags work because the browser loads and executes whatever script in it or referenced by it upon seeing any of them, but that also means the browser will block until it is done with the script.
If you're using jQuery, you can use getScript(). Facebook has a good example on how to employ this. This is a more manageable solution to the original one I posted below.
Alternatively:
Building off of galambalazs's answer you can wrap his include()
function in an event like the jQuery $(document).ready()
to create deferred scripts with a dependency line without having to rely on an extra JS plugin. I also added a callbackOnError, which is handy if you're fetching from Google CDN.
/* galambalazs's include() */
function include(file, callback, callbackOnError) {
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = file;
script.onload = script.onreadystatechange = function() {
// execute dependent code
if (callback) callback();
// prevent memory leak in IE
head.removeChild(script);
script.onload = null;
script.onerror = null;
};
script.onerror = function() {
if(callbackOnError) callbackOnError();
// prevent memory leak in IE
head.removeChild(script);
script.onload = null;
script.onerror = null;
};
head.appendChild(script);
}
/* If you need a deferred inline script, this will work */
function init() {
// Insert Code
}
/* Example with callback */
$(document).ready(function() {
include('something.js', init);
});
/* Maybe I want something on window.load() */
$(window).load(function() {
// Without a callback
include('whatever.js');
});
/* Or use an event to load and initialize script when it's needed */
$(".nearAButton").hover(include('button.js',function() {initButtonJS()}));
function initButtonJS() {
$(".nearAButton").off("mouseenter mouseleave");
}
/* Attempt to load Google Code, on fail load local */
include(
'//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/jquery-ui.min.js',
function () {
// Inline Callback
},
function () {
include('/local/jquery-ui-1.10.3.custom.min.js', function () {
// Inline Callback
});
}
);
精彩评论