Situation

iPhone Safariを使うときにあるInput boxで何か入力後”return”キーのkeydownイベントをキャッチして、何かしらのアクションを行いたい、のが目的です。よくあるのがreturnキーでformをsubmitしたり、ボタンクリックのアクションを行ったり、キーボードを隠したりするところですかね。

Keydown event

*13</em>という数字がreturnキーのkeydown時のコードです。実はJavascript経験がある方ならすぐ分かると思いますが、13Enterキー*のコードでもあります。

もう一つのTipはキーボードを隠したいときはjQueryのblur()を使えばOKです。

参考:http://stackoverflow.com/questions/5932317/how-to-capture-the-keyboard-return-event-on-iphone-browser

#jquery

一年くらい使ってなかったので、ほぼ忘れてしまいました。そのためのメモという感じです。

// idがwrapperの中の最初のdivを取る
$("#wrapper").find("div:first")

この:xxxがBasic Filter(基本フィルタ)と読んで、他にもいろいろあります。

:first 先頭の要素を選択する。 :last 末尾の要素を選択する。 :not(selector) 指定したセレクターを除外した要素を選択する。 :even 偶数番の要素を選択する。 :odd 奇数番の要素を選択する。 :eq(index) インデックス指定した要素を選択する。 :gt(index) 指定したインデックスより後の要素を選択する。 :lt(index) 指定したインデックスより前の要素を選択する。 :header h1,h2などのヘッダ要素を選択する。 :animated アニメーション中の要素を選択する。

英語API 日本語API

#javascript #jquery

jQueryのappendやafterは全部DOM Manipulation、つまりDOM操作のメソッドであります。どう違うかは下記ソースコードを見るのが一番速いでしょう。

append(prepend,appendTo,prependTo)は要素内に、子供要素として貼り付ける

$('<span>span text</span>').appendTo(".chapter");

<div class="chapter"> ... </div>

組み立てた結果:

<div class="chapter">
	...
	<span>span text</span>
</div>

append、appendToは最後の子供要素として、prepend、prependToは最初の子供要素として挿入する感じです。

after(before,insertAfter,insertBefore)は要素の外、つまり同一のレベルで兄弟要素として貼り付ける

$('<span>span text</span>').insertAfter(".chapter");

組み立てた結果:

<div class="chapter">
	...
	<span>span text</span>
</div>

htmlタグがなければ無効

$('some text').appendTo(".chapter");

htmlに何の変更もないです。

#jquery

elem指定とID指定のjQueryセレクタパフォーマンス実験を行いました。 “先にJavascriptでelementをとってそれをjQueryの$セレクタに囲むやつ” vs “直接jQueryのidセレクタでとるやつ”。


コードで言うと $(document.getElementById(“foo”)) vs $(“#foo”)


普通前者が勝だろうと思うだろう、 どれくらいの差かを確認したくて。

結果

一万回ループでとった結果です。

  • IE8: 187 vs 344
  • IE6: 203 vs 453
  • Firefox×(3.6.3): 21 vs 63
  • Chrome(4.1.xx): 9 vs 39

サンプルコード

デモページへ

var t0 = new Date();

for (var i=0; i<10000; i++){
	$(document.getElementById("foo"));
}

var t1 = new Date();

for (var i=0; i<10000; i++){
	$("#foo");
}

var t2 = new Date();

alert("直接elementを渡す時間は:" + (t1-t0) + " , ID指定でとる時間は:"+ (t2-t1));

#jquery

下記のURLで試してみればすぐ分かりますが、 表題の通りblockUIで制御したところは解除した後にマウスのカーソルがおかしいです。 IE,FirefoxとChromeでテストした結果、Firefoxは無事のようです。

http://malsup.com/jquery/block/position.html

解決策

jquery.blockUI.jsを開いてreset()のfunctionのところに以下のコードを追加

data.el.style.cursor = 'default';

第三者のソースに手を加えるのはあまりやりたくないけど。

参考サイト

http://groups.google.com/group/jquery-en/browse_thread/thread/c86671033a86be25/ebd5e710cc78885a?lnk=gst&q=cursor#

#jquery

よく出来ていると思います。 勉強になります。

siblings: function( elem ) {
	return jQuery.sibling( elem.parentNode.firstChild, elem );
},
children: function( elem ) {
	return jQuery.sibling( elem.firstChild );
},

そしてjQuery.sibling()の中身です! nodeTypeが1の場合はelementノードの意味です。 nはループに使われて、elemは除外する要素です。 例えばsiblings()の場合は自分自身を除外しています。 for文の書き方も覚えとこう、、 javaでのIteratorのhasNext()関数みたいな動きをしていますね。


	sibling: function( n, elem ) {
		var r = **;

		for ( ; n; n = n.nextSibling ) {
			if ( n.nodeType === 1 && n !== elem ) {
				r.push( n );
			}
		}

		return r;
	}

#jquery

表題の通り、IE6 + jQuery1.3.2の状態でbindする時に jQueryのnamespaceを使うと確実にメモリリークが発生します。 jQuery1.4.2では発生しないことを確認しました。

メモリリークが発生するコード

$("#foo").bind("change.abc", function(){});

上記”change.abc”のabcがnamespaceです。 それをなくすことでメモリリークは解消されます。 イベントハンドラの中身とは関係ありません。

メモリリークは発生しない

$("#foo").bind("change", function(){});

これはjQueryのbugとして上げられましたが、 完全に修正できなかったみたいです。 http://dev.jquery.com/ticket/4241で 当時の担当者のコメントを見ると

I had a really difficult time getting a reliable test case to verify this actually solves the memory leak. r6321 appears to have fixed this issue

「時間ないからちゃんとテストしてない、r6321の対応で解決できたように見える」と、 ずいぶん適当な回答ですよね。。。

#jquery

DOM操作を避けてjQueryのパフォーマンスを改善する掟です。 こんなコードがあるとしましょう。

パフォーマンスの悪い例

var list = *....*;    // 長さ100の配列とする

for (var i in list) {

    var li = document.createElement("li");

    $(li)
       .attr("id", "li" + i)
       .text(list*i*);

$("ul").append(li);

}

改善したコード

var list = *....*;    // 長さ100の配列とする

var li = "";
for (var i in list) {

    li += "<li id='li" + i "'>" + list*i* + "</li>";

}

$("ul").html(li);

まとめ

  • document.createElementの代わりにHTMLの文字列を作る
  • jQueryオブジェクトに属性やテキストを設定するのではなく、直接HTML文字列に書く
  • for文内毎回appendの代わりにhtml()を使う

実際のプロジェクトでやってみたら10倍以上は速くなりました。 とは言ってもこれはIE6でのパフォーマンスで、 FirefoxやIE8だと悪い例のコードても遅いとは実感できないくらいでした。

ちなみに $(li).attr(…).val(…).text(…)の方は読みやすいので結構気に入ったんですけど。。。

#jquery

jQuery 1.4.2ではこれは治ったようです。 jQuery最新版をお使いの方は下記のようなバグはもう発生しません。

サンプル

※jQuery 1.3.2で発生する問題※

HTML

<select>
	<option id="foo">&nbsp;</option>
	<option>11</option>
	<option>22</option>
</select>

<tr id="bar">&nbsp;</tr>

Javascript

var optionText = $("#foo").text();

// firefoxは0、IEは1
alert("select optionタグの をtrimした後のlength: " + $.trim(optionText).length);

var trText = $("#bar").text();

// firefoxは0、IEも0!
alert("trタグの をtrimした後のlength: " + $.trim(trText).length);

結果

selectのoptionタグのテキストにある“&nbsp;”に $.trimをかけて見ると Firefoxはちゃんとtrimしてlengthが0になったが、 IEはtrimできずlengthが1のままです。

しかしtrタグのテキストにある”&nbsp;”をtrimすると IEも正しくtrimしてlengthが0になるんです。。。

DEMO

jQuery最新版(1.4.2)を使うDEMO

#jquery

こんなHTMLがあるとします。 idに**が付いてますね。

<input id="foo0" type="text" />
<input id="foo1" type="text" />
<input id="foo2" type="text" />

こういうIDに括弧が付いたモノに対して 普通の#付きのjQueryセレクタでは選択できません。

$("#foo0");    // 取れません

属性フィルタattribute=valueでとるのが正解です。

$("id='foo[0]'");

0311更新: もし具体的なタグがわかってあれば、 それを指定することでパフォーマンスを向上できます。 上記の例で言うと

$("inputid='foo[0]'");

このほうが速いです。

#jquery

$.inArray(value, array)

指定した値が配列中にあれば、そのインデックスを返します。 配列に存在しなければ戻り値は-1になりますので注意してください。

var array = ["a", "b", "c"];

if ($.inArray("d", array) == -1) {
    // d is not in array
}

下記のコードは間違いですよ。。。

if ($.inArray("d", array)) {}

$.isArray(obj)

パラメータで渡された値が配列であるかどうかを判別します。 戻り値はtrueかfalseです。

#jquery

jQueryでマウス右クリックを無効にする方法です。 “contextmenu”のイベントはjQueryのドキュメントには乗ってませんが、 それのハンドラでreturn falseすることで簡単に実現できます。


$("document").bind("contextmenu", function(){
    return false;
});

#jquery

jQueryのAPIを一枚の紙にまとめたものです。 ノートはPDFファイルで、ダウンロードすることができます。 jQuery APIノート

jQuery-api-note

作者はMattさんです。ありがとうございました。

他にもHTML、CSS、JavaScript、PHP、Mac、Windows、Photoshop、Browserなどのノートが満載です。

HTML, CSS, PHP, Javascript And More Cheat Sheets 興味のある方は直接作者のサイトを参照してください。

#jquery

iframeでXMLを読み込んた場合、XMLのdocumentを正しく指定すれば 普通のDOM操作のようにXMLに対して操作できます。 FirefoxとIEの取り方が異なるため、その方法を紹介します。

サンプル

こんなXMLファイルの中の各name要素のテキストを取るとします。

<?xml version=”1.0″ encoding=”utf-8″ ?>
<games>
    <game>World of Warcraft</game>
    <game>Warcraft III</game>
    <game>StarCraft</game>
    <game>Final Fantasy</game>
</games>

IEの場合XMLDocument

$("iframe").attr("src",xmlUrl).one("load", function(){
    var xmlDocument = this.contentWindow.document.XMLDocument;
    $(xmlDocument).find("game").each(function(){
        var game = $(this).text();
       // ほかの処理
    });
});

Firefoxの場合ActiveElement

$("iframe").attr("src",xmlUrl).one("load", function(){
    var xmlDocument = this.contentWindow.document.ActiveElement;
    $(xmlDocument).find("game").each(function(){
        var game = $(this).text();
       // ほかの処理
    });
});

xmlUrlは実際XMLファイルのURLです。

参考サイト

下記の英語掲示板で見つけたんです。 How to Get XML Document from iFrame

#jquery

そもそもIDというのは一つのページ内でユニークなはずですが、 何らかの理由で同じIDを持つ形になったとしましょう。 その場合普通のjQueryの#idセレクタでは一つの要素(順番的に最初に合致した要素)しか選択できません。 そこで[id=xx]の形で属性フィルタで全ての選択することができます。 以下サンプルコードです。

$("#foo").css("background-color","gray");
$("[id=bar]").css("background-color","green");
<h2>use #id selector</h2>
<input type="text" id="foo" value="Text1" />
<input type="text" id="foo" value="Text2" />
<h2>use attribute selector *id=xx*</h2>
<input type="text" id="bar" value="Text3" />
<input type="text" id="bar" value="Text4" />
<input type="text" id="bar" value="Text5" />

jQuerySelectorByID

Demo

以下のjsfiddleで実際実行してみてくださいー

#jquery

FireQueryはFirebugを拡張したアドオンで、jQueryをよりよくサポートできるんです。 jQueryのオブジェクトをコンソールで確認したり、マウスオーバーで画面上のレーヤーで表示されたりして 大変便利になります。 これ以外でもjQuerifyというやつがあって、 jQueryが適用されてないhtmlにもfirebugのコンソールで直接jQueryのコードを書いてそのまま動作確認ができます。

主な機能

  • jQuery expressions are intelligently presented in Firebug Console and DOM inspector
  • attached jQuery data are first class citizens
  • elements in jQuery collections are highlighted on hover
  • jQuerify: enables you to inject jQuery into any page

FireQuery

FireQuery2

jQuerifyを使おう!

  • まずfirebugのconsoleのjQuerifyをクリックします。するとjqueryが適用されたと表示されます。 jquerify

  • 次は「»>」のところでjquery文を書けばOKです。

fireQuery

  • 複数行のjqueryコードが書きたい場合は、右下にある「↑」ボタンをクリックし、コンソールの右フレームで書けます。

jquery-runed

ダウンロード

FireQuery Download

#jquery

今のlive関数は二番目の引数にデータを渡すことができません。 bindとliveのシグネチャーは以下になります。


bind(type, *data*, fn)
live(type, fn)


いざ使おうと思って単純にbindをliveに変換したところアプリは動かなくなっちゃいました。 回避方法はいろいろありますが、以下の記事によりますと jQuery 1.3.3ではliveにもdataを渡すことができるそうです。 作者はjQueryのコアコントリビュートだそうです。 jQuery Edge: Live Events now with Data

#jquery

今まで平気に$(expression)を使ってきましたが、 この二番目のcontextパラメータでセレクタの範囲を決まることができます。 この関数はjQueryのコア関数で幅広く使われ、 もっとも一般的な使い方はcontextを省略したものでしょう。

$("div")

contextパラメータ

contextが何も指定されなければ、$()関数は現在のHTMLのDOMエレメントを検索する。 逆にDOMエレメントやjQueryオブジェクトなどのcontextが指定されれば、expressionはそのcontextに対して合致するものを捜します。

簡単にいうとfind()関数と似ています。 実践でいうと以下の二つは同じ機能をしています。

$("body").find("div");
$("div,body");

参考サイト

jQuery(expression, context) - jQuery 1.3.2 日本語リファレンス

#jquery

htmlにoptionが一つしかないselectboxがあるとします。 このようなselectを非表示にし、そのテキストラベルで表示させたいのもありですね。

<select>
    <option>1</option>
</select>

jQuery文はこれ

//:only-childフィルタで子要素が一つしかない要素を選択
var $target = $("select :only-child");

$.each($target, function(index, item) {

  // spanのhtmlを構築
  var span = '<span>' + $(this).text() + '</span>';

  // thisはoptionを指しているため、そのparentのselect要素を非表示
  // 構築したspanを挿入
  $(this).parent().hide().after(span);

});

さらにブランクの要素をフィルタ

selectボックスの先頭がblankのケースが結構あると思います。 その場合はラベル表示させたくないです。 なのでそれをフィルタするには、以下のようにfilter()を使います。

var $target = $("select :only-child").filter(function(index) {
	return $.trim($(this).text()).length != 0;
});

$.trim()の1000倍速い方法でブランクを検出

jQueryにはblankを検出するメソッドがないため、上記のソースコードでは $.trim()を利用して判断しています。 しかしこの$.trim()は遅いとの報告がありました。 そこでblankのテキストを検出するためのメソッドも提供されました。 $.trim()が2000msかかったものがこれだと0.5msになったようです。

blank: function( text ) {
	return !text || !/\S/.test(text);
}

興味のある方はこの記事を参照してください。英語のサイトです。 Zipalong Blog » Blog Archive » jQuery: x1000 faster test for blank strings (on large strings)

#jquery

toggle()の普通の使い方は多分皆さんご存知だと思います。 該当要素をクリックするたびに表示/非表示を切り替えます。

今日紹介するのはこのswitchパラメータ付のtoggleです。 swtich文を評価しtrueであれば要素を表示、falseであれば非表示です。 これで下記のコードがこのswtich付きのtoggle文なら一行ですみます。

if (name == "kinopyo") {
	$("p").show();
} else {
	$("p").hide();
}

これがこうなります。

$("p").toggle(name == "kinopyo");

どうですか?すごくないですか? まさにjQueryの「The Write Less, Do More」ですよね。 ただし判断の条件文が行の最後になるので、 読みやすさは多少落ちると思います。
ちなみに、Googleの単語とよく似ているので、ついついtoogleと書いちゃいますorz

#jquery

今までjQueryを使ってきたtipsをメモします。

Tipsの定義とおり知っていればちょっと便利になるけど、

知らなくても特に問題ないですね。

ただしlive関数においてはすべてのイベントに有効じゃないのは

知っておいてほしいです。

live関数

liveはすべてのイベントに対応していない。

サポート

click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, keydown, keypress, keyup

非サポート

blur, focus, mouseenter, mouseleave, change, submit


ajax関数のurlパラメータ

AJAXのURLではセレクタも併用できる。セレクタによりあるページの一部だけを読み込むことができる。

こんな形です:"url #some > selector"

デフォルトは"body>*"のセレクタが適用されていますよ。

```js $("#links").load("/Main_Page #jq-p-Getting-Started li"); ```

:has(selector)フィルタ

:has(selector)は持ってるすべての子要素に対して動作してる

divい対して:hasフィルタを使うと、p要素までフィルタが走る

```html
span ...

p..

```

属性フィルタの組み合わせ

[filter][filter]……のように複数を連続して記述することもできます。この場合、すべての属性フィルタに合致する要素だけが取り出されます。

htmlの組み立て

ハードコードで書く
```js $(select).append(""); ```
jQueryの関数を用いて書く
```js $(select).append($('
#jquery

@IT連載:jQuery逆引きリファレンスの第二回のテーマは属性&コンテンツです。

目次は以下になります。

* 属性値を取得するには?

* 属性値を設定するには?

* 複数の属性値をまとめて設定するには?

* 関数の結果によって動的に属性値を設定するには?

* 属性値を削除するには?

* スタイル・クラスを追加/削除するには?

* スタイル・クラスが適用されているかを判定するには?

* スタイル・クラスの適用/解除を交互に行うには?

* 要素に適用されたスタイル情報を取得するには?

* 要素に特定のスタイルを適用するには?

* 複数のスタイル・プロパティをまとめて設定するには?

* 要素の表示位置を取得するには?

* ページのスクロール位置を取得/設定するには?

* 要素の高さや幅を取得するには?

* 要素の高さや幅を設定するには?

* 要素のテキストを取得するには?

* 要素のテキストを設定するには?

* フォーム要素の値を取得/設定するには?

勉強メモ

text()とhtml()の違い

(1)取得する対象

 要素セット(jQueryオブジェクト)が複数の要素を含んでいる場合、htmlメソッドは先頭要素の内容だけを取得しますが、textメソッドはすべての要素の内容を結合したものを取得します。

(2)取得する内容

 名前のとおり、htmlメソッドは要素の内容をHTML文字列として取得しますが、textメソッドは純粋なテキストだけを取得します。

(3)対応する形式

 textメソッドはHTML/XMLいずれの形式でも動作しますが、htmlメソッドはHTML(XHTMLを含む)形式でしか動作しません。このサンプルでは扱っていませんが、textメソッドをXML形式で利用する方法については、あらためてAjax編で紹介する予定です。

https://www.atmarkit.co.jp/fdotnet/jqueryref/02attribute/attribute_16.html
height(val)、width(val)

引数valには数値、もしくは「em」や「%」などの単位付きの数値を指定できます(単なる数値の場合はピクセル値として認識します)。

要素の高さや幅を取得するには?

- height()、width()、innerHeight()、innerWidth()、outerHeight()、outerWidth()

関数paddingborder-widthmargin
height、widthxxx
innerHeight、innerWidthoxx
outerHeight、outerWidthoox
outerHeight、outerWidth(trueooo

関数の結果によって動的に属性値を設定するには?

- attr(name, fnc) -

コールバック関数の戻り値を用いて設定。

```javascript $(function() { $('li > img').attr( 'src', function(index) { return "http://www.wings.msn.to/books/" + this.id + "/" + this.id + "_logo.jpg"; }); }); ```

#jquery

jQueryのfocus()はデフォルトのフォーカス動作とそのエレメントにバインドされたイベントが実行されます。

しかしIE8とFirefoxではこのfocus()の動作が多少違います。

現象

例えば複数のinput要素があって、それぞれfocusイベントとblurイベントがバインドされたとします。

focus()を実行する前はelem1にフォーカスしていて、要素$(‘elem2’).focus()を実行すると

  • Firefox 3.5.5ではelem1のblurイベントが実行した後に、elem2のfocusイベントが実行する
  • IE8ではelem1のblurイベントは実行されますが、elem2には2回フォーカスするように動作します。

つまり下記の動きです。

  1. elem1のblurイベント
  2. elem2のfocusイベント
  3. elem2のblurイベント
  4. elem2のfocusイベント

普通に考えたらFirefoxの動きが正しいはずですよね。 上記の3と4は余計な処理になります。

サンプルコード

$("form :input").bind("focus", function() {
  $(this).css("background-color", "gray");
  // ログを出力
    $("#result").append($(this).get(0).id + " focus event triggered.<br>");
  }).bind("blur", function() {
  $(this).css("background-color", "");
  // ログを出力
    $("#result").append($(this).get(0).id + " blur event triggered.<br>");
  });
$("#foo").focus();
setTimeout(focusBar, 3000);
function focusBar() {
  $("#" + document.activeElement.id).trigger('blur');
  $("#bar").focus();
};
Foo<input id="foo" type="text" />
Bar<input id="bar" type="text" />
<div id="result"></div>

先にfooテキストエリアにフォーカスしてくささい。 3秒後にbarテキストエリアにfocus()メソッドでフォーカスします。 その時の出力ログを見てください。

回避策

まだいい方法はつかんでません。

Googleで検索すると似たようなものはありましたが、

回避策はまだないようです。

[jQuery] Focus event firing twice in Internet Explorer

#jquery

@IT新しい連載:jQuery逆引きリファレンスが始まりました。

既に一ヶ月前になりますが、

自己テスト用でもいいともいます。

私は自信がない項目が結構ありました。


jQueryで使ったシンタックス英単語は

ほとんど簡単な単語で

ぱっと見たら分かるような気がするけど、

本気で使おうとしたらまたいろいろ調べないと

と感じました。

例えば:containのフィルタにはテキスト(case-sensitive)

しか入りません。

逆に:hasにはセレクタ分が使えるなど

意味合い的には似てますが、

使い方がまったく違うところが

落とし穴だと思います。


以下がセレクタ編のタイトルです。

自信があるのは何項目ですか?

* id値で要素を特定するには?

* タグ名で要素を特定するには?

* スタイル・クラスで要素を特定するには?

* 複数のセレクタをまとめて指定するには?

* すべての要素を取得するには?

* ある要素の配下にある要素だけを取得するには?

* ある要素の直下にある要素だけを取得するには?

* 指定した要素の次要素を取得するには?

* 指定した要素以降の兄弟要素を取得するには?

* 先頭/末尾の要素だけを取得するには?

* 指定された親要素の先頭/末尾の子要素を取得するには?

* 偶数/奇数番目の要素だけを取得するには?

* 指定したインデックス番号(より大きい/未満)の要素を取得するには?

* 指定された要素直下から特定の子要素だけを取得するには?

* 指定したセレクタ以外の要素を取得するには?

* 配下に特定のテキストを含んだ要素を取得するには?

* 空要素だけを取得するには?

* 何らかの子要素を持つ要素を取得するには?

* 指定した子要素を持つ要素を取得するには?

* 子要素が1つだけである要素を取得するには?

* 属性の値によって取得要素を絞り込むには?

* 複数の属性フィルタを組み合わせるには?

* フォーム要素やヘッダ要素を取得するには?

* 特定の状態にある要素のみを取得するには?

第1回 セレクタ編 - @IT

これをきっかけに曖昧なところをいったん全部整理しようと思います。

後の記事でまた詳しく書きます。

#jquery

誤った使い方

例えばbind時にname変数に格納された情報を渡したい

var name = "kinopyo";
$(":button").bind("click", function(name){
  alert(name);
});

これは誤った使い方です。

alertでは望まれた「kinopyo」の文字列は表示されません。

私は最初jQueryに触れたときはこんな書き方をしたんです。


もちろんname変数とbindのコールバックは同じスコープなのでfunctionから直接name変数を参照できますが、

ここではあえて誤った使い方にしました。


実際alertでは[object Object]と表示されました。

firebugで中身をのぞいてみるとこんな感じのオブジェクトです。

このnameは一体何のか、答えはjQueryのEventオブジェクトです。

Eventオブジェクトについてはこの記事「jQuery Eventオブジェクトの詳細、バブリングの仕組み」を参照してください。

bindのAPI

bind(type, [data], fn)

  • type:click, dbclick,mousedown…などトリガーとなるイベントタイプ
  • [data]:第三パラメータのハンドラにデータを渡す。括弧は配列の意味ではなく、省略可の意味
  • fn:イベントハンドラ
  • パラメータ:jQueryのEventオブジェクト、event.dataで第二引数の[data]を参照できる

jQueryは第二パラメータに対してdataかfunctionか自動判断してます。

普段使い慣れたのはdataを省略したものでしょう。

さっきの例を修正すると、正しく「kinopyo」が表示されます。

var name = "kinopyo";
$(":button").bind("click", name, function(event){
  alert(event.data);
});

渡されるのはJavaScriptのオブジェクトです。。

つまり配列も、キー値ペアのオブジェクトも全部渡されます


参考サイト

公式サイトのbindドキュメント

StackTraceサイト

#jquery

jQueryのEventオブジェクトには

いくつかのプロパティとメソッドがありますが、

それらの定義より、実際どの場面に使えるかを重点として紹介したいと思います。

dataプロパティ

bind時に渡されたデータを保持します。

こちらの記事「jQuery bindバインド時にデータを渡す」をごらんください。

currentTargetとtargetプロパティ

最初currentTargetはイベントが発生したDOM要素だと理解していましたが、

jQueryのドキュメントを見ると似た名前でtargetの属性もあります。

そしてcurrentTargetには「バブリング」のキーワードが出てきましたので、

詳しく書きたいと思います。

サンプル:

一番大きいdiv範囲内をクリックするとそのdivのclass属性の値を返すJavaScriptです。


$(".big").bind("click",function(evt){
	alert(evt.currentTarget.className);
});

そしてHTMLコードは以こんな感じです。CSSの部分は省略しました。

直接画像を参照してください。

<div class="big">
	<div class="medium">
		<div class="small">
		</div>
	</div>
</div>

f:id:kinopyo:20091111223232j:image

alert部分のevt.currentTargetとevt.targetを入れ替えて検証します。

  • 黄色の部分をクリック
    • currentTarget:big
    • target:small
  • 緑色の部分をクリック
    • currentTarget:big
    • target:medium
  • 青色の部分をクリック
    • currentTarget:big
    • target:big

結果:

currentTargetは常にbigを表示するに対し、

targetは子要素まで「精確」表示する

どうですか、あたり?はずれ?

ここでもう一回jQueryのドキュメントを見てみましょう。

currentTarget The current DOM element within the event bubbling phase.This attribute will always be equal to this of the function.
target Contains the DOM element that issued the event. This can be the element that registered for the event or a child of it.

currentTargetは実際bind時の要素を指して、

targetはその要素および子要素まで全部含んでいると私は理解しましたが、

「バブリングフェーズ」の言葉については未だ曖昧な感じです。

そしてcurrentTargetは常にハンドラ内のthisと同じことも覚えておきましょう。

クロージャを使う際に例えばthisがほかのオブジェクトを指しても

event.currentTargetでイベントにバインドされた要素を使えます。

pageX、pageYプロパティ

  • 定義:イベント発生時のマウス座標

この「マウス座標」に興味があり、本当にイベント発生時のマウス座標か、

それともイベントが発生時のDOM要素の座標かを試しました。

jQueryサンプルのソースを使いました。

$("a").click(function(event){
	alert("Current mouse position: "
		+ event.pageX + ", " + event.pageY);
})
  • マウスでクリック:「Current mouse position: 37, 312」
  • リンクにTabでフォーカスしEnter:「Current mouse position: 0, 0」

本当にマウスによるイベントでしか座標が取れないみたいです。

応用としてはツールチップなどのプラグインで、

マウス現在の座標でオフセットして表示するイメージです。

stopPropagation()メソッド

これはバブリングに対してよく使われる用語ですね。

バブリングは言語に制限せずイベントに関する制御では必ず出てきます。

最近見たFlex3でもバブリングがあったし、

iPhoneの開発でもresponder chainの用語があり、その中身も実際はバブリングの話です。

一回だけ徹底で勉強すればどの場面でも使えるんです。

ここまで書いてちょっと疲れましたが、

自分もちゃんと決着をつけたいので、やはり書きましょう!

利用するサンプルはやはりさっきの大中小DIVです。

JavaScriptのほうのみ修正します。

$(".big").bind("click",function(evt){
	alert("big");
});
$(".medium").bind("click",function(evt){
	alert("medium");
});
$(".small").bind("click",function(evt){
	alert("small");
	evt.stopPropagation();
});
  • 黄色部分をクリックするとsmallのみが出力される
解釈

もしstopPropagationがなかったら

そもそもの動きとしてはまずイベントが発生した要素smallのイベントハンドラが処理を行います。

そしてそのsmall要素が属している親要素にイベント終了とのことを伝播し、

もしその親要素も該当イベントにバインドされたら、親のイベントハンドラが実行します。

こんな形でどんどん親にイベントを伝播するイメージがまさにバブリングという単語の意味です。

stopPropagationが実行されるとそのバブリングフェーズが終了した時点で親に対しての伝播を中止します。

自分もよくわからない「バブリングフェーズ」の用語を使っちゃいました。

なぜかって言うと、次のサンプルを先に見てみましょう。

さっきのJavaScriptを元に一つの処理だけを追加しました。

$(".big").bind("click",function(evt){
	alert("big");
});
$(".medium").bind("click",function(evt){
	alert("medium");
});
$(".small").bind("click",function(evt){
	alert("small");
	evt.stopPropagation();
});
$(".small").bind("click",function(evt){
	alert("small2");
});

これでsmallの黄色部分をクリックするとどうなるでしょうか?

small2は表示されますか?

答えは、表示されます。

なぜならさっき言ったようにstopPropagationは親に対しての伝播を中止するだけで、

同じ要素に対しての処理には影響がないとのことです。

もし同じ要素に対しても処理を中止したい場合はstopPropagation()の代わりに、

これは使います。

event.stopImmediatePropagation();

これならさっきの例で言うと、small2は出力されません。

イベントオブジェクトについてはとりあえずこの辺で終わります。

参考サイト

公式サイトのEventオブジェクトドキュメント

StackTraceサイト

#jquery

マインドマップでまとめました。ごらんください。

基本的な使い方はほかのサイトでもいっぱい書いてるため、

省略します。

大まかな仕組みだけをメモとして書きたいと思います。


最初に理解してほしいのはルールと検証メソッドです。

これはペアとして使います。

まずルールでは検証したい項目のname属性と適用するルール名を書きます。


例えばこんな感じです。

rules: {
  comment: {
    required: true,
    minlength: 5
  }
}

これはname属性がcommentの要素に対してrequiredとminlengthのルールを適用する意味です。

ルールの詳細はつまり検証メソッドに実装されています。

required,minlengthなどはプラグインのbuilt-inルールです。

ここでrequired(必須)は実際どう実装されたかをちらっと見てみましょう。

(私も実は初めてです。。。)

以下抜粋したコードです。

required: function (value, element, param) {
    // check if dependency is met
    if (!this.depend(param, element)) return "dependency-mismatch";
    switch (element.nodeName.toLowerCase()) {
    case 'select':
        var options = $("option:selected", element);
        return options.length > 0 && (element.type == "select-multiple" || ($.browser.msie && !(options[0].attributes['value'].specified) ? options[0].text : options[0].value).length > 0);
    case 'input':
        if (this.checkable(element)) return this.getLength(value, element) > 0;
    default:
        return $.trim(value).length > 0;
    }

一番デフォルトな行為はこれですね。

return $.trim(value).length > 0;

単純にその項目のvauleをtrim(スペースを取り除く)して長さを確認してます。

その前に要素がselectの場合や、inputの場合の判断がそれぞれ違います。

最初にdependがあるのですが、これは簡単に言うとこの要素が必須項目となるのはある前提がある意味です。


これが一番基本の仕組みとなってます。

これ以外もメッセージの内容や位置、

どのタイミングで検証するか、

エラーがある場合のコールバックなどを各自でカスタマイズできるようになってます。


参考となったサイト:

#jquery

jQueryの$.extendはとても便利な機能です。

jQueryのプラグインを作成する場合は以下の二つを利用します。


$.extend(object) //jQueryそのものを拡張する
$.fn.extend(object) //jQueryエレメントに新しいメソッドを追加する。
//(典型的なjQueryプラグインの作成方法)


今回検討するのは第三の使い方です。

$.extend(target,option,...);

これは第一のパラメータのオブジェクトをどんどん拡張する意味です。

実際のプログラミングではこんな使い方が両方あります。

$.extend(target, option);
$.extend({}, target, option);


違いは何でしょうか?


$.extend(target, option);

これはtargetそのものを拡張する意味です。

実行後targetオブジェクトは変更(拡張)されます。


実例として、例えばプロジェクトにトップレベルの空のConstansクラスがあります。

その下で各モジュール要のconstantsが定義されていて、

それをトップのConstantsに拡張します。

$.extend(constants,subConstants1,subConstants2...);

落とし穴:

var defaults = {};
var option = {};
var opts = $.extend(defaults,option);

上記ではdefaultsが変更され、わざわざ変数optsに代入する意味もなくなります。


$.extend({}, target, option);

これは空のオブジェクトを拡張する意味です。

実行後、targetもoptionもかわらりません。

最も多く使われている実例は、jQueryのプラグインの開発です。

あるデフォルトのoptionを定義し、

ユーザが自分のニーズにあったoptionがあればそれを適用する感じです。

ここで大事なのは定義したデフォルトのoptionはかわりたくないのです。

なので、最初に空のオブジェクトを拡張しそれを何かの変数に

リファレンスをアサインします。


var defaults = {};
var option = {};
var opts = $.extend({},defaults,option);

これで変数optsは求めているデフォルトoptionとユーザが定義したoptionをマージ、拡張したものとなります。

#jquery

前記:

この記事では多数のAJAX通信が発生した際、 「非同期」の処理順番を保障する方法を検討します。 すべては私個人の経験なので、もしこれよりもっどいい方法があれば ぜひ教えてください。 実際この問題にぶつかった際の考えの流れで書いています。 使えない案や、懸念がある案も全部述べたので、文章が長くなってしまいました。 開発する当時はまだインターネットにつながらないので、 何の情報も取得できず、考えたんです。 後でネットで調べたらAjax Queueのプラグインが 同じことをしてくれます。 このプラグインを使った後に所感を書く予定です。

本題

AJAXはご存知だと思います。非同期通信でページをリフレッシュせずに動的に通信ができる、 リッチなウェブアプリケーションを構築する上で不欠けんな存在であります。

一方、この「非同期」というのは特徴であり、たまには厄介なことになります。 例えばajaxの処理と普通の処理の実行順序を気にするとき、 コードの書いた順番とおり実行する保障はありません。

jQueryでコードを書くと、こんな感じです。

$.ajax(option);
alert('ajax done');

ここでajax通信が終わってからalertが出るように見えますがそうとは言い切れないです。 ajax通信が終わってない段階でalertが出るかもです。 ならばどうしたらいいんですか?

一番簡単なのはjQueryが用意したコールバック関数です。

$.load(url, [data], [callback])
$.get(url, [data], [callback], [returnType])
$.getJSON(url, [data], [callback])

などがあります。 [data]がなければ、コールバックの関数を二番目のパラメータで書いてもOKです。 jQueryは内部的に判断してくれます。dataなのか、コールバックかを。

そして$.ajaxにはoptionでsuccessやcompleteにコールバックを設定できます。 これらを用いて上記のコードを以下のように改善できます。

$.ajax(option)の場合

.load(url,[data],[callback])
$.get(url,[data],[callback],[returnType])
$.getJSON(url,[data],[callback])

ここで問題2に入ります。

もし必要なajax通信が一つ以上で、すべてのajax通信が完了した後に何かの処理が実行したい場合は どうすればいいでしょうか。

コードで書くと、こんな感じです。

$.ajax(option1);
$.ajax(option2);
$.ajax(option3);
function(){
	alert('all ajax done');
}

案1:ajaxのグローバル関数

jQueryではajaxのグローバル関数と呼ばれるいくつかの関数を提供してくれました。 それらは以下のようなものです。

.ajaxComplete(handler)
.ajaxSuccess(handler)

これらはDOM上のどの要素にも設定でき、AJAX通信が行われる際に呼び出されます。

例えば以下のようなコードがあります。

$(document).ajaxComplete(function(){
	alert('ajax complete');
});

これはdocument要素において、何かのajax通信が完了したらパラメータのコールバックを実行する意味です。 selectorにはもっと範囲を縮むことができます。 例えばこんなHTMLがあるとします。

<div id='content'></div>

$('#content').ajaxComplete(function(){
	alert('content ajax complete');
});

これならidがcontentのdivにajax通信が完了する際のコールバックを示しています。

しかしこれだけではまだ問題2を解決できません。

$.ajax(option1);
$.ajax(option2);
$.ajax(option3);
$(document).ajaxComplete(function(){
	alert('ajax complete');
});

こう書くと、任意の通信が完了したらこのajaxCompleteが呼ばれ、 ほかの二つの処理がどうなってるかはまったくわからないです。

ここで$.ajax(option)のoptionに注目しましょう。 optionにはglobalというフラグがあり、デフォルトはtrueになってます。 その役割はグローバル関数の監視対象にするかしないかです。 このフラグをfalseに設定すれば、該当のajax通信がどうなってもグローバル関数はトリガーしません。 なので、通信処理1と2のglobalフラグをfalseに設定し、最後の処理3をtrueに設定すれば、 処理3が実行完了した際、グローバルのajaxCompleteが実行されます。

改善したコードは以下になります。一部省略しました。

var option1 = {
	global: false
	// ほかのurlなどの設定
}

var option2 = {
	global: false
	// ほかのurlなどの設定
}

var option3 = {
	global: true
	// ほかのurlなどの設定
}

$.ajax(option1);
$.ajax(option2);
$.ajax(option3);
$(document).ajaxComplete(function(){
	alert('ajax complete');
});

しかし、ここで懸念事項があります。 ajax処理の間の順番はどうなるか断言できません。 つまりこういった順番で実行されたかもです。

処理1実行 処理1完了 処理2実行 処理3実行 処理3完了 グローバルの関すを呼び出す 処理2完了

軽く動作確認ではちゃんと思ったとおり1,2,3で動いていますが、 やはりその辺が気になって、やめました。

案2:ajaxをラッパーした関数を作る

$.ajax(option)のoptionにはcompleteというのがあります。 successと使い方は同じで、successは通信が成功した際実行するコールバックで、 completeは完了した際のコールバックです。

なので今回思い出したのアイディアはこのcompleteに次のajax処理を指定して、 さらにその次のajaxのcomplete optionにも後のajax処理を指定したらどうでしょうか。 尻尾をどんどん噛んでいく蛇のイメージです。

(抜粋)

var option1 = {
	complete: $.ajax(option2)
}

var option2 = {
	complete: $.ajax(option3)
}

var option3 = {
	complete: function() {
		alert('ajax all complete');
	}
}

$.ajax(option1);

動作確認でOKでした。 completeオプションで前のajax通信が必ず完了した後に次のajax通信を始まることを保障しています。 これでajaxのチェインができました。

これをちょっと綺麗にラッパーした関数を作りました。 ご覧ください。

function doOrderGuaranteedAjax(ajaxOptionArray, allCompleteHandler){
  var defaults = {
    type : "GET",
    dataType : "text",
    complete : function() {
      // 最初の要素を削除
      ajaxOptionArray.shift();
      // すべての通信が完了した場合
      if (ajaxOptionArray.length == 0 ) {
        // コールバックが設定された場合
        if (allCompleteHandler) {
          allCompleteHandler();
        }
      } else {
        // 通信配列にまだ通信が残っている場合
        option = ajaxOptionArray[0];
        // ajaxのオプションを次の通信に切り替え
        opts = $.extend({}, defaults, option);
        // 通信を開始
        $.ajax(opts);
      };
    }
  };

  // 初期指定
  var option = ajaxOptionArray[0];
  var opts = $.extend({}, defaults, option);
  // 一回のみ実行
  $.ajax(opts);
};

まず$.ajax(option)のoptionを順番でpushした配列が第一パラメータで渡されます。 2~23行まではデフォルトのoptionを構築し、一回目の処理は29行から走ります。 そしてデフォルトのoptionではcompleteで実行完了した処理を配列から削除(7行)します。 配列にまだ待ち状態の処理があるならオプションを次の通信に切り替えます(14~20行)。 もし配列にある処理が全部実行完了したら、コールバックを呼びます(9~13行)。

使い方はまずオプションを一つの配列にpushし、その配列を一番目のパラメータで、 コールバックを二番目のコールバックで渡します。

var optionArray = [];
optionArray.push(option1);
optionArray.push(option2);
optionArray.push(option3);
doOrderGuaranteedAjax(optionArray, function(){
	alert('all complete');
});

arrayのpushとshiftを利用し、スタック構造を真似してます。 push() は array の最後に配列要素を加えます。 shift() は array の最初の要素を削除します。

これでファーストイン、ファーストアウトFIFOが実現し、 処理の順番が保ちます。

#jquery

本文(英語)のアドレス: A Plugin Development Pattern » Learning jQuery - Tips, Techniques, Tutorials

結論から

まず、要点規約に沿ったソースを先頭に置きます。

  1. Claim only a single name in the jQuery namespace
  2. Accept an options argument to control plugin behavior
  3. Provide public access to default plugin settings
  4. Provide public access to secondary functions (as applicable)
  5. Keep private functions private
  6. Support the Metadata Plugin
// create closure
(function($) {
  // plugin definition
  $.fn.hilight = function(options) {
    debug(this);

    // build main options before element iteration
    var opts = $.extend({}, $.fn.hilight.defaults, options);

    // iterate and reformat each matched element
    return this.each(function() {
      $this = $(this);

      // build element specific options
      var o = $.meta ? $.extend({}, opts, $this.data()) : opts;

      // update element styles
      $this.css({
        backgroundColor: o.background,
        color: o.foreground
      });

      var markup = $this.html();
      // call our format function
      markup = $.fn.hilight.format(markup);
      $this.html(markup);
    });
  }

  // private function for debugging
  function debug($obj) {
    if (window.console && window.console.log)
      window.console.log('hilight selection count: ' + $obj.size());
  }

  // define and expose our format function
  $.fn.hilight.format = function(txt) {
    return '<strong>' + txt + '</strong>';
  }

  // plugin defaults
  $.fn.hilight.defaults = {
    foreground: 'red',
    background: 'yellow'
  }
// end of closure
})(jQuery);

解読

1. Claim only a single name in the jQuery namespace

  • 目的:jQueryの名前空間にファンクション(メソッド)を一つのみ追加。

プラグイン目的の純粋化と思われます。

  • 実装例
// プラグインの宣言
$.fn.highlight = function() {
  // Our plugin implementation code goes here.
}
  • 使い方:
$('#myDiv').highlight();

以下はよくないパターンです。こうするなら二つのプラグインに分けるか、目的をもっと明確にしろうってことです。

  • 実装例
$.fn.oneFunction= function() {};
$.fn.anotherFunction= function() {};

2. Accept an options argument to control plugin behavior

  • 目的:オプションをつけることでより柔軟なAPIをユーザに提供
  • 実装例
// プラグインの宣言
$.fn.highlight = function(options) {
  var defaults = {
    foreground: 'red',
    background: 'yellow'
  }
  // Extend our default options with those provided.
  var opts = $.extend(defaults, options);
  // Our plugin implementation code goes here.
}
  • 使い方
$('#myDiv').highlight({
  foreground: 'blue'
});

3. Provide public access to default plugin settings

  • 目的:デフォルトの設定を変更できるようにする。
  • 実装例
// プラグインの宣言
$.fn.highlight = function(options) {
  // Extend our default options with those provided.
  // Note that the first arg to extend is an empty object -
  // this is to keep from overriding our "defaults" object.
  var opts = $.extend({}, $.fn.highlight.defaults, options);
  // Our plugin implementation code goes here.
}

// plugin defaults - added as a property on our plugin function
$.fn.highlight.defaults = {
  foreground: 'red',
  background: 'yellow'
}
  • 使い方:全体のデフォルト設定を変更することもできるし、個別にオーバーライドすることも可能
// override plugin default foreground color
$.fn.highlight.defaults.foreground = 'blue';
// ...
// invoke plugin using new defaults
$('.highlightDiv').highlight();
// ...
// override default by passing options to plugin method
$('#green').highlight({
  foreground: 'green'
})

4. Provide public access to secondary functions (as applicable)

  • 目的:プラグイン開発者、または使い側がより簡単に拡張できる
  • 方法:jQueryの名前空間に登録したファンクションにプロパティとして一個追加することで実現可能です。
  • 実装例:

例えば文字列をフォーマットするファンクション”format”があるとします。 ここでは単純に強調表示するだけですが、誰でも簡単に変更できます。

// プラグインの宣言
$.fn.highlight = function(options) {
  // iterate and reformat each matched element
  return this.each(function() {
    var $this = $(this);
    // ...
    var markup = $this.html();
    // call our format function
    markup = $.fn.highlight.format(markup);
    $this.html(markup);
  });
}

// define our format function
$.fn.highlight.format = function(txt) {
  return '<strong>' + txt + '</strong>';
}

5. Keep private functions private

  • 目的:単純にprivateなファンクションをprivate化にするだけ
  • 方法:javascriptのクロージャで全体を囲む
  • 実装例:
// create closure
(function($) {
  // プラグインの宣言
  $.fn.highlight = function(options) {
    debug(this);
    // ...
  };

  // private function for debugging
  function debug(obj) {
   if (window.console && window.console.log)
     window.console.log('highlight selection count: ' + obj.size());
   }
   //  ...
// end of closure
})(jQuery);

6. Support the Metadata Plugin

Plugins/Metadata/metadata - jQuery Wiki

  • 目的:

これはMetadataというプラグインがあるそうで、 なおかつたくさん人が使っていることを前提(或いは現状)としたため、 自分が作ったプラグインはMetadataにも対応するべきという結論になったわけです。

  • TODO:

私もまだMetadataプラグインが何か全然わからないため、 ここはTODOとして残します。