jQuery でファイルをインクルードする ( jQuery によるモジュール化)

jQuery でシンプルにファイルをインクルードする

通常のスタティックな Web サイトにおいて、Web ページの中で更新頻度の高いパーツを別ファイルにして、それをインクルードするシーンは多々あるかと思います。

Movable Type でも、モジュールやウィジェットを「インデックステンプレートのコンテキストで全ページに表示させたい」なんてとき、インデックステンプレートに読み込み用のファイルを作って、それを MTInclude で読み込むという手法で実現するのが一般的だと思います。

さて、ファイルを読み込む方法には、大きく分けると、サーバーサイドインクルード( SSI )とクライアントサイドインクルード( CSI )、がありますが、今回は後者の「クライアントサイド」で読み込む方法を jQuery を使ってやってみました。

いわゆる「 jQuery によるモジュール化」と言ったところです。

jQuery でのファイルの読み込みは、「Movable Type 備忘録 - jQuery でカンタンに外部ファイルを読込む(jquery.inc)」で紹介されている便利な jQuery プラグインを使う手もあります。手軽で便利なので試してみてください。

ただ、僕が使ったときは、ちゃんと UTF-8 で保存したのになぜか IE 6 で表示すると日本語が文字化けしてしまいました。なんで? また、インクルードしたファイルは、インクルードを指定した要素の子要素としてしか読み込めないようなので、ウィジェット部分の dt、dd 要素だけを読み込みたいときにはちょっと困りました。

そこで、今回は自分的にもう少し使いやすくした jQuery_inc.js を作ってみました。

メリット

この JavaScript のメリットをいくつかあげてみます。

複数のモジュール(パーツ)を 1 ファイルで管理

1 つのファイルから、読み込むモジュールをCSS セレクタのように指定するので、複数のパーツを 1 ファイルにまとめて管理できます。

1 モジュール = 1 ファイルだと、数が増えてくると管理が大変になります。その点、全てのモジュールを 1 ファイルにまとめられれば管理が楽です。

文字化けしない(と思う)

XHTML ファイルにまとめることで、head 要素内で文字コードも宣言するので、IE でも文字化けしないと思います。

モジュール用のファイルを作らなくても可能

極端な話、モジュール用のインデックステンプレートすら作らなくても良くなります。メインインデックス( index.html )からインクルードするという荒業も可能です。お勧めしませんが。。

読み込み元の要素を、読み込んだ要素で置換可能

「<div class="読み込み元"><p>ここに読み込む</p></div>」

のように子要素に読み込むだけでなく、

<div class="読み込み元"></div><p>ここに読み込む</p>

のように読み込み要素と置換することも可能です。

この柔軟性のおかげで、valid なソースを書きやすくなります。

読み込む要素を CSS セレクタなどで指定

モジュール用ファイルを編集しなくても、読込先を指定するセレクタを変更すれば、読み込む要素を変えられます。

完成したソース

/*
 * jQuery_inc.js
 *
 * Copyright (c) 2008 Tomohiro Okuwaki (http://www.tinybeans.net/blog/)
 * Licensed under the MIT License:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Modified: 2008-11-10
 * Document: http://www.tinybeans.net/blog/2008/11/10-173717.html
 *
 */
function strRef (text) {
	text = text.replace(/&amp;/g,'&');
	text = text.replace(/&lt;/g,'<');
	text = text.replace(/&gt;/g,'>');
	text = text.replace(/&quot;/g,'"');
	return text;
}
jQuery(document).ready(function(){
	jQuery('.jquery_inc').each(function(){
		var inc_url = '/jquery_inc.html';   /* <== Edit it first */
		var inc_selector = jQuery(this).attr('title');
		var replace_inc = jQuery(this).filter('.replace_inc').size();
		var file_inc = jQuery(this).filter('.file_inc').size();
		var child_inc = jQuery(this).filter('.child_inc').size();
		inc_selector = strRef(inc_selector);
		if (jQuery.browser.msie) {
			/* for IE [start] */
			if (file_inc) {
				inc_selector = inc_selector.replace(/ ?/,':');
				inc_selector = inc_selector.split(':');
				inc_url = inc_selector[0];
				inc_selector = inc_selector[1];
			}
			if (child_inc) {
				var matchStr = inc_url.match(' ');
				if (matchStr) {
					inc_selector = inc_selector + '>*';
				}
			}
			jQuery.ajax({cache: false});
			if (replace_inc) {
				jQuery(this).load(
					inc_url,
					function () {
						var default_content = jQuery(this).clone();
						var inc_content = default_content.find(inc_selector);
						jQuery(this).replaceWith(inc_content);
					}
				);
			} else {
				jQuery(this).load(
					inc_url,
					function () {
						var default_content = jQuery(this).clone();
						var inc_content = default_content.find(inc_selector);
						jQuery(this).html(inc_content);
					}
				);
			}
			/* for IE [ end ] */
		} else {
			if (file_inc) {
				inc_url = inc_selector;
			} else {
				inc_url = inc_url + ' ' + inc_selector;
			}
			if (child_inc) {
				var matchStr = inc_url.match(' ');
				if (matchStr) {
					inc_url = inc_url + '>*';
				}
			}
			jQuery.ajax({cache: false});
			if (replace_inc) {
				jQuery(this).load(
					inc_url,
					function () {
						var default_content = jQuery(this).clone();
						var inc_content = default_content.html();
						jQuery(this).replaceWith(inc_content);
					}
				);
			} else {
				jQuery(this).load(inc_url);
			}
		}
	});
});

このソースをコピーして保存するか、以下よりダウンロードしたファイルを解凍して保存します。

ダウンロード

jquery_inc.js の使い方

ここでは、Movable Type で使う場合を例に説明しますが、もちろん普通の Web サイトでも同様の考え方で使えます。

モジュール用ファイル(インデックステンプレート)の作成

まず初めに、モジュール用ファイルを作成しておきましょう。Movable Type の場合、モジュールとして読み込みたい部分をまとめてインデックステンプレートとして作成すればOKです。

ここでは、「Recent Comments (最近のコメント)」と「Recommended (オススメ)」をモジュール化してみます。

なお、読み込むファイルをできるだけ軽くするために、余計な要素は排除してシンプルにしましょう。また、以下の例では、検索ロボットは一応拒否しています。

テンプレートのデータ
  • インデックステンプレート
  • 出力ファイル名 : jquery_inc.html
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja" dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>jQuery Include - <$mt:BlogName$></title>
<meta name="ROBOTS" content="NONE" />
</head>
<body>
<dl id="wdg_include">
<dt>Recent Comments</dt>
<dd class="recentComments"><ul class="recentComments"><mt:Entries recently_commented_on="5">
<li><a href="<$mt:EntryLink$>"><$mt:EntryTitle$></a>
	<ul><mt:Comments>
	<li><a href="<mt:CommentEntry><$mt:EntryLink$></mt:CommentEntry>#comment<$mt:CommentID$>" title="<mt:SetVarBlock name="commentBodyCount"><$mt:CommentBody count_characters="1"$></mt:SetVarBlock><mt:If name="commentBodyCount" gt="50"><$mt:CommentBody remove_html="1" encode_html="1" trim_to="50" cat="..." regex_replace="/\n|\r\n/g",""$><mt:Else><$mt:CommentBody remove_html="1" encode_html="1"$></mt:If>" rel="nofollow"><mt:IfNonZero tag="CommentAuthor"><$mt:CommentAuthor$><mt:Else>No Name</mt:IfNonZero> - <$mt:CommentDate format="%m/%d"$></a></li></mt:Comments>
	</ul></li></mt:Entries>
</ul></dd>
<dt>Recommended</dt>
<dd class="recommended">
<p><a href="http://getfirefox.jp/"><img src="<$mt:BlogURL$>img/banner/firefox_125x125_rounded_blue.png" alt="Mozilla Firefox ブラウザ無料ダウンロード" title="Mozilla Firefox ブラウザ無料ダウンロード" width="125" height="125" /></a></p>
</dd>
</dl>
</body>
</html>

再構築したファイルは次のようになります。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja" dir="ltr">
<head>
<meta name="ROBOTS" content="NONE" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>jQuery Include - かたつむりくんのWWW</title>
</head>
<body>
<dl id="wdg_include">
    <dt>Recent Comments</dt>
    <dd class="recentComments">
        <ul class="recentComments">
            省略
        </ul>
    </dd>
    <dt>Recommended</dt>
    <dd class="recommended">
        <p><a href="http://getfirefox.jp/"><img src="http://www.tinybeans.net/blog/img/banner/firefox_125x125_rounded_blue.png" alt="Mozilla Firefox ブラウザ無料ダウンロード" title="Mozilla Firefox ブラウザ無料ダウンロード" width="125" height="125" /></a></p>
    </dd>
</dl>
</body>
</html>

以下の説明で出てくるサンプルも、基本的にこのモジュール用ファイルからインクルードすることにします。

jquery_inc.js の初期設定

jquery_inc.js の 22 行目当たりのファイルのパスを、作成したモジュール用ファイルのパスに変更します。

var inc_url = '/jquery_inc.html';   /* <== Edit it first */

jQuery などの読み込み

jquery_inc.js をサーバーにアップロードし、jQuery とともに読み込みます。ファイルへのパス部分は適宜変更してください。ここでは jQuery は 「AJAX Libraries API - Google Code」を使って読み込んでいます。

<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">google.load("jquery", "1.2");</script>
<script type="text/javascript" src="/js/jquery_inc.js" charset="UTF-8"></script>

読み込みたい場所に title 属性、class 属性を設定

インクルードしたい場所のソースに、以下のような title 属性、class 属性を設定します。

title 属性(必須)

モジュール用ファイルの読み込みたい要素を jQuery のセレクタで指定します。jQuery のセレクタについては、次のページが参考になります。シンプルな CSS セレクタなら、ほぼそのまま使えます。

なお、< > & などは実体参照にすることを忘れずに。

jquery_inc クラス(必須)

jquery_inc.js を使ってモジュールを読み込みたい要素に設定します。必須です。

<Element class="jquery_inc" title="selector"> ~ </Element>

【サンプル】 dd.recommended 内の p 要素をインクルート

[読み込みたいソースは次の p 要素]
<dd class="recommended">
    <p><a href="http://getfirefox.jp/"><img src="http://www.tinybeans.net/blog/img/banner/firefox_125x125_rounded_blue.png" alt="Mozilla Firefox ブラウザ無料ダウンロード" title="Mozilla Firefox ブラウザ無料ダウンロード" width="125" height="125" /></a></p>
</dd>
[読み込みたい場所のソース]
<div class="jquery_inc" title="#wdg_List_RecentComments dd.recommended p">
    ここに読み込みます
</div>
[読み込み後のソース]
<div class="jquery_inc lastChild" title="#wdg_List_RecentComments dd.recommended p">
    <p><a href="http://getfirefox.jp/"><img src="http://www.tinybeans.net/blog/img/banner/firefox_125x125_rounded_blue.png" alt="Mozilla Firefox ブラウザ無料ダウンロード" title="Mozilla Firefox ブラウザ無料ダウンロード" width="125" height="125"></a></p>
</div>

child_inc クラス(オプション)

title 属性で指定した要素の「子要素」をインクルードしたい場合に設定します。

<Element class="jquery_inc child_inc" title="selector"> ~ </Element>

一つ手前のサンプルでは、セレクタで dd.recommended の子要素の p 要素まで指定しましたが、child_inc クラスをつければ少しシンプルになります。

[セレクタで指定]
<div class="jquery_inc" title="#wdg_include dd.recommended p">
[child_inc クラスで指定]
<div class="jquery_inc child_inc" title="#wdg_include dd.recommended">

このように子要素が一つのときは無意味に思えるかもしれませんが、dl 要素の子要素の dt、dd 要素など、複数の子要素をまとめてインクルードしたいときに威力を発揮します。

replace_inc クラス(オプション)

インクルードしたい場所の要素を、インクルードした要素と置き換えます。

<Element class="jquery_inc replace_inc" title="selector"> ~ </Element>

【サンプル】 span.test を dd.recommended 内の p 要素と置換

[読み込みたいソースは次の p 要素]
<dd class="recommended">
    <p><a href="http://getfirefox.jp/"><img src="http://www.tinybeans.net/blog/img/banner/firefox_125x125_rounded_blue.png" alt="Mozilla Firefox ブラウザ無料ダウンロード" title="Mozilla Firefox ブラウザ無料ダウンロード" width="125" height="125" /></a></p>
</dd>
[読み込みたい場所のソース]
<dl>
    <dt>Recommended</dt>
    <dd class="recommended">
        <span class="test jquery_inc replace_inc" title="dd.recommended p">ここに読み込みます</span>
    </dd>
</dl>
[読み込み後のソース]
<dl>
    <dt>Recommended</dt>
    <dd class="recommended lastChild">
        <p><a href="http://getfirefox.jp/"><img src="http://www.tinybeans.net/blog/img/banner/firefox_125x125_rounded_blue.png" alt="Mozilla Firefox ブラウザ無料ダウンロード" title="Mozilla Firefox ブラウザ無料ダウンロード" width="125" height="125"></a></p>
    </dd>
</dl>

file_inc クラス(オプション)

通常は、最初に設定した一つのファイルからモジュールをインクルードしますが、file_inc クラスをつけると、別のファイルからインクルードすることができます。その場合、title 属性を「(読み込みたいファイルの URL ) + (半角スペース) + (セレクタ)」と記述します。

<Element class="jquery_inc file_inc" title="URL selector"> ~ </Element>

【サンプル】 トップページの最新記事タイトルをインクルード

[読み込みたい場所のソース]
<p>最新の記事 : <span class="jquery_inc replace_inc file_inc" title="http://www.tinybeans.net/blog/ #primary h2 a:first">最新記事を読み込みます</span></p>
[読み込み後のソース]
<p>最新の記事 : <a href="http://www.tinybeans.net/blog/2008/11/05-124152.html">ブログ記事を「公開した日時」を自動的にカスタムフィールドで保存するカスタマイズ</a></p>

SEO 対策や JavaScript オフ時の対応

この jQuery を使ったインクルードは、読み込み後のコンテンツがソースに反映されていないため、SEO 的に若干問題があるかもしれません。また、JavaScript がオフの状態だと、全く機能しなくなります。

しかし、replace_inc クラスを使えば、読み込みたい場所のソースを丸々置換できるので、代替コンテンツを入れておくことが可能です。

例えば、Movable Type の場合、全ページに同じ「インデックステンプレートのコンテキストの最新のブログ記事」を表示したいけど、保険として「ブログ記事コンテキスト(カテゴリごと)の最新のブログ記事」を表示させておく、などの方法が可能です。

参考文献など

jQuery について本で勉強したい場合は、以下の書籍がお勧めです。

以上です。

  • このエントリーをはてなブックマークに追加
Just a second...