2009年11月28日 #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)

2009年11月27日 #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

2009年11月23日 #jquery

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

目次は以下になります。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

勉強メモ

text()とhtml()の違い

(1)取得する対象

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

(2)取得する内容

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

(3)対応する形式

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

http://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"; }); }); ```

2009年11月23日 #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..


<h4>属性フィルタの組み合わせ</h4>
<p>[filter][filter]……のように複数を連続して記述することもできます。この場合、すべての属性フィルタに合致する要素だけが取り出されます。</p>
<h4>htmlの組み立て</h4>
<h5>ハードコードで書く</h5>

```js
$(select).append("<option value='" + 1 + "'>text</option>");
jQueryの関数を用いて書く
$(select).append($('<option>').attr({ value: 1 }).text("text"));

このほうが簡潔だと思いますが、、

:nth-child

:nth-childフィルタによりn行おきに子要素を取得することができる

例えば、2、5、8行目……のように3行おきに(「3で割ったときの余りが2」番目の)要素を取得したい場合には、以下のように記述できます。

$('ol > li:nth-child(3n + 2)')


validationプラグイン

jQueryのvalidationプラグイン:showErrorを定義するとhighlightとunhighlightとは実行しない

そもそもshowErrorはエラーをどう表示するかを決めるための高レベルの関数なので、

簡略化したhighlightとunhighlightは隠蔽されたっぽいの感じで、完全に実行しません。

2009年11月22日 #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

2009年11月15日 #jquery

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

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

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

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


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

ほとんど簡単な単語で

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

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

と感じました。

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

しか入りません。

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

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

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

落とし穴だと思います。


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

第1回 セレクタ編 - @IT

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

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

2009年11月11日 #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サイト

2009年11月11日 #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サイト

2009年11月 4日 #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があるのですが、これは簡単に言うとこの要素が必須項目となるのはある前提がある意味です。


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

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

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

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


参考となったサイト:

2009年11月 1日 #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をマージ、拡張したものとなります。