JS.3 Ajax通信で遊んでみる

色々な書き方

今回は、以下のHTMLを

という方法で作る方法を学びます。

<div id="img_unit">
  <div class="photo">
    <img src="img/img01.jpg">
    <div class="inner">
      <p>コメント1<span>name01</span></p>
    </div>
  </div>
  <div class="photo">
    <img src="img/img02.jpg">
    <div class="inner">
      <p>コメント2<span>name02</span></p>
    </div>
  </div>
</div>

なお、それぞれのhtmlファイルを index.html と言う名前だと仮定し以下のようなファイルパス関係だとします。

.
├── index.html
└── img
    ├── img01.jpg
    ├── img02.jpg
    └── img03.jpg

ちなみに、以下の css を読み込んでおくと綺麗に表示されます。

body {
  margin: 0;
  padding: 0;
  background-color: rgba(26, 55, 229, 0.06);
}
.container { /*<div class="container">で上記のhtmlを囲むとより綺麗に表示されます。*/
  max-width: 600px;
  margin: 0 auto;
  box-shadow: 0px 0px 3px rgba(0, 0, 0, .3);
}
img {
  width: 100%;
  margin 0;
  vertical-align: top;
}
.photo {
  position: relative; /*親要素に relative とすることで下で absolute が photo に対して行われる。*/
}
.photo .inner {
  position: absolute;
  bottom: 0;
  background-color: rgba(0, 0, 0, .5);
  font-size: 10px;
  color: #fff;
  margin: 0;
  width: 100%;
}

.inner p {
  padding: 20px;
}

.inner span {
  margin-left: 10px;
}

json から読み込む

Json(JavaScript Object Notation)ファイルにデータを用意しておいて、それらを随時読み込んで表示する方式。

以下のどちらを利用するかは自由。

  • htmlを直接 innerHTML プロパティで挿入する。
  • createElementappendChild を使って要素をオブジェクトとして扱う。
<div id="img_unit">
</div>

<script>
  var images = [
    {
      "path": "img/img01.jpg",
      "name": "name01",
      "caption": "コメント1"
    },
    {
      "path": "img/img02.jpg",
      "name": "name02",
      "caption": "コメント2"
    },
    {
      "path": "img/img03.jpg",
      "name": "name03",
      "caption": "コメント3"
    }
  ];

  var img;
  var caption;
  var div;

  for (var i=0; i<images.length; i++){
    img = document.createElement('img'); // <img>タグが作られる。
    img.setAttribute('src', images[i].path); // src属性を追加し、属性値を設定。

    caption = document.createElement('div'); // <div>タグが作られる。
    caption.className = 'inner'; // class属性を追加し、属性値を設定。
    caption.innerHTML = '<p>' + images[i].caption + '<span>' + images[i].name + '</span></p>'; // divタグの中に<p>...</p>という要素を追加。

    div = document.createElement('div');
    div.className = 'photo';
    div.appendChild(img); // divの内部にimgを追加する。
    div.appendChild(caption); // divの内部にcaptionを追加する。

    document.getElementById('img_unit').appendChild(div); //"id=img_unit"のタグの内部にdivを追加する。
  }
</script>

直書きでAjax通信を使う

プログラムの中にjsonデータを保持しているのは賢いやり方ではない。

というか、API(Application Programing Interface)を使って外部と通信しながらデータを処理することがほとんどであり、その時に使えるのがAjax通信。

なお、ここでは、"https://h2o-space.com/htmlbook/images.php" というサーバーと通信を行なっているが、これはjsonのセキュリティの問題のため。

file がCross origin requestsでサポートされているプロトコルに含まれていない(セキュリティ上危ないから)ので、講師の方が用意してくださっている。

また、ajax通信は以下のようにいくつかのステップに分かれており、それぞれに状態が割り当てられているので、通信が終わったことを確認してから次の処理を行うことができる。

定数 状態
0 UNSENT インスタンスができた
1 OPENED openメソッドを利用した
2 HEADERS_RECEIVED ヘッダーが受信できた
3 LOADING データを受信中である
4 DONE 通信が終了した
<div id="img_unit">
</div>

<script>
  var ajax = new XMLHttpRequest(); //ajax通信を行うためのオブジェクト。XMLはデータ形式の一つだが、ここではJsonでデータのやり取りを行う。
  // alert(ajax.readyState); // 0
  ajax.open('GET', 'https://h2o-space.com/htmlbook/images.php'); // ajax通信を行う相手先のアドレス(講師の方が用意してくださっている。)
  // alert(ajax.readyState); // 1 (openを行なった後)
  ajax.responseType = 'json'; // データの形式を指定
  ajax.send(null); // ファイルを呼び出す。

  ajax.onreadystatechange = function(){
    if (ajax.readyState === XMLHttpRequest.DONE && ajax.status === 200){
      for (var i=0; i<this.response.length; i++){
        var data = this.response[i];

        img = document.createElement('img');
        img.setAttribute('src', data.path);

        caption = document.createElement('div');
        caption.className = 'inner';
        caption.innerHTML = '<p>' + data.caption + '<span>' + data.name + '</span></p>';

        div = document.createElement('div');
        div.className = 'photo';
        div.appendChild(img);
        div.appendChild(caption);

        document.getElementById('img_unit').appendChild(div);
      }
    }
  };
</script>

jquery でAjax通信を使う

jqueryの公式サイトから、jqueryをダウンロードし、js/jquery.min.js に保存してください。

<div id="img_unit">
</div>

<script src="js/jquery.min.js"></script>
<script>
  $.getJSON('https://h2o-space.com/htmlbook/images.php', function(data) { // コールバック(処理が終わった時に自動的に呼び出されるファイルのこと。)
    for (var i=0; i<data.length; i++){
      $('<div class="photo"></div>')
        .append('<img src="' + data[i].path + '">') // 自分自身「に」追加する。
        .append('<div class="inner"<p>' + data[i].caption + '<span>' + data[i].name + '</span></p></div>')
        .appendTo('#img_unit'); // 自分自身「を」追加する。
    }
  });
  /* サンプル(htmlを生成する。)
  $(#img_unit).html('ここに、画像リストが表示されます。');
  $(#img_unit).css('margin-top', '100px');
  */
</script>

vue.js でAjax通信を使う

jquery だとhtmlを生成する際に要素をそのままscript内に書いており、少しわかりにくかったです。そこで、vue.jsというライブラリがよく使われる。

なお、vue.jsは公式サイトにてcdnで配布されています。

vue,jsは以下の形が基本で、プレースホルダーを書き換える、といった操作を行います。

<div id="vue_unit">
  {{ message }}
</div>
<script>
  var app = new Vue({
    el: '#vue_unit',
    data: {
      message: 'vue.jsで書き換えました。'
    }
  });
</script>

今までのサンプルに適用すると、以下のようになります。なお、プレースホルダーを属性値の中に書くことができないので、別の書き方をしています。

<div id="img_unit">
  <div class="photo" v-for="Photo in Photos"> <!-- vue.js の for構文を使っている。 -->
    <img :src="Photo.path"> <!-- vue.js によって書き換えられる対象となる。 -->
    <div class="inner"><p>{{ Photo.caption }}<span>{{ Photo.name }}</span></p></div>
  </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="js/jquery.min.js"></script>
<script>
  var app = new Vue({
    el: '#img_unit',
    data: {
      Photos: []
    },
    created: function() { // vueのオブジェクトが作られる時のメソッド
      var self = this; // ここでのスコープのthisを保存しておく。
      $.getJSON('https://h2o-space.com/htmlbook/images.php', function(data) {
        self.Photos = data
      });
    }
  });
</script>

最後に

これで、講義で習った事は終了しました:)

other contents
social