Help us understand the problem. What is going on with this article?

JavaScript超初心者向け Meteor メモ (3) シンプルなチャットを作ってみる

More than 3 years have passed since last update.

今回はチュートリアルに挑戦!w

Meteor.jsは、 Webアプリづくりを楽しくする フレームワークです。

前回はv0.8.0での変更点を見てみましたが差分情報ばかりで、あまり「超初心者向け」になってませんでしたね。すいません。
やはり、作りながら覚えないと面白くない!
というわけで、今回は、動くものを作りながらテンプレートやデータベース(コレクション)の使い方を覚えちゃいましょう!という企画です。

つくるもの:シンプルなチャット

今回は、チャットを作ってみましょう。

こんなの(ライブデモ)です。

こんな感じのものです。

  • チャットなのでリロード無しに相手が書き込んだときに自動的に自分が開いているブラウザの表示に反映される。
  • ログイン機能などは無し。部屋のような機能もありません。誰でも書けます。
  • テキストボックスでenterキーを押したら入力を確定させます。
  • 見やすいように色分けする機能つき
  • 10件まで表示。古いのは自動的に消えます。

このように、シンプルな機能のチャットではありますが、リアクティブでリアルタイムに同期するMeteorならでわの動きを体感することができると思います。
今度こそ、 Meteorを始めてインストールするぞ! という方も、是非一緒に進めてみてください!

準備

それでは、はじめましょう!

すいません。。。MacかLinuxで

いきなりごめんなさい、なのですが、MeteorはまだWindowsに対応してません。。。
是非、MacかLinuxを準備してください。

Meteorのインストール

まず、Meteorをインストールしましょう。

$ curl https://install.meteor.com/ | sh

これでインストール完了です。
※万が一うまくいかない方は、JavaScript超初心者向け Meteor メモ (1)も参照してみてください。

プロジェクトを作る

次にプロジェクトを作ります。

プロジェクト名は何でもかまわないのですが、今回はsimpleにしたとして話をすすめます。

コマンドラインから、

meteor create simple
cd simple

と入力してください。
これでプロジェクトフォルダができました。
さらに、プロジェクトフォルダを覗いてみます。

ls
simple.css simple.html simple.js

上記のように、3つのファイルが出来ていれば成功です。

jQueryを追加

今回のプロジェクトではjQueryを使います。
早速追加してみましょう。

コマンドラインから、

meteor add jquery

と入力してください。
これでjQueryが使えるようになりました。

それでは、最後にMeteorを起動します。

meteor

http://localhost:3000/にアクセスしてみてください。
下記のような画面が表示されていれば、準備完了です。

最初はhello world

いよいよコードを書いてみる(HTML,JavaScript)

それでは、コードを書いていきましょう。
今回は、simple.htmlとsimple.jsを書きかえてみます。

書き換えるには、HTMLやJavaScriptの基本的な知識が必要です。
下記サイトを参考にしながら進めてください。

HTMLやJavaScriptを優しく教えてくれる参考サイト

しっかりマスターしてからでないと進められない、というものではないので、判らない部分が出て来たら調べる感じで進めてしまいましょう。

CSSは?

simple.cssについての説明は今回サボりますw

下記をコピペしといてください。
もちろん、もっとカッコよい見た目を目指して好きなように書き換えて頂いてかまいません。

simple.css
*{padding:0px;margin:0px;word-break:break-all!important;box-sizing:border-box!important;font-size:14px;}
body{background-color: #FFF;}
#head{padding:10px;background-color: #CFA!important;color:#000!important;}
#h_title{font-size:24px;}
#wrap{padding:5px;margin:0 auto;max-width:640px;color:#FFF;}
#postmes{width:320px;}
#postname{width:120px;}
#head{background-color: #000;color:#FFF;}
.rec_wrap{margin:5px;padding:5px 10px;color:#000;margin-bottom:10px;}
.rec_date{float:left;font-size:10px;width:100px;}
.rec_name{float:left;font-size:10px;width:120px;}
.rec_mes{clear:left;font-size: 20px;}
#control{clear:left;}
#colorbox{display:inline-block;vertical-align: middle;width:14px;height:14px;}

HTMLを編集

それでは、simple.htmlから書いていきましょう。
何も編集しいない状態ですと、下記のようになっているはずです。

simple.html
<head>
  <title>simple</title>
</head>

<body>
  {{> hello}}
</body>

<template name="hello">
  <h1>Hello World!</h1>
  {{greeting}}
  <input type="button" value="Click" />
</template>

ちょっと待った。なんか変だぞ?このHTML

そうなんです!meteorで使うHTMLは少し変なんです。

  1. <html></html>とか無いよ?
  2. {{> hello}}{{greeting}}? なんなのこれ
  3. <template></template>

いろいろ変ですね?

実はMeteorで使うHTMLは、普通のHTMLファイルではありません。
Meteorがテンプレートという機能を使って書き換える元となるファイルになっています。

まず、<html></html>などは、Meteorが自動生成しますので気にしないでください。
次に、{{> hello}}の部分は後で出てくる<template></template>に記載されているコードに置き換えられます。
最後の{{greeting}}の部分はMeteorが採用するテンプレート記法での変数で、JavaScriptで内容を設定できます。

このあたりの説明は、体感!JavaScriptで超速アプリケーション開発 -Meteor完全解説 第4回 Meteor開発のテンプレートあたりに詳しく書いてありますので、そちらを参照してみてください。

今回どのように書き換える?

さて、simple.htmlを、以下のように書き換えます。

  1. テンプレート名がhelloなのはアレなのでcontentsに変更
  2. 今のテンプレートの内容は使わないので削除

すると、こんな↓感じになったはずです。

simple.html
<head>
  <title>simple</title>
</head>

<body>
  {{> contents}}
</body>

<template name="contents">

</template>

これをベースに、チャットで使うコードを追加していきましょう。
必要なテンプレートを含めるように書いていきます。

テンプレート 役割
{{maxrec}} 表示最大件数
{{color}} 背景色のスタイル
{{messages}} メッセージのリスト
{{datetime}} 日付
{{name}} 名前
{{message}} 本文

最終的にコードは下記のようになりました。

simple.html
<head>
  <title>simple</title>
</head>

<body>
  {{> contents}}
</body>

<template name="contents">
  <div id="head">
    <div id="h_title">Meteorを使ったシンプルなチャットのデモです。</div>
    <div id="m_title">{{maxrec}}件まで表示されます。背景色は
      <span><div id="colorbox" style="{{color}}"></div></span>です。
    </div>
    <div id="control">
      <input id="postname" type="text" placeholder="enter your name">
      <input id="postmes" type="text" placeholder="enter message">
    </div>
  </div>
  <div id="wrap">
    <div id="messages">
    {{#each messages}}
      <div class="rec_wrap" style="{{style}}">
        <div class="rec_date" id="date{{_id}}">{{datetime}}</div>
        <div class="rec_name" id="name{{_id}}">{{name}}</div>
        <div class="rec_mes" id="mes{{_id}}">{{message}}</div>
     </div>
   {{/each}}
   </div>
  </div>
</template>

入力Box2つと、リスト表示エリアがあるだけのシンプルなものができました。

JavaScriptの編集に入る前に、一旦http://localhost:3000/にアクセスしてみてください。

HTMLの編集が終わった状態での画面

こんな感じで表示されましたか?

JavaScriptを編集

それでは次にsimple.jsを編集します。
こちらも、最初はhello Worldの内容になっています。
(コメントは消してあります)

simple.js
if (Meteor.isClient) {
  Template.hello.greeting = function () {
    return "Welcome to simple.";
  };

  Template.hello.events({
    'click input': function () {
      if (typeof console !== 'undefined')
        console.log("You pressed the button");
    }
  });
}

if (Meteor.isServer) {
  Meteor.startup(function () {
  });
}

最初にhelloテンプレートに関連するコードは一旦消しておきましょう。

simple.js
if (Meteor.isClient) {
}

if (Meteor.isServer) {
  Meteor.startup(function () {
  });
}

上記コードをベースに追加していきたいと思います。

色指定や、レコード数を書いてみる。

簡単なところから始めましょう。
最初は、html側に書かれているレコード最大件数の変数{{maxrec}}と、背景色の変数{{color}}に値を設定してみましょう。
この処理は、クライアントコード(if (Meteor.isClient) { } の内側)に書きます。

最大件数を追加するには、下記のように書きます。

var maxrec = 10;
Template.contents.maxrec = maxrec;  // 最大件数表示

これでHTML側にも最大件数が表示されるようになります。

Template.contents.maxrec = maxrecは、「{{> contents}}の中の{{maxrec}}にmaxrecを設定する」という処理になります。
この部分だけで最大件数を使うのであれば、10をそのまま設定してもかまわないのですが、後で別の箇所でも最大件数を使うことになるので、maxrecに入れておくことにします。

続けて、背景色部分です。

var colors = [
  'Cornsilk','Aquamarine','LightPink','PaleGreen','Coral',
  'SpringGreen','Plum','LightSkyBlue','MistyRose','Turquoise'];
var color = "background-color:"+colors[(+new Date()) % 10]+";";
Template.contents.color = color;    // 背景色表示

まず、10個の色テーブルから、ランダムに1個を選んで、background-color:と合成して変数colorに一旦設定したうえで、Template.contents.colorにも設定します。

ここまで出来たら、http://localhost:3000/を確認してみましょう。

最大件数と背景色を追加

ソースコードから最大件数を、他の数字に変えると、http://localhost:3000/の表示もすぐに変わるはずです。
また、背景色はリロードの都度変わると思います。いろいろ変えてみてください。

確認ができたら先に進みましょう。

コレクションを使ってみる

チャットの情報を貯めておくには、データベースが使いたいですね。
Meteorでは、コレクションという機能を使うこと簡単にデータベースを使うことができます。

早速コレクションを使ってみましょう。

コレクションの生成

最初にコレクションを1つ生成します。
このコレクションは、メッセージを貯めるものですので、Messagesという名前にしましょう。

コレクションの生成には、Meteor.Collection()を使います。

simple.jsの冒頭(if (Meteor.isClient) { より上)に、下記コードを追加します。

var Messages = new Meteor.Collection('messages');

コレクションからリストを読み込んでテンプレートに表示する

次に、Messagesコレクションからメッセージのリストを読み込んで、
テンプレートに流し込む処理を書いてみましょう。
この処理は、クライアントコード(if (Meteor.isClient) { } の内側)に書きます。

  Template.contents.messages = function () {
    return Messages.find({},{sort:{date:-1}});
  };

このようになります。

Messages.find({},{sort:{date:-1}})で、Messagesコレクションに登録された全てのレコードをdateというフィールドの逆順にソートしてクエリしています。
クエリ結果は配列のようなオブジェクトcursor形式で返されます。

この結果は、直接Template.contents.messagesに設定しています。
HTML側には、{{#each messages}}{{/each}}と書かれていますが、#eachは指定された配列(cursorでも良い)のレコードの数だけ内側に書かれたコードをコピーします。

これにより、Messages.find()で取り出したデータの数に対応したDOMを作ることができます。

コレクションにデータ登録する

最後に、少しコードが多くなりますが、textboxから文字を取り出してコレクションにデータ登録する処理を書いてみましょう。
コレクションは、SQLなどと違って、ドキュメントにデータ登録する時に、そのドキュメントが持つフィールドを自由に決めることができます。
今回、Messagesには下記フィールドを持たせることにします。

フィールド名 テンプレート側の変数名
datetime {{datetime}}
date -
name {{name}}
message {{message}}
style {{style}}

datetimenamemessagestyleはそのままテンプレートの変数に設定されます。

コードは下記のようになります。
クライアントコード(if (Meteor.isClient) { } の内側)に書きます。

 // イベント処理
  Template.contents.events({
    'keydown input#postmes':function(ev){
      if(ev.keyCode == 13){ // 'enter' keyで確定
        var message = $("#postmes").val();
        if(message != ""){
          $("#postmes").val("");   // 入力Boxの文字消す。
          var setdata = createProperties(message); // データをつくる
          // コレクションへ新レコードを登録
          Messages.insert(setdata,function(err,_id){
            // 最大件数以上なら古いのを消す
            var len = Messages.find({}).fetch().length;
            if(len > maxrec){
              var doc = Messages.findOne({}); // 先頭レコード(つまり一番古いレコード)を取り出す
              Messages.remove({_id:doc._id}); // そして消す
            }
          });
        }
      } 
    }
  });

  // messageレコードのプロパティ生成
  function createProperties(message){
    var date = Date.parse(new Date());
    var datetime = toDateStr(date);
    var name = $("#postname").val();
    var style = color;
    if(name == ""){
      name = "guest";
    }
    return {date:date,datetime:datetime,message:message,name:name,style:style};
  }

  // 日付を文字列に変換
  function toDateStr(parseDate){
    var date = new Date(parseDate);
    var y = date.getFullYear();
    var m = date.getMonth()+1;
    var d = date.getDate();
    var h = date.getHours();
    var min = date.getMinutes();
    return y+"/"+m+"/"+d+" "+h+":"+min;
  }

ここだけちょっと長かったですね。申し訳ありません。
少し解説します。

Template.contents.events()

これはイベントハンドラです。
今回は、ID #postmes のテキストボックスで改行キー(enterキー)を押したらイベント処理を行うように設定しています。
jQueryを使ってテキストボックスに入力されたテキストを取得し、何も入力されてなかったら、登録しないよう条件を入れています。
これは、連続改行連打とかで酷いことになるのを防止するためです。
テキストボックスに何か、文字が入っていたら、createProperties()を使って登録データを生成後、Messages.insert()を使ってコレクションにデータを登録しています。

createProperties()

Messagesへ登録するドキュメント(1レコード)のデータを生成しています。

Messages.insert()

Messagesへデータ登録を行っています。
非同期で呼び出されるコールバックの中では、Messagesに登録されたドキュメントの件数を求めて、maxrecを超えてないかチェックしています。
超えてたら、Messages.remove()を使って1件削除しています。
なので、厳密に言うと、maxrecは「表示件数の上限」ではなくて、「データ登録件数の上限」なんですねw

コレクションの初期化

なぜか、一番最後になってしまいましたが、コレクションの初期化処理について書きます。
コレクションの初期化処理は、サーバ側コード(if (Meteor.isServer) { } の内側)に書きます。

これまで、Meteor.startup()(アプリを立ち上げると動作する処理)には何も書かれていませんでしたが、下記コードを追加しておきます。

  Meteor.startup(function () {
    Messages.remove({});  // 全クリア
  });

Messages.remove({}) で全ドキュメント(レコード)がクリアされます。

もし、開発が終わったら、この部分は他の方法で実装した方が良いと思いますw

一応完成のはず。

完成しましたか?
完成しねーぞごら!という方は、申し訳ありませんがこのようなコードですが、githubにも上げておきましたから引っ張ってやってみてくださいw

まとめ。

今回は、簡単に作ることを目指したので、コレクションの使い方もかなりいい加減なものになっています。
しかし、引き換えに本当に簡単にチャットが作れました。

いろいろと説明がヘタ、不足などあると思いますので、ご指摘、質問よろしくお願いします!

たぶん、(4)も書くと思います。
どっかでPixi.jsとの連携もやりたいなーw

バックナンバーと続き

下記もよろしくお願いします!

JavaScript超初心者向け Meteor メモ (1)
JavaScript超初心者向け Meteor メモ (2) v0.8.0でのテンプレートエンジンの変更について
JavaScript超初心者向け Meteor メモ (4) ログイン画面を作る (基本編)
JavaScript超初心者向け Meteor メモ (5) ログイン画面を作る (Google/Twitterアカウント編)
JavaScript超初心者向け Meteor メモ (6) 外部パッケージを使ってみる
JavaScript超初心者向け Meteor メモ (7) テンプレートを使ってみる

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away