Как эффективно использовать yepnope.js с $(document).ready()?
Я выполняю загрузчик скриптов yepnope как часть библиотеки modernizr.js. Я успешно получил jQuery для загрузки и jQuery-зависимые сценарии впоследствии. Я новичок в асинхронной загрузке ресурсов, так что это немного ново для меня. Я искал вокруг, но мне не повезло со следующим.
Мой вопрос: что вы думаете о том, как эффективно заменить функциональность $(document).ready() при работе с фреймворком yepnope.js?
Моя теория состояла в том, чтобы создать функцию с соответствующим именем в моей базовой библиотеке, а затем установить эту переменную на моих страницах в анонимную функцию, содержащую мой существующий код $(document).ready(). Эта переменная затем будет вызвана yepnope после того, как все сценарии были загружены в полный обратный вызов.
Согласитесь ли вы, что это хороший способ сделать это, или я подхожу к этому совершенно неправильно?
(Для тех, кто не знает, асинхронный характер yepnope.js означает, что документ вызывает $ или jQuery до того, как загрузчик yepnope завершил работу, выдавая ошибку "$ is undefined" <- исправьте меня, если это не так.)
Первый вопрос, надеюсь, он хороший.
5 ответов
Если загрузка jQuery без yepnope не является для вас проблемой, есть более простой способ сделать это.
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script>
$.holdReady(true);
yepnope.load({
load: [
'placeholder.js',
'jquery-ui.min.js'
],
complete: function (){
$.holdReady(false);
}
});
</script>
Это техника, которую я использую. Это позволяет мне посылать вызовы в стиле $(document).ready() куда угодно. Используя этот метод, вы можете взять сайт, который уже использует jQuery и имеет существующие вызовы $(document).ready(), и легко модифицировать yepnope.
Во-первых, добавьте эту строку JS, предпочтительно в заголовок документа, перед любым JavaScript, который вызывает $(document).ready():
<script>
var docready=[],$=function(o){function r(fn){docready.push(fn);}if(typeof o === 'function') r(o);return{ready: r}};
</script>
Затем установите тестовый объект yepnope jQuery, подобный следующему:
yepnope({
load: '//ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js',
complete: function() {
$ = jQuery;
for(n in docready) $(document).ready(docready[n]);
}
});
Мы создаем фальшивый $(document).ready() перед загрузкой jQuery. Это сохраняет каждый вызов $(document).ready() в массиве docready. Затем, после загрузки jQuery, мы перезаписываем наш временный объект $ теперь загруженным реальным объектом jQuery. Затем мы перебираем все сохраненные вызовы $(document).ready() и выполняем их по-настоящему.
ОБНОВЛЕНО: улучшенная версия от Криса Джонса, которая также охватывает вызовы стиля $(function() {}).
Теги скрипта загружаются синхронно - поэтому, если вы поместите свой yepnope в файл js и загрузите его через тег скрипта:
<script type="text/javascript" src="/my-yepnope-stuff.js"></script>
</body>
прямо перед закрывающим тегом body вы можете быть в состоянии $(document).ready().
Что вам нужно для себя ответить, так это то, имеет ли смысл принудительно загружать yepnope в виде $(document).ready(), поскольку его главная цель - в первую очередь нарушить порядок синхронной загрузки тегов скрипта.
Я думаю, что решение Алекса Секстона будет правильным:
yepnope({
load: '//ajax.googleapisOFFLINE.com/ajaxX/libs/jquery/1.7.1/jquery.min.js',
callback: function () {
if (!window.jQuery) {
yepnope('/js/jquery-1.7.1.min.js');
}
},
complete: function () {
$(function(){
$("div.whatever").css("color","red");
});
}
});
Используя руководство @ezmilhouse, я подумал о том, как лучше всего достичь того, чего я достиг, при этом сохраняя совместимость с нашим старым кодом.
Мое решение состояло в том, чтобы настроить загрузчик сценариев yepnope для загрузки всех необходимых сценариев в иерархическом порядке, исходя из их индивидуальных зависимостей. После загрузки всех сценариев вы можете использовать complete
свойство моего вызова в yepnope для вызова моей функции готовности. Это означало, что документ был фактически готов и код работал бы без проблем.
Я также переместил мои js в базу своих страниц (то, что я должен был сделать давным-давно, но у нас было много старых страниц!:))
Вот пример (использование ложных имен libray/script только для иллюстрации):
yepnope({
test: baseLib.debug,
yep: { "max": "/version2/res/jquery/jquery-1.5.2.js" },
nope: { "min": "/version2/res/jquery/jquery-1.5.2.min.js" },
callback: {
"max": function (url, result, key) {
baseLib.Log("jQuery full loaded.");
},
"min": function (url, result, key) {
baseLib.Log("jQuery min loaded.");
}
},
complete: function () {
if (window.$) {
yepnope({
test: base.debug,
yep: {
"anotherscript": "script/url/here.js",
"anotherscript2": "script/url/here2.js"
},
nope: {
"anotherscript": "script/url/here-min.js",
"anotherscript2": "script/url/here2-min.js"
},
both: {
"anotherscript3": "script/url/here3.js"
},
callback: {
"anotherscript": function (url, result, key) {
baseLib.Log("anotherscript " + (result ? "Max" : "Min") + " loaded.");
},
"anotherscript2": function (url, result, key) {
baseLib.Log("anotherscript2 " + (result ? "Max" : "Min") + " loaded.");
},
"anotherscript3": function (url, result, key) {
baseLib.Log("anotherscript3 loaded.");
}
},
complete: function () {
baseLib.Log("Scripts Loaded");
baseLib.Page.Ready();
}
});
}
else {
baseLib.Log("Could not load jQuery. No further jQuery dependent files loaded.", "error");
}
}
});
На моей странице JS я назначу функцию baseLib.Page.Ready
это тогда будет вызвано yepnope по завершению.