JS 小部件(使用 Jquery)与主机页面上的原型冲突

发布于 2024-12-08 21:09:29 字数 4373 浏览 2 评论 0 原文

我正在向其他站点提供 Javascript 小部件,并且我在小部件中对 Jquery 的使用似乎与主机站点对 Prototype 的使用发生冲突。

您可以在此处查看冲突的实际情况: http://www.phillyrealestateadvocate.idxco.com/idx/8572/results.php?lp=100000&hp=500000&sqFt=0&bd=2&ba=0&searchSubmit=& city%5B%5D=131

在页面右侧,点击绿色“提问”按钮 - 它将生成一个弹出窗口,一旦您打开弹出窗口,“无效数组长度”错误就会开始滚动到 JS 控制台(并且不会停止。)然后弹出窗口无法关闭,但仍然是可拖动的。弹出窗口中的代码/内容位于 iframe 中,因此它仍然可以正常工作,但弹出窗口不会关闭。

Firebug 给我的错误是: Prototype.js 中的数组长度无效,但是当我展开它的详细信息时,它引用了 jquery.min.js,所以这让我相信两者是冲突的。

我的小部件代码完全位于匿名函数中,并使用 Alex Marandon 此处描述的模型加载 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 UI,因此我完全消除了 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() 
    { 

I am providing a Javascript widget to other sites, and my use of Jquery in the widget appears to be conflicting with the host site's use of Prototype.

You can see the conflict in action here:
http://www.phillyrealestateadvocate.idxco.com/idx/8572/results.php?lp=100000&hp=500000&sqFt=0&bd=2&ba=0&searchSubmit=&city%5B%5D=131

On the right side of the page, click on the green "Ask a question" button - it will spawn a popup and as soon as you open the popup, "invalid array length" errors start rolling in to the JS console (and don't stop.) The popup is then unable to close but is still draggable. The code/content within the popup is in an iframe, so it still works normally, but the popup just won't close.

The error Firebug gives me is:
invalid array length in Prototype.js, but when I expand that for details, it has references to jquery.min.js, so this led me to believe the two are conflicting.

My widget code is entirely in an anonymous function, and loads Jquery using the model described here by Alex Marandon:
http://alexmarandon.com/articles/web_widget_jquery/

I am using a noConflict call, but perhaps it's not working the way I placed it?

Here is the beginning of my widget script which contains the references to jquery.min.js and 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

Any help would be much appreciated!

Edit: I now have Jquery UI directly within the widget, so I eliminated the getScript calls altogether. Unfortunately, this did not fix the conflict. Here is the new code:

(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() 
    { 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

稚然 2024-12-15 21:09:29

问题在于 Prototype 以不完全兼容的方式覆盖默认的 Array.shift 方法。 jQuery 期望默认行为。

实际上,这不仅仅对 jQuery 造成问题,当您的页面加载时,您会收到一个类似的错误,这是由于调用该页面上加载的 curfon-yui.js 脚本中的 shift 引起的。

让我们在没有加载原型的 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

不幸的是,jQuery 的 noConflict 对此无济于事。该问题似乎在最新版本的 Prototype 中得到了解决,因此,如果您对主页有任何控制权,则可能有助于更新其 Prototype 版本。事实上,它已经导致另一个脚本出现错误,这可能是说服该页面的所有者修复它的一个很好的论据。否则,您可能需要修改您的小部件,以便它不会调用 Array.shift,或者您甚至可以尝试以修复它的方式对 Array.shift 进行猴子修补。

The problem is that Prototype overrides the default Array.shift method in a way that is not fully compatible. jQuery expects the default behaviour.

Actually it's not causing problem only to jQuery, when your page loads, you get a similar error caused by a call to shift in the curfon-yui.js script loaded on that page.

Let's try it in Firebug without Prototype loaded:

  >>> [].shift()
  undefined

Now on your page:

>>> [].shift()
RangeError: invalid array length
this[i]=this[i+1];this.length--;return...ct).join(': ');}).join(', ')+'}>';}} 

Apparently you're not the only one to have this problem: http://tommysetiawan.com/post/7887390641/jquery-and-prototype-conflict-array-shift

jQuery's noConflict won't help with this unfortunately. The issue seems to be solved in more recent versions of Prototype, so if you have any control on the host page it might help to update its version of Prototype. The fact that its already causing errors with another script might be a good argument to convince the owner of that page to fix it. Otherwise you might need to modify your widget so that it doesn't call Array.shift or you could even try to monkey-patch Array.shift in a way that fixes it.

煞人兵器 2024-12-15 21:09:29

您必须在 function scriptLoadHandler(){ 之后立即定义 jQuery.noConflict()。目前,您在 UI 插件加载后调用 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 以防止代码的双重执行。

You have to define jQuery.noConflict() immediately after function scriptLoadHandler(){. Currently, you're calling noConflict() after the UI plugin has loaded, which is too late.

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

Update: added hasLoaded to prevent double execution of the code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文