jquery jQuery load() を使って別のページの見出しを表示する

2015年5月16日

jQuery の load() を使って同じサイト内の別のページの見出しを表示する方法に関するメモ。load() の基本的な使い方等についても再度メモ。

目次

load() の概要

書式

$(ターゲット要素).load(url, parameters, callback)

パラメータと戻り値

url (String)
要求を送信するサーバ側リソース(読む込むデータ)のURL。
オプションとして jQuery セレクタを使い(指定して)取得したいインスタンスを絞り込める 。(後述
parameters (String|Object|Array) 
オプション。
リクエストと一緒に送信するデータ(要求のパラメータとして渡すべきデータ)を指定。
callback (Function) 
オプション。
取得したデータがロードされた後に呼び出されるコールバック関数。
この関数に渡されるパラメータは、
・response:応答テキスト(取得したファイルのテキスト)、
・status:ステータス文字列(success、 error、notmodified、timeout、parsererror)、
・xhr:XMLHttpRequest インスタンス。
この関数はマッチしている各要素それぞれで呼び出され、ターゲットの要素集合(それぞれの DOM 要素)が関数のコンテクスト(this)になる。
$('#some_id').load('xyz.html', function(response, status, xhr) {  
  処理      
});
//第2引数(parameters)を省略した場合
戻り値
ラップ集合

セレクタを指定するには、URLの後に、1個のスペースに続けてセレクタを記述。例えば、取得するデータにフィルタをかけて id=”side” の div 要素だけを #some_id に注入したい場合は、次のように記述。

$('#some_id').load('samples/sample1.html div#side');

利用時の制限

  • 文字コードは、原則として「UTF-8 」を使用。
  • (Ajax では)セキュリティ上の理由から、その HTML と同一ドメイン上にあるファイルしか取得できない。

別のページの見出しを抽出してみる

取り合えず、別のページ(sample1.html)の見出しを抽出してみる。以下のページの div 要素(#content)内の見出し要素を抽出して表示。

見出しを抽出する別ページ(sample1.html)のHTML

<html lang="ja">
<head>
・・・中略・・・
</head>
<body>
<div id="header">
  <h1>Web Desing Leaves</h1>
</div>
<div id="container">
  <div id="content">
    <h2>Web サイト作成入門</h2>
    <h3>Web について</h3>
    <h4>Web ページ</h4>
    <ul>
      <li>インターネット上に公開している文書(ファイル)・・・</li>
    </ul>
    <h4>Web サイト</h4>
    <p>Web サイトには複数の Web ページが含まれていて、各 Web ページは・・・</p>
    <h3>Web サイト作成に必要な知識</h3>
    <p>Web サイト作成に必要な知識(代表的なもの)には・・・。</p>
    <h3>Web ページを作成する方法</h3>
    <p>・・・</p>
  </div><!-- end of #content -->
  <div id="side">
    <h2>Side Bar</h2>
  </div><!-- end of #side --> 
</div><!-- end of #container --> 
<div id="footer">
  <p id="copy"><small>Copyright <span>&copy;</span> Web Design Leaves. All Rights Reserved.</small></p>
</div><!--end of #footer--> 
</body>
</html>

読み込む側(test01.html)の HTML

<body>
<div id="index"></div>
</body>

jQuery では load() を使って sample1.html の #content 内の見出し要素(:header)を test01.html にロードして表示。

jQuery

<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>  
<script>
jQuery(function($){
   $('#index').load('samples/sample1.html #content :header');
});
</script>

load() の外側で、 $(‘#index’) の HTML をコンソールに表示してみると、何も表示されない(空文字列)。

jQuery(function($){
    $('#index').load('samples/sample1.html #content :header');
    
    console.log($('#index').html());  //コンソールに出力
});

load_01

コンソールには GET リクエストと(空文字列)と表示されているが、test01.html には抽出(取得)した見出しが表示されている。

この時表示されている test01.html の HTML を見てみると、以下のようになっていて、div 要素(#content)内に抽出した見出し要素が注入されている。

load_02

コールバック関数を使って応答テキスト(取得したデータ)をコンソールに表示してみる。

jQuery(function($){
    $('#index').load('samples/sample1.html #content :header', function(response) {  
      console.log(response);  //コールバックで応答テキストをコンソールに出力
  });
});

以下のように sample1.html の HTML 全てが出力される。

load_03

load() の第1引数の URL に jQuery のセレクタを指定して、取得する要素をフィルタしても、コールバック関数に渡されるパラメータ「response:応答テキスト」は常に GET でリクエストされた HTML 全体になっている。

それでは、以下のようにコールバック関数でターゲットの HTML をコンソールに出力すると。。。

jQuery(function($){
    $('#index').load('samples/sample1.html #content :header', function() {  
        console.log($(this).html());
        //console.log($('#index').html()); でも同じ
    });
});

以下のように、見出し要素が表示される。

load_04

このことから(?)、ターゲットの要素へ注入する要素に何らかの操作するには、コールバック関数で処理する必要があるらしい。

別のページの見出しをリストとして表示する

別のページの見出しをそのまま見出しとして表示するのではなく、リスト(ul li 要素)として表示してみる。

jQuery(function($){
  $('#index').load('samples/sample1.html #content', function() {  
    //変数に必要な要素を記憶させてこの関数の中で処理する
    var index$ = $(this).find(':header');
    //var index$ = $('#index').find(':header'); こちらでも同じ
    $('#index').html(''); //$(this).html('');でも同じ
    var ul$ = $('<ul id="index_list"></ul>');
    var elem, li;
    index$.each(function() {
      for(var i = 1; i <= 5 ; i++) {
        elem = 'h' + i;
        if($(this).is(elem)){  // $(this)は index$ の中の各要素(h要素)
          li = '<li class="' + elem + '_class">' + $(this).text() + '</li>';
          ul$.append(li);
        }
      }
    });
    $('#index').append(ul$); //$(this).append(ul$);でも同じ
  });
});
4行目:index$ = $(this).find(‘:header’);
ターゲット $(this) には、load() で取得された要素(この場合はsample1.html の #content 内の要素 )が入っているので、この中から見出し要素のみを find() で抽出して変数 index$ に記憶(格納)しておく。
6行目: $(‘#index’).html(”);
ターゲット $(‘#index’) の中を初期化(空にする)
7行目:var ul$ = $(‘<ul id=”index_list”></ul>’);
ul 要素を生成し変数に代入(格納)
9行目:index$.each(function(n)
4行目で抽出した見出し要素のそれぞれについて each() を使って処理を実行
10行目:for(var i = 1; i <= 5 ; i++)
for()文を使って、h1 要素から h5 要素を対象に処理を実行
11行目: elem = ‘h’ + i;
h1 要素から h5 要素を処理するための変数の作成
12行目:if($(this).is(elem))
is() で処理している要素 $(this) が h1 要素から h5 要素の場合に限り実行(そうしないと、i が1~5までにしているので5倍の量の要素ができてしまう)
13行目:li = ‘<li class=”‘ + elem + ‘_class”>’ + $(this).text() + ‘</li>’;
CSS でスタイルするためのクラスを付与して、見出し要素のテキストで li 要素を生成
14行目:ul$.append(li);
生成した li 要素を ul 要素に付け足していく。
18行目:$(‘#index’).append(ul$);
ターゲット $(‘#index’) に ul 要素を付加。

表示される HTML

<div id="index">
  <ul id="index_list">
    <li class="h2_class">Web サイト作成入門</li>
    <li class="h3_class">Web について</li>
    <li class="h4_class">Web ページ</li>
    <li class="h4_class">Web サイト</li>
    <li class="h3_class">Web サイト作成に必要な知識</li>
    <li class="h3_class">Web ページを作成する方法</li>
  </ul>
</div>

関数にしておく

複数のページから見出しを抽出する場合、いちいち同じ記述を繰り返すのは面倒なので、関数にしておく場合の例。

  • target : リストを表示する要素
  • url: ファイルの URL
  • start : h1~h6 のどの要素を対象とするか(小さい方の数値を指定)
  • end : h1~h6 のどの要素を対象とするか(大きい方の数値を指定)
function list_hx(target, url, start, end){
  $(target).load(url, function() {  
    var index$ = $(this).find(':header');
    $(target).html('');
    var ul$ = $('<ul id="index_list"></ul>');
    var elem, li;
    index$.each(function() {
      for(var i = start; i <= end ; i++) {
        elem = 'h' + i;
        if($(this).is(elem)){  
          li = '<li class="' + elem + '_class">' + $(this).text() + '</li>';
          ul$.append(li);
        }
      }
    });
    $(target).append(ul$);
  });
}
list_hx('#index', 'samples/sample1.html #content :header', 1, 5);

引数に $.extend を使う場合の例(あまり実用的ではないかも)。

関連ページ: $.extend を利用したパラメータ(引数)の整理

function list_hx(my_options){
  var settings = $.extend({      
    target : '#index',    //リストを表示する要素(必須:デフォルトはダミー)
    url: 'index.html',   //URL(必須:デフォルトはダミー)
    filter : '',    //取得するデータにフィルタをかける要素等  
    ul_id: 'index_list',  //リスト(ul 要素)の id
    start : 1,  //h1~h6 のどの要素を対象とするか(小さい方の数値を指定)
    end : 6,  //h1~h6 のどの要素を対象とするか(大きい方の数値を指定)
  }, my_options || {});
  $(settings.target).load(settings.url + '' +  settings.filter, function() {  
    var index$ = $(this).find(':header');
    $(settings.target).html('');
    var ul$ = $('<ul id="' + settings.ul_id + '"></ul>');
    var elem, li;
    index$.each(function() {
      for(var i = settings.start; i <= settings.end ; i++) {
        elem = 'h' + i;
        if($(this).is(elem)){  
          li = '<li class="' + elem + '_class">' + $(this).text() + '</li>';
          ul$.append(li);
        }
      }
    });
    $(settings.target).append(ul$);
  });
}
list_hx({url: 'samples/sample1.html', target:'#index', start:1, end:5});

表示する対象のページが多い場合は、以下のように引数に配列を渡した方がいいかもしれない。

function list_hx(targets, urls){
  var length = targets.length;
  for(var i=0; i<length; i++){
    $(targets[i]).load(urls[i], function() {	
      var index$ = $(this).find(':header');
      $(this).html('');
      var ul$ = $('<ul id="index_list"></ul>');
      var elem, li;
      index$.each(function() {
      for(var j = 1; j <= 5 ; j++) {
        elem = 'h' + j;
        if($(this).is(elem)){	
        li = '<li class="' + elem + '_class">' + $(this).text() + '</li>';
        ul$.append(li);
        }
      }
      });
      $(this).append(ul$);
    });		
  }  
}
var targets = ['#index1', '#index2'];
var urls =  ['samples/sample1.html #content :header', 'samples/sample2.html #content :header'];		 
list_hx(targets, urls);	
読み込む側の HTML を工夫する

前述の配列を使った例などで、読み込む対象のページに変更があると毎回 jQuery も変更しなければならないので、読み込む側の HTML を工夫してみる。

以下のようにターゲット要素にクラス属性(list_h)を付与して、その内側に、読み込む対象のページのリンクを記述しておく。

HTML

<div class="list_h"><a href="samples/sample1.html"></a></div>
<div class="list_h"><a href="samples/sample2.html"></a></div>

jQuery

jQuery(function($){  
  //引数にクラス名などのターゲット要素を指定
  function list_hx(targets) {
    var targets$  = $(targets);
    var urls = [];
    targets$.each(function() {
      urls.push($(this).find('a').attr('href') + ' #content');
    });
    //for 文ではなく、each() を利用する場合
    targets$.each(function(index) {
      $(this).load(urls[index], function() {
        var index$ = $(this).find(':header');
        $(this).html('');
        var ul$ = $('<ul id="index_list"></ul>');
        var elem, li;
        index$.each(function() {
          for(var i = 1; i <= 5 ; i++) {
            elem = 'h' + i;
            if($(this).is(elem)){
              li = '<li class="' + elem + '_class">' + $(this).text() + '</li>';
              ul$.append(li);
            }
          }
        });
        $(this).append(ul$);
      });
    });
    
    //for 文を使う場合の例
    /*for(var i = 0; i < targets.length; i++) {
      targets$.eq(i).load(urls[i], function() {
        //targets$ はラップ集合なので eq() を利用
        var index$ = $(this).find(':header');
        $(this).html('');
        var ul$ = $('<ul id="index_list"></ul>');
        var elem, li;
        index$.each(function() {
          for(var j = 1; j <= 5 ; j++) {
            elem = 'h' + j;
            if($(this).is(elem)){
              li = '<li class="' + elem + '_class">' + $(this).text() + '</li>';
              ul$.append(li);
            }
          }
        });
        $(this).append(ul$);
      });
    }*/           
                         
  }
  list_hx('.list_h');
});
3行目:list_hx(targets)
引数にクラス名などのターゲット要素を指定するようにする
4行目:var targets$ = $(targets);
読み込むターゲット要素のラップ集合
5行目:var urls = [];
URL を格納する配列
6行目から8行目
ターゲット要素のラップ集合のそれぞれから URL を取得して配列に入れる
10行目: targets$.each(function(index){
targets$ はラップ集合なので each() を使ってそれぞれの要素に load() を実行

もし読み込む対象のページごとに絞り込む要素が異なる場合は、HTML5 の独自データ属性を使用する方法も考えられる。

HTML

<div class="list_h"><a href="samples/sample1.html" data-filter ="#content"></a></div>
<div class="list_h"><a href="samples/sample2.html" data-filter ="#side"></a></div>

jQuery

jQuery(function($){
  function list_hx(targets) {
    var targets$  = $(targets);
    var urls = [];
    targets$.each(function() {
      urls.push($(this).find('a').attr('href') + ' ' + $(this).find('a').data('filter'));
    });
    targets$.each(function(index) {
      $(this).load(urls[index], function() {
        var index$ = $(this).find(':header');
        $(this).html('');
        var ul$ = $('<ul id="index_list"></ul>');
        var elem, li;
        index$.each(function() {
          for(var i = 1; i <= 5 ; i++) {
            elem = 'h' + i;
            if($(this).is(elem)){
              li = '<li class="' + elem + '_class">' + $(this).text() + '</li>';
              ul$.append(li);
            }
          }
        });
        $(this).append(ul$);
      });
    });       
  }
  list_hx('.list_h');
});
6行目:$(this).find(‘a’).data(‘filter’)
独自データ属性の値を取り出すには、data メソッドの引数に「data-」以降に設定した文字列を指定

コールバックの応答テキスト(response)を使う例

コールバックでターゲットを操作するのではなく、応答テキスト(response)を使って別のページの見出しを表示してみる例。(この場合、load() ではなく、$.get() を使うほうが自然かも)

応答テキスト(response)は、load() の 第1パラメータ(URL)に、フィルタのための要素を指定しても常に読み込む HTML の全文を取得しているので、対象の範囲を絞るには、応答テキストを正規表現で絞り込む(フィルタする)必要がある。

function list_hx(target, url) {
  $(target).load(url, function(response) {  	
    response = response.replace(/<div id="side">[\s\S]*<\/html>/, "");	
    var hx = /<(h\d).?>(.+)<\/h\d>/g;
    var result_hx; 
    $(this).html('');
    var h_type_array = new Array();
    var hx_array = new Array();
    while((result_hx = hx.exec(response)) != null){
      h_type_array.push(result_hx[1]);
      hx_array.push(result_hx[2]);			  
    }
    var my_html = '<ul>';
    for(var i = 0; i < hx_array.length; i++){
      my_html += '<li class="' + h_type_array[i] + '_class" >' + hx_array[i]  + '</li>\n';
    }
    $(this).html(my_html + '</ul>' );     
  });	
}
list_hx('#index','samples/sample1.html' );
3行目:response = response.replace(/<div id="side">[\s\S]*<\/html>/, "");
id=”side” の div 要素は対象外にしたいので、replace() を使って応答テキストの<div id="side"> から</html> の部分を削除(空文字に置き換える)。
3行目:[\s\S]
改行文字を含めたあらゆる文字にマッチさせる正規表現
参考:RegExp – JavaScript | MDN
4行目:var hx = /<(h\d).?>(.+)<\/h\d>/g;
見出し要素を表す正規表現。exec() で使用するため()「括弧」 を使って h~ の部分とテキスト部分を指定。(グローバル)
5行目:var result_hx;
マッチしたものを入れる変数
6行目:$(this).html(”);
ターゲット $(‘#index’) の中を初期化(空にする)
9行目:while((result_hx = hx.exec(res)) != null)
exec() を繰り返し呼びだすことで、文字列の全てのマッチを調べる。(終了/継続の判定は戻り値が null かどうか)
10行目:h_type_array.push(result_hx[1]);
配列の要素1には、1番目の括弧で囲まれた部分表現に一致した文字列が格納されている
11行目:hx_array.push(result_hx[2]);
配列の要素2には、2番目の括弧で囲まれた部分表現に一致した文字列が格納されている
13行目~
ul 要素を作成して、配列の中身を使って li 要素を生成していき、最後にターゲットにそれを注入

関連ページ:ajax を使って更新を自動的に行う

クリックしたら別のページの見出しを表示する

サンプル1

以下のような HTML で、リンク「索引を表示」をクリックすると、指定したページの見出しを読み込んで表示する例。

  • リンク「索引を表示」(class=”show_list”)は一度クリックすると非表示にする
  • load() を使って指定したページの見出しを class の値が index_target の div 要素にリストとして表示
  • CSS で見出しの種類によりインデント等を設定

HTML (load_01.html)

<body>
<div class="list_index">
  <h3><a href="samples/sample1.html">HTML</a></h3>
  <p><a href="samples/sample1.html" class="show_list">索引を表示</a></p>
  <div class="index_target"></div>
</div>
<div class="list_index">
  <h3><a href="samples/sample2.html">CSS</a></h3>
  <p><a href="samples/sample2.html" class="show_list">索引を表示</a></p>
  <div class="index_target"></div>
</div>

jQuery

jQuery(function($){
  $(document).on('click', 'a.show_list', function() {
    var this$ = $(this);
    var url = this$.attr('href') + ' #content :header';
    var target = this$.closest('.list_index').find('div.index_target');
      target.load(url, function() {
        var index$ = $(this).find(':header');
        $(this).html('').hide();
        var ul$ = $('<ul id="index_list"></ul>');
        var elem, li;
        index$.each(function() {
          for(var i = 1; i <= 5 ; i++) {
            elem = 'h' + i;
            if($(this).is(elem)){
              li = '<li class="' + elem + '_class">' + $(this).text() + '</li>';
              ul$.append(li);
            }
          }
        });
        this$.hide();
        $(this).append(ul$).fadeIn();   
      });
    return false;
  });  
});
3行目:var this$ = $(this);
クリックされたリンク要素を this$ に代入
4行目:var url = this$.attr(‘href’) + ‘ #content :header’;
リンクの href 属性を利用して、load() のパラメータを作成
5行目:var target = this$.closest(‘.list_index’).find(‘div.index_target’);
リンク要素から class の値が index_target の div 要素を探してターゲットにする
6行目から19行目
load() を使って指定されたページのリンク要素を抽出
8行目:$(this).html(”).hide();
ターゲットを初めは非表示に
20行目:this$.hide();
リンク要素を非表示に
21行目:$(this).append(ul$).fadeIn();
ターゲットをフェードインで表示
23行目:return false;
指定されたページに移動するのを中止

CSS

ul {
  list-style-type: none;
}
.h2_class {
  font-weight: bold;
}
.h3_class {
  padding-left: 1em;
}
.h4_class {
  padding-left: 2em;
}

サンプル2

サンプル1と同じ HTML の構造だが以下が異なる。

  • リンク「索引を表示」(class=”show_list”)をクリックすると、表示される文字を「索引を隠す」に変更
  • 「索引を隠す」をクリックすると表示されている見出しのリストを非表示にする
  • 一度 load() したものは、再度 load() しないようにする

jQuery

jQuery(function($){
  $(document).on('click', 'a.show_list', function() {
    var this$ = $(this);
    var text_display = "索引を表示";
    var text_hide = "索引を隠す";
    var url = this$.attr('href') + ' #content :header';
    var target = this$.closest('.list_index').find('div.index_target');
    if(!target.hasClass('loaded')){
      target.load(url, function() {
        var index$ = $(this).find(':header');
        $(this).html('').hide();
        var ul$ = $('<ul id="index_list"></ul>');
        var elem, li;
        index$.each(function() {
          for(var i = 1; i <= 5 ; i++) {
            elem = 'h' + i;
            if($(this).is(elem)){
              li = '<li class="' + elem + '_class">' + $(this).text() + '</li>';
              ul$.append(li);
            }
          }
        });
        $(this).append(ul$).fadeIn().addClass('loaded').addClass('displayed');
          this$.text(text_hide);
      });
    }else{
      if(target.hasClass('displayed')) {
        target.removeClass('displayed');
        target.fadeOut();
        this$.text(text_display);
      }else{
        target.addClass('displayed');
        target.fadeIn();
        this$.text(text_hide);
      }
    }
    return false;
  });
});
8行目:if(!target.hasClass(‘loaded’))
一度ロードしたら、クラス「loaded」を追加しておいて、すでにロードされていない場合のみ load() を実行
23行目:$(this).append(ul$).fadeIn().addClass(‘loaded’).addClass(‘displayed’);
一度ロードしたら、クラス「loaded」を追加。また、その際にクラス「displayed」を追加して現在リストが表示中であることを判定できるようにする。
27行目:if(target.hasClass(‘displayed’))
すでにリストが表示されているかを判定
28行目~30行目
リストが表示されている場合は、クラス「displayed」を削除して、リストを非表示(fadeOut())にして文字列を変更
32行目~34行目
リストが表示されていない場合の処理