web-dev-qa-db-ja.com

奇妙なChromeプロトタイプ/ jQueryの競合

プロトタイプに依存するレガシーコードを使用したアプリケーションがありますが、それを使用したいほとんどの場所にとって「重すぎる」ことがわかり、jQueryが私たちの作業方法により適していることがわかりました。そのため、新しい機能のためにjQueryに移行しています。

それまでの間、両方のライブラリをロードする必要のあるページがいくつかあります。

<script language="javascript" type="text/javascript"
        src="prototype-1.5.1.2.js"></script> 
<script language="javascript" type="text/javascript"  
        src="jquery-1.3.2.js"></script> 
<script language="javascript" type="text/javascript">
    $j = jQuery.noConflict();
</script> 

(プロトタイプの古いバージョンに注意してください。とにかく段階的に廃止する場合、修正したくないアップグレードの問題が見つかりました)

これはIE6、IE7、IE8-as-7およびFX3で機能しますが、Chromeにロードすると、すべてのjQueryスタッフが失敗します。

開発者のJavaScriptコンソールをロードすると、次のエラーが表示されます。

Uncaught Error: NOT_SUPPORTED_ERR: DOM Exception 9 http://.../prototype-1.5.1.2.js (line 1272)
Uncaught TypeError: Object #<an Object> has no method 'ready' http://.../lib.js (line 161)
Uncaught TypeError: Object #<an Object> has no method 'slideUp' http://.../page.aspx (line 173)
... and so on - all the failures are missing jQuery methods

したがって、これはプロトタイプの競合のように見え、jQueryオブジェクトの作成が失敗する原因になります。

XPathのdocument.evaluateがサポートされていないため、プロトタイプの特定の問題は、本来はPrototype.BrowserFeatures.XPathが真ではないように見えるようです。

さて、それではJavaScriptコンソールを開いた状態でページをリロードしてください-それはすべて機能します! WTF?コンソールを閉じてリロードすると、再び失敗します。

このエラーは、JavaScriptコンソールを開かずにページの読み込みが行われた場合にのみ発生します。なぜ違いが生じるのですか?これはChromeのバグに非常によく似ています。

何が問題になっているのか説明できる人はいますか?プロトタイプのエラーによりjQuery initが失敗するのはなぜですか?コンソールを開いた状態でページをロードすると機能するのはなぜですか?

誰かが良い回避策を知っていますか? (prototype-1.6.0.3.jsへのアップグレードは別として、この問題は修正されますが、レガシーコードのロードが他の場所で中断されます)

24
Keith

From Core/jQuery.noConflict

注:この関数は、jQuery JavaScriptファイルをインクルードした後で呼び出す必要がありますが、[〜#〜] before [〜#〜]他の競合するライブラリを含めて、また、jQueryが最後に含まれる場合に備えて、実際に他の競合するライブラリが使用される前に。 noConflictをjQuery.jsファイルの最後に呼び出して、$()jQueryエイリアスをグローバルに無効にすることができます。 jQuery.noConflictはjQueryへの参照を返すため、jQueryオブジェクトの$()エイリアスをオーバーライドするために使用できます。

多分それを次のように変更してみてください:

<script language="javascript" type="text/javascript"
  src="jquery-1.3.2.js"></script> 
<script language="javascript" type="text/javascript">
    $j = jQuery.noConflict();
</script>
<script language="javascript" type="text/javascript"
  src="prototype-1.5.1.2.js"></script>
44
Jake McGraw

この問題の原因は次のとおりです。

  1. プロトタイプがロードされ、WebKitにはdocument.getElementsByClass()がないため、プロトタイプが(ひそかに)作成します。

  2. jQueryの初期化が始まり、最上部で_window.$_をjQueryに設定します。

  3. JQueryの初期化中に、Sizzleエンジン(1.3.2で追加?)が初期化されます。イントロスペクションの一環として、document.getElementsByClass()の機能をチェックしてテストします。その結果、プロトタイプのgetElementsByClass()の実装を呼び出します。これは、jQueryではなくプロトタイプの_window.$_に設定されている_$_に依存します。

最終的に、これはjQueryで修正する必要があります(チケット http://bugs.jquery.com/ticket/4365 および 5027 を参照)。私の簡単なパッチは、jQueryの初期化の先頭にある_window.$_への割り当てを削除することでした。

10
hblanks