jQuery 1.3.1 リリース
ちょうどタイムリーな話題がわかったので、書いておきます。 jQuery 1.3.1 Released | Official jQuery Blog 23個のバグフィックスリスト Error: Invalid Report Number – jQuery Core - Bug Tracker 1.3 系最初のリビジョンアップとあって、既に使っている方は早速置き換えた方がいいでしょう。
ちょうどタイムリーな話題がわかったので、書いておきます。 jQuery 1.3.1 Released | Official jQuery Blog 23個のバグフィックスリスト Error: Invalid Report Number – jQuery Core - Bug Tracker 1.3 系最初のリビジョンアップとあって、既に使っている方は早速置き換えた方がいいでしょう。
jQuery 1.2.6 のソースコードを見ると、appendTo, prependTo, insertBefore, insertAfter, replaceAll の定義は下記のように、内部で append, prepend, before, after, replaceWith を呼び出し元、引数の対象を逆にして呼び出すようになっていることがわかる。 jQuery.each({ appendTo: “append”, prependTo: “prepend”, insertBefore: “before”, insertAfter: “after”, replaceAll: “replaceWith” }, function(name, original){ jQuery.fn[ name ] = function() { var args = arguments; return this.each(function(){ for ( var i = 0, length = args.length; i < length; i++ ) jQuery( args[ i ] )[ original ]( this ); }); }; }); あくまでも append, prepend, before, after, replaceWith がオリジナルのメソッドなのだ。 処理のステップを少なくするには、appendTo, prependTo, insertBefore, insertAfter, replaceAll はメソッドチェーン的に書きやすいか、引数となる対象が jQuery オブジェクトではない場合に限った方がよいだろう。 A.appendTo(B) とも B.append(A) とも変数 A, B がどちらも jQuery オブジェクトであるなら、後者を選んだ方がよい。 DOM 操作をするときは(replaceWith は除くが)append, prepend, before, after とメソッド名が短い方を選ぶと覚えておこう。
てっく煮ブログさんのエントリー jQuery を高速に使う CSS セレクタの書き方 - てっく煮ブログ をみてて、jQuery の $("#xxxx") を速くしたいと考えていたことを思いだした。それについて書く。 jQuery の $("#xxxx") について セレクタをどう処理しているのか jquery-1.2.6.js で確認してみよう。 まず下記の init が $() に相当する。Handle HTML stringsのところで引数が string だと quickExpr.exec が走る。これは正規表現でのセレクタ解析処理である。 その後、HANDLE: $("#id")のところでマッチして取得した ID を使って、var elem = document.getElementById 使い、それを return jQuery(elem) として再び init が呼び出される。 jQuery.fn = jQuery.prototype = { init: function( selector, context ) { // Make sure that a selection was provided selector = selector || document; // Handle $(DOMElement) if ( selector.nodeType ) { this[0] = selector; this.length = 1; return this; } // Handle HTML strings if ( typeof selector == “string” ) { // Are we dealing with HTML string or an ID? var match = quickExpr.exec( selector ); // Verify a match, and that no context was specified for #id if ( match && (match[1] || !context) ) { // HANDLE: $(html) -> $(array) if ( match[1] ) selector = jQuery.clean( [ match[1] ], context ); // HANDLE: $("#id") else { var elem = document.getElementById( match[3] ); // Make sure an element was located if ( elem ){ // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id != match[3] ) return jQuery().find( selector ); // Otherwise, we inject the element directly into the jQuery object return jQuery( elem ); } selector = []; } // HANDLE: $(expr, [context]) // (which is just equivalent to: $(content).find(expr) } else return jQuery( context ).find( selector ); // HANDLE: $(function) // Shortcut for document ready } else if ( jQuery.isFunction( selector ) ) return jQuery( document )[ jQuery.fn.ready ? “ready” : “load” ]( selector ); return this.setArray(jQuery.makeArray(selector)); }, ...
先日、404 Not Found に参加しました。 #1 は未参加だったので、 jQuery.fn.init() について後から読んでいたのですが、あまり Travesing API を見ていなかったので、あるノード以下から選択するときは、 $(".classname", context) みたいに書いてました。 jquery-1.2.6.js / Line 73 - 76 // HANDLE: $(expr, \[context\]) // (which is just equivalent to: $(content).find(expr) } else return jQuery( context ).find( selector ); とあるとおり完全にオーバーヘッドでした。 上記の抜粋部分に辿りつくには、正義表現で expr を解析するステップ(下記の部分)が発生していて、find 呼び出しのブロックに流れるとその結果を捨てています。この解析では expr が生成用の HTML 文字列もしくは ID セレクトかを判別しているからです。どちらでもない場合は、find となります。よって $("#id", context) というセレクタが ID 指定の場合には今回の話は当てはまりません。 jquery-1.2.6.js / Line 47 - 50 // Are we dealing with HTML string or an ID? var match = quickExpr.exec( selector ); // Verify a match, and that no context was specified for #id if ( match && (match\[1\] || !context) ) { 最初に『あるエレメント下のものを対象にしたい』と調べていたら、まず jQuery( expression, [context] )に辿りついたので、何も考えずにこの書き方をしてました。これからは context.find(selector) を使うようにします。 ...
jQuery UI (http://ui.jquery.com/) には便利なコンポーネントがある。このダイアログを使ってユーザーへの確認に使うモーダルダイアログを作りたい。 設定仕様に幅がある分、わかりずらいところがある。ということで下記のように手軽に使える用に関数を作ってみた。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 /* * 確認ダイアログ * * message : ダイアログのメッセージ本文 * title : ダイアログのタイトル * buttonok : OKボタンのテキスト * buttoncancel : キャンセルボタンのテキスト * response : コールバック関数を指定する。引数 cancel にボタン選択の結果が入る。 * OK ならば false キャンセルならば true となる。 */ function confirmDialog(message, title, buttonok, buttoncancel, response){ var _dlg = $('<div>'+message+'</div>'); var _buttons = {}; _buttons[buttonok] = function(){$(this).dialog('close');response(false)}; _buttons[buttoncancel] = function(){$(this).dialog('close');response(true)}; _dlg.dialog({ modal:true, draggable:false, title:title, height:130, width:320, buttons:_buttons, overlay:{ opacity:0.3, background:'#225B7F' } }); } /* Sample */ confirmDialog('この処理を続行しますか?', '確認', 'OK', 'キャンセル', function(cancel){ if (cancel) return; /*------------ 処理を書く ------------*/ }); ダイアログのベースとなる div は Document DOM ツリーに存在していなくてもいいので生成して、dialog() を呼び出すだけで動く。これは便利だ。dialog の引数で様々な設定が可能である。上記の例では見た目を一つのアプリで統一するので幅、高さなど固定で定義している。あとは modal 化と背景がクリックできないことを明示するために overlay を設定している。 ちょっとわかりづらいのは、buttons で表示ボタンがという設定できるのだが、ボタンのラベル値がキーであり、対となる値が選択時に走る関数の定義となるところだ。定義の例では、ボタン名としてキーを変数値にしたいために map[key] = func としてセットしている。
hover() は mouseenter と mouseleave を同時にセットする http://docs.jquery.com/Events/hover の引数の名前付けを見て、hover は mouseover と mouseout を同時に指定するものだと思っていたが違うらしい。 jquery-1.2.6.js の 2278 行付近 hover: function(fnOver, fnOut) { return this.bind(‘mouseenter’, fnOver).bind(‘mouseleave’, fnOut); }, とあるように mouseenter と mouseleave に対して指定するものである。 over/outと enter/leave の違いは、http://docs.jquery.com/Events/mouseover の Demo みるとよくわかる。 ある領域 A にカーソルが載ったときに、領域 A 内に動的にブロック B を表示するという処理を次のようなに作っていた。 http://tilfin.googlepages.com/overout.html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="content-script-type" content="text/javascript"> <script src="jquery-1.2.6.js"></script> <title>jquery mouseover / mouseout</title> <style type="text/css"><!-- #A { color:#fff; background-color:blue; border:1px solid #000; width:300px; height:200px; position:relative; } #B { color:#fff; background-color:red; border:1px solid #000; display:none; width:200px; height:100px; position:absolute; bottom:0; right:0; } #debug p { margin:0; line-height:110%; font-size:9pt; } //--></style> <script><!-- $(document).ready(function(){ $("#A") .mouseover(function(){ $("#debug").append("<p>A: mouseover</p>"); $("#B").appendTo(this).show(); }) .mouseout(function(){ $("#debug").append("<p>A: mouseout</p>"); $("#B").hide().appendTo(document.body); }); }); //--></script> </head> <body> <div id="A">A</div> <div id="B">B</div> <div id="debug"></div> </body> </html> しかし、これだと表示されたブロック B にカーソルが載ったとき、A の mouseout が発生するためちらつきが起こってしまう(これは Firefox のときで IE ではちらつきではなく消えたままになった)。 ...
先日、オライリーの Amazon ベストセラートップ 10 のフィードを生成をした。それを今度はスライドショーっぽく表示するガジェットを作ってみる。 フィードの取得には、Google Feed API — Google Developers を使う。これで RSS/ATOM の規格に左右されないし、サーバーサイドの中継 CGI を作る必要もなくなる。 スライドショー表示はクロスフェードさせたい。Prototype + Rico より jQuery (http://jquery.com/) の方が簡単だと思うのでこちらを選択した。 Google AJAX Feed API まずは Sign-up for an API Key - Google Loader — Google Developers でアクセスキーを取得する。 Google.load はおまじない。1 はバージョンらしい。 <script type="text/javascript" src="http://www.google.com/jsapi?key=キー"></script> <script type="text/javascript"> google.load("feeds", "1"); Google.feeds.Feed(フィードのURL) で取得の準備。 setNumEntries はエントリをいくつ取るかを設定する(デフォルトは 4)。 load でコールバック関数を指定する。 Google.setOnLoadCallback(initialize); で初期化関数をロード時に実行するようにする。 取得したフィード情報は、result.feed で取れる。通常だと JSON で返る。 http://code.google.com/intl/ja/apis/ajaxfeeds/documentation/reference.html#JSON 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 function initialize() { var feed = new google.feeds.Feed("http://feed.tilfin.net/amazon/oreilly-bestseller.xml"); feed.setNumEntries(10); feed.load(function(result) { if (!result.error) { var container = document.getElementById("container"); for (var i = 0; i < result.feed.entries.length; i++) { var entry = result.feed.entries\[i\]; var div = document.createElement("div"); div.innerHTML = '<a target="_blank" href="' \+ entry.link + '"><p>' \+ entry.title + '</p><div class="ctn">' \+ entry.content + '</div></a>'; div.className = 'page'; div.id = "page" \+ i; container.appendChild(div); if (i > 0) $("#page" \+ i).hide(); } pages = result.feed.entries.length; } }); } google.setOnLoadCallback(initialize); </script> まあ、サンプル見てわかるとおり、とても簡単。 ...