jQueryの基礎

よく使うようになった JavaScript ライブラリの jQuery を簡単に紹介。

jQueryの使い方

まず jQueryをダウンロードして利用する html でロードするようにします。そして、CSSクラスやCSS ID に対して動作させたい内容(アクション)を関数で定義します。どのように jQuery が動作するか簡単な図を以下に示します。

jQuery

この例では、"ボタン"リンクがクリックされたら、隠れている"panel"をスライド表示されるものです。

実際の動作例:

こんにちは

↓ボタン

$()関数

jQuery のもっとも基本となる操作は $() 関数を利用することです。この関数で操作したい対象を選び、様々な操作を行うことができます。$()指定方法は、CSSとXPathどちらでも利用できます。

指定場所(セレクタ) 概要
タグ

HTMLタグに対してアクションを指定します。

$("ul").append("<li>リスト1</li>");
ID CSS IDに対しては、ID名に # をつけてアクションを指定します。 $("#my_target").load("/path/to/data.php");
クラス CSSクラス対しては、クラス名に . をつけてアクションを指定します。 $(".my_class").css("border","2px solid blue");

$() 関数に指定できるのは、単一のタグだけでなく、 $("form#login") のように IDである login を持つ formタグに対してという具合に細かく指定していくことも可能です。

CSS Selector jQuery/CSS Syntax mean
タグ $("p") "p"タグを選択
ID $("#myId") "myId" IDを選択
クラス $(".myClass") "myClass"クラスを選択
属性選択 $("p[style]") "p"タグの属性"style"を選択
CSS3 属性選択 $("a[href^='http:']")
$("a[href$='pdf']")
$("div[style*='border']")
属性"href"が"http:"で始まる"a"タグを選択
属性"href"が"pdf"で終わる"a"タグを選択
属性"style"が"border"を含む"div"タグを選択
子孫要素の選択 $(".myClass span") ".myClass"クラス以下のすべての "span"タグを選択
小要素の選択 $(".myClas > span") ".myClass"クラス直下(子のみ)のすべての "span"タグを選択
隣接した兄弟選択 $(".myClas + span") ".myClass"クラス直後の "span"タグを選択
兄弟選択(CSS3) $(".myClas ~ span") ".myClass"クラス後のすべての "span"タグを選択
一番始めの要素 $("li:first") 一番始めの"li"タグを選択
一番最後の要素 $("li:last") 一番最後の"li"タグを選択
偶数要素 $("li:even") 偶数番目の"li"タグを選択
奇数要素 $("li:odd") 奇数番目の"li"タグを選択

アクションの追加(イベント・ハンドラの登録)

$("セレクタ").API名([引数や関数]);

セレクタに対してAPIを指定することで、セレクタに対してアクションを設定することができます。APIは、マウスの操作やキーの操作であるイベントであったり、HTMLやCSSスタイルを追加する操作であったり、動きのあるアニメーションを付加するものです。

APIは数多く用意されており、jQueryのドキュメントを参考にしてください。

$("a.myClass").click(function(){
    alert("CLICK!");   // myClassクラスのアンカーがクリックされるとアラートが表示される
    return false;       // 元のアンカーの遷移する機能を無効にする
}

イベントの追加・削除を整序したいなら、bind/unbindを利用できます。このとき "click"や "submit"などの元々の動作をキャンセルするには、戻り値を falseにします。

$("a").bind("click", function(){
    alert("BIND!");
    return false;
});

しかし bind では、登録時にマッチした要素しかイベントハンドラを追加することができません。もし、永続的に要素にマッチさせたい場合は liveを利用します。

$("li").live("click", function(){
    alert("LIVE!");
});

たとえば、li要素に対して clickイベントを登録した場合、bindではその時点でページ上に存在する li要素に対してのみクリックイベントが登録されるが、liveではその後に動的に追加された li要素に対しても同一のクリックイベントが付加されます。

JavaScript部

JavaScriptコード部分を記述する場合、HTMLが読み込み終わった後で必要なイベントを設定しなければなりません。通常の JavaScript で onLoad イベントに相当する記述を jQuery では $(document).ready(function(){})を利用します。onload の場合は、ページの全てのもの(画像も含む)が読み込まれるまで実行されません。しかし、$(document).ready(function(){})を利用すると、HTMLドキュメントの準備が出来た段階(DOMが構築完了)で 実行させることが可能となります。

$(document).ready(function(){
    // ここに処理を記述します
});

この関数は、必要な回数だけ何度でも呼び出すことができます。また、新しいバージョンの jQueryでは以下のようにショートカットで記述できます。

$(function(){
    // ここに処理を記述します
});

これら jQuery の ready関数を用いたイベント処理では不都合があり、onLoadイベントとおなじ動作をさせたい場合には以下のように記述します。

$(window).load(function() {
  // ここに処理を記述します
});

Ajax

jQueryでは、Ajax に関する部分においても簡単な処理で実現することができます。その中でも最も使われる二つを紹介します。

リクエスト 概要

$.ajax( options );

ローレベルの XMLHttpRequestを jQueryで実装したもので XMLHttpRequestオブジェクトを返します。オプションを利用することで、XMLHttpRequestで行える細かい設定を指定できます。

$("#foo").load( url, [data], [callback] ); 指定した対象となるオブジェクト(#foo)の内容を、ロードした内容(HTML)に差し替えます。はじめの引数に URL を指定します。はじめの URL にパラメータを記述すれば GETによる通信。2番目に引数に JSON形式でURLに必要なパラメータを指定すると POSTによる通信となります。2または3番目にコールバック関数を記述でき、ロードが完了した時点で実行される処理を記述できます。2,3番目のパラメータは、必要がなければ省略可能です。

※ 基本的に XMLHttpRequestによる通信では同一生成元ポリシー(Same-Origin)というセキュリティの概念があります。よって、ここで指定する URL と 呼び元のHTMLページは同じドメインとなります。(これを回避するには、JSONPを利用)

ajax関数を利用する場合の記述例:

$.ajax({
    type: "GET",
    url: "/path/to/some_api.php",    // 呼び出すAPI
    data: "start=1&range=50",        // APIが受付けるパラメータ
    dataType: "xml",                 // APIが出力するデータのタイプ
    timeout: 1000,                   // タイムアウトする時間 (ms)
    success: function(xml){          // APIをコールし成功した際の処理
        $(xml).find("item").each(function(){                // XML内の itemタグを検索
            var item_text = $(this).text();                 // 中のテキストを取得
            $("<li></li>").html(item_text).appendTo("ol");  // olタグに li として追加
        });
    },
    error: function(){               // APIをコールし失敗した際の処理
        alert( "API call error" );
    }
});

load関数を利用する場合の記述例:

$("#loaded_area").load("/path/to/api.cgi?key=f1&start=1");          // GET
$("#loaded_area").load("/path/to/api.cgi", { key:"f1", start:1});   // POST

※ API が出力するデータに漢字コードが含まれている場合、そのコードがどんなフォーマットであるかきちんと明示しておかないと受け取った側で文字化けすることがあります。きちんとヘッダーを出力しておきましょう。たとえば、API が 漢字コード UTF-8 で PHP にて作られているような場合、以下のように header関数利用して charset等を出力する。

<?php
header("Content-Type: text/html; charset=utf-8");
echo $sBuff;
?>

DOM操作

* 要素へのCSSクラスの操作

$('#myelement').addClass('myclass');       /* クラスの追加 */
$('#myelement').removeClass('myclass');    /* クラスの削除 */
$(this).hasClass(class);                   /* クラスの存在チェック */

* 要素の操作

$('#myid').append('sometext');            /* HTMLの追加 */
if ($('img').length) {                    /* 要素の存在チェック */
    log('"img"タグが存在しています');
} else {
    log('"img"タグは見つかりませんでした');
}
var id = $("button").closest("div").attr("id");    /* 要素の親要素を取得 */

プラグイン

jQuery のプラグインの作り方と利用方法

/* フラグイン定義 */
;(function($) {

$.fn.pluginName = function(options) {              /* プラグイン名 */
    options = jQuery.extend({                      /* オプションデフォルト値設定 */
        showDialog: false,
        color: '#ffffff'
    }, options);

    function initialize() {                        /* 機能を関数ごとに記述していっても */
        if (options.showDialog) {                  /* 動作をそのまま記述してもよい */
            // ダイアログ有効
        }
        ...
    }
    return this.unbind('click').click(initialize); /* 要素をクリックしたら動作する */
};

}) (jQuery);

/* プラグインの利用 */
$(function() {
    $('#myId').pluginName();                       /* オプションデフォルト利用 */
    $('.myClass').pluginName({                     /* オプション指定利用 */
        "showDialog":true
    });
});

最適化とTIPS

jQuery を利用したコードが効率よく動作するための注意点。FirebugのConsole APIを使って時間を計ってみます。
Improve your jQuery - 25 excellent tipsを参考

Firebug

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>jQuery Test</title>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">google.load("jquery", "1.2");</script>
</head>
<body>
<div class="myClass"></div>
</body>
</html>
console.time('append list');
for (i = 0; i < 1000; i++) {
    $('.myClass').append('<li>Item' + i + '</li>');
}
console.timeEnd('append list');

* セレクタの検索方法

セレクタを何度も検索するより、一度検索したら変数に格納しておくとよい。

for (i = 0; i < 1000; i++) {
    $('.myClass').append('<li>Item' + i + '</li>');  
}

よりも、以下のようにマッチしたエレメントを変数に格納して利用した方が速い。

var myClass = $('.myClass');
for (i = 0; i < 1000; i++) {
    myClass.append('<li>Item' + i + '</li>');  
}

* DOMを操作する関数の利用

.append() .prepend() .after() や .wrap() といった DOMを操作するメソッドの利用を最小限にする。

var myClass = $('.myClass');
for (i=0; i<1000; i++){
    myClass.append('<li>Item' + i + '</li>');
}

よりも、以下のように文字列として HTMLを作成しておき、最後に .html()メソッドで追加した方が速い?ちょっとこれは、バッファとして格納するデータ量にも左右される?

var myClass = $('.myClass');  
var myClassItems = '';  
for (i = 0; i < 1000; i++) {  
    myClassItems += '<li>Item' + i + '</li>';  
}  
myClass.html(myClassItems);

* IDの利用

クラスを利用するよりも IDを利用する。

// Create our list
var myClass = $('.myClass');
var myClassItems = '<ul>';
for (i = 0; i < 1000; i++) {
    myClassItems += '<li class="listItem' + i + '">This is a list item ' + i + '</li>';
}
myClassItems += '</ul>';
myClass.html(myClassItems);
 
// Select each item once
for (i = 0; i < 1000; i++) {
    var selectedItem = $('.listItem' + i);
}

class による実装よりも、以下のように IDを利用したほうが速い。

// Create our list
var myClass = $('.myClass');
var myClassItems = '<ul>';
for (i = 0; i < 1000; i++) {
    myClassItems += '<li id="listItem' + i + '">This is a list item ' + i + '</li>';
}
myClassItems += '</ul>';
myClass.html(myClassItems);
 
// Select each item once
for (i = 0; i < 1000; i++) {
    var selectedItem = $('#listItem' + i);
}

* セレクタを検索するなら検索範囲を指定

セレクタを検索するなら検索範囲を指定したほうが速い。第2引数にコンテキストとして検索範囲を指定する。

var selectedItem = $('#listItem' + i, $('.myClass'));

* チェーンメソッドを利用

セレクタに対して何度もメソッドを実行する場合、順番につなげて書いていくことができる。

$('myDiv').removeClass('off').addClass('on');

.find()と .end()を利用することで異なる要素に異なるメソッドを実行できる。

$('#myTable')
  .find('.firstColumn')
    .css('background','red')
  .end()
  .find('.lastColumn')
    .css('background','blue');

チェーンメソッドを定義することもできる。

$.fn.makeRed = function() {
	return $(this).css('background', 'red');
}
 
$('#myTable').find('.firstColumn').makeRed().append('hello');

* eventを効率よく利用

jQueryはイベントの追加が簡単です。しかし、むやみにイベントを割り当てるのは非効率です。例えば、テーブルの各セルにクリックイベントを割り当てる。この場合、5行 10列 のテーブルでは 50個のイベントが割り当てられます。

$('#myTable TD').click(function(){
  $(this).css('background', 'red');
});

しかし以下のようにテーブルに対してどのセルがクリックされたのかを調べてスタイルを設定するほうが効率よく実装することができる。

$('#myTable').click(function(e) {
  var clicked = $(e.target);
  clicked.css('background', 'red');
});

* classにスタイルを設定しておき .removeClass() や .addClass() で切り替え

スタイルを設定したクラスを用意しておき、.hasClass()メソッドで存在確認後 .removeClass() や .addClass()メソッドで切り替え可能なフラグとして利用する。

<div class="menuItem expanded">
  <div class="button">click me</div>
  <div class="panel">
    <ul>
    <li>Menu item 1</li>
    <li>Menu item 2</li>
    <li>Menu item 3</li>
    </ul>
  </div>
</div>

クラス .button がクリックされるとパネルが開閉するスクリプト

$('.button').click(function() {
  var menuItem = $(this).parent();
  var panel = menuItem.find('.panel');
  if (menuItem.hasClass("expanded")) {
    menuItem.removeClass('expanded').addClass('collapsed');
    panel.slideUp();
  }
  else if (menuItem.hasClass("collapsed")) {
    menuItem.removeClass('collapsed').addClass('expanded');
    panel.slideDown();
  }
});

さらに、上記のようにHTMLにclassなどを追加して操作するのではなく、.data()メソッドを利用すると効率かつシンプル。

* SEO対策に利用

HTMLは、SEOに効果的なレイアウトだが非常にシンプルに記述しておき、飾りつけは jQueryを利用してHTMLを修正する。

また、google mapの埋め込みやフォーム、注意事項などはloadメソッドを利用して非同期で読み込む。

* 他のライブラリと共存する場合、noconflict設定を行う

多くのJavaScriptライブラリ(prototype.jsなど)で$というオブジェクトを利用しています。jQueryではnoconflict設定を行うことによって$を違うオブジェクト名に変更できます。

var $j = jQuery.noConflict();
$j('#myDiv').hide(); 

ただし、$が完全に別のライブラリの動作になってしまうのは、jQueryで既に存在しているコードを利用したい場合などには不都合が生じます。そこで、$ をready内ではjQueryの動作をさせるといったことが可能です。

<script>
<!--
jQuery.noConflict();
jQuery(document).ready(function($){
  // ここでは、$はjQueryのオブジェクトとして動作
});
// ここでは、$は別のライブラリのオブジェクトとして動作
//-->
</script>

* 画像の読み込み完了を調べる

画像の読み込みが完了してから何かアクションを起こしたい場合、load()メソッドを利用する。

$('#myImage').attr('src', 'image.jpg').load(function() {
  alert('Image Loaded');
});

* 画像の Pre-Loading

画像をあらかじめ読み込んでおく方法

// 定義
jQuery.preloadImages = function() {
    for(var i = 0; i<arguments.length; i++) {
        jQuery("img").attr("src", arguments[i]);
    }
};
// 利用
$.preloadImages("image1.gif", "/path/to/image2.png", "some/image3.jpg");

* カラムの高さをそろえる

それぞれのカラムの最大を調べて設定する。

var max_height = 0;
$("div.column").each(function(){
  if ($(this).height() > max_height) {
    max_height = $(this).height();
  }
});
$("div.column").height(max_height);

* URLパラメータを取得

URLパラメータを取得します。

$.urlParam = function(name){
  var results = new RegExp('[\\?&]' + name + '=([^&#]*)').exec(window.location.href);
  if (!results) {
    return 0;
  }
  return results[1] || 0;
}
$.urlParams = function(){
  var vars = [], hash;
  var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
  for(var i = 0; i < hashes.length; i++) {
    hash = hashes[i].split('=');
    vars.push(hash[0]);
    vars[hash[0]] = hash[1];
  }
  return vars;
}

* 要素が存在するかチェックする方法

確実な方法ではないけれど。。。。

if ($('#myDiv').length) {
  alert("has myDiv");
}

* 初期の挙動を止めるために return false

以下のように アンカータグにアクションを設定する場合、href="#"のためにページ上部にジャンプしてしまいます。これを防ぐために "return false" で戻るように関数を定義する。

<a href="#" class="popup">Click me!</a>
$('popup').click(function(){
  // Launch popup code
  return false;
});

さいごに

ここで紹介したのはほんの一部で基本的な部分だけです。jQuery ではもっとたくさんの機能が用意されているのでドキュメントを参考にしてください。また数多くの plug-in が用意されており多くの機能を利用することができます。