#javascript #jquery #jquery-ui #prototypejs #conflict
#javascript #jquery #jquery-пользовательский интерфейс #prototypejs #конфликт
Вопрос:
Я предоставляю виджет Javascript другим сайтам, и мое использование Jquery в виджете, похоже, противоречит использованию Prototype на хост-сайте.
Вы можете увидеть конфликт в действии здесь: http://www.phillyrealestateadvocate.idxco.com/idx/8572/results.php?lp=100000amp;hp=500000amp;sqFt=0amp;bd=2amp;ba=0amp;searchSubmit=amp;city[]=131
В правой части страницы нажмите на зеленую кнопку «Задать вопрос» — появится всплывающее окно, и как только вы откроете всплывающее окно, в консоль JS начнут поступать ошибки «недопустимая длина массива» (и не останавливаются.) Затем всплывающее окно не может быть закрыто, но его все еще можно перетащить. Код / содержимое во всплывающем окне находится в iframe, поэтому он по-прежнему работает нормально, но всплывающее окно просто не закрывается.
Ошибка, которую выдает Firebug, такова: invalid array length
в Prototype.js , но когда я расширяю это для получения подробной информации, в нем есть ссылки на jquery.min.js , так что это привело меня к мысли, что эти два понятия противоречат друг другу.
Мой код виджета полностью находится в анонимной функции и загружает Jquery, используя модель, описанную здесь Алексом Марандоном: http://alexmarandon.com/articles/web_widget_jquery /
Я использую вызов noConflict, но, возможно, он работает не так, как я его разместил?
Вот начало моего скрипта виджета, который содержит ссылки на jquery.min.js и jqueryui:
(function() {
// Localize jQuery variable
var jQuery;
/******** Load jQuery if not present *********/
if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.6.2')
{
var script_tag = document.createElement('script');
script_tag.setAttribute("type","text/javascript");
script_tag.setAttribute("src",
"http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js");
script_tag.onload = scriptLoadHandler;
script_tag.onreadystatechange = function () { // Same thing but for IE
if (this.readyState == 'complete' || this.readyState == 'loaded') {
scriptLoadHandler();
}
};
// Try to find the head, otherwise default to the documentElement
(document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
}
else
{
$.getScript( "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js" ,
function()
{
// The jQuery version on the window is the one we want to use
jQuery = window.jQuery;
main();
}
);
}
/******** Called once jQuery has loaded ******/
function scriptLoadHandler()
{
$.getScript( "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js" ,
function()
{
// Restore $ and window.jQuery to their previous values and store the
// new jQuery in our local jQuery variable
jQuery = window.jQuery.noConflict(true);
main();
}
);
}
/******** Our main function ********/
function main()
{
// Do a bunch of stuff here
}
})(); // We call our anonymous function immediately
Любая помощь будет высоко оценена!
Редактировать: теперь у меня есть пользовательский интерфейс Jquery непосредственно в виджете, поэтому я полностью исключил вызовы getScript. К сожалению, это не устранило конфликт. Вот новый код:
(function() {
// Localize jQuery variable
var jQuery,
/******** Load jQuery if not present *********/
if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.6.2')
{
var script_tag = document.createElement('script');
script_tag.setAttribute("type","text/javascript");
script_tag.setAttribute("src", "http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js");
script_tag.onload = scriptLoadHandler;
script_tag.onreadystatechange = function () { // Same thing but for IE
if (this.readyState == 'complete' || this.readyState == 'loaded') {
scriptLoadHandler();
}
};
// Try to find the head, otherwise default to the documentElement
(document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
}
else
{
jQuery = window.jQuery;
main();
}
/******** Called once jQuery has loaded ******/
function scriptLoadHandler()
{
jQuery = window.jQuery.noConflict(true);
main();
}
/******** Our main function ********/
function main()
{
Ответ №1:
Проблема в том, что Prototype переопределяет метод Array.shift по умолчанию, который не является полностью совместимым. jQuery ожидает поведение по умолчанию.
На самом деле это не вызывает проблем только для jQuery, когда ваша страница загружается, вы получаете аналогичную ошибку, вызванную вызовом shift в curfon-yui.js скрипт загружен на эту страницу.
Давайте попробуем это в Firebug без загруженного прототипа:
>>> [].shift()
undefined
Теперь на вашей странице:
>>> [].shift()
RangeError: invalid array length
this[i]=this[i 1];this.length--;return...ct).join(': ');}).join(', ') '}>';}}
По-видимому, вы не единственный, у кого есть эта проблема: http://tommysetiawan.com/post/7887390641/jquery-and-prototype-conflict-array-shift
К сожалению, noConflict от jQuery не поможет в этом. Проблема, похоже, решена в более поздних версиях Prototype, поэтому, если у вас есть какой-либо контроль на главной странице, это может помочь обновить его версию Prototype. Тот факт, что он уже вызывает ошибки с другим скриптом, может быть хорошим аргументом, чтобы убедить владельца этой страницы исправить это. В противном случае вам может потребоваться изменить ваш виджет, чтобы он не вызывал Array.shift, или вы могли бы даже попытаться исправить Array.shift таким образом, чтобы исправить это.
Ответ №2:
Вы должны определить jQuery.noConflict()
сразу после function scriptLoadHandler(){
. В настоящее время вы вызываете noConflict()
после загрузки плагина пользовательского интерфейса, что слишком поздно.
var hasLoaded = false;
function scriptLoadHandler()
{
if(hasLoaded) return;
hasLoaded = true;
window.jQuery = jQuery.noConflict(true);
jQuery.getScript( "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.14/jquery-ui.min.js" ,
function(){
main();
}
);
}
Обновление: добавлено hasLoaded
для предотвращения двойного выполнения кода.
Комментарии:
1. Итак, я только что попробовал это, но теперь Firebug говорит, что jQuery не определен (в строке noConflict)
2. Ваш загрузчик неисправен, обновляя ответ, чтобы исправить это.
3. Я не смог заставить это работать с помощью getScript после noConflict, поэтому в итоге я вставил код пользовательского интерфейса jQuery в сам код виджета. Если кто-то видит, что я делаю не так, я бы хотел это услышать!