title
Design

Javascript修行

こんにちは!新人森田です。
エイプリルフールというイベントもありつつ、今日からいよいよ新年度ですね。
今年度はがっつり活躍するのが私の目標です。
その為にも修行あるのみ!

コーディングの修行をいくつかやったところで、Javascript(以下js)の勉強を再開しました。
というのも、流行っている内に一度はパララックス作ってみたいんです。
いまだに私のjsコードは師匠からのアドバイス9割で出来ているので、少なくとも今の自分のhtmlやcssの知識くらいに、試行錯誤しながら作っていけるレベルにはなりたいところ。

師匠に色々教わった中でも、今回は基礎中の基礎である“jsを書く時の注意点”をまとめてみます。
これを絶対守らなければだめだという訳ではなく、こういったことに気をつけると見やすいコードになるよという目印ですね。
ブログが練習ノートみたいになってますすいません。

Javascriptを書く時の注意点

コーテーション

0401_01

htmlでは<div class=“”>のようにダブルコーテーションを使うのが一般的ですが、たとえばRubyではダブルコーテーションには特別な意味があったりします。様々な言語に共通して使えるという面もあり、特別な理由がない限りはシングルコーテーションを使うと無難そうです。
ただし文字列の中にコーテーションが使われる場合はダブルコーテーションで囲います。例:“I’m …”

オブジェクト

0401_03_03

{}で囲われるオブジェクトは、中身が複雑化しがちなため括弧の内側にスペースをあけて見やすくします。
また、オブジェクト内に複数の要素が入る場合はカンマで区切ったあとにスペースをあけて次を記述します。

配列

0401_05

一方、[]で囲われる配列にはスペースを使わずに記述します。
複数の要素を書く場合はオブジェクトと同じです。

引数

ここではif文の引数という形で見てみます。
関数(function)の時も同じです。

0401_07

ifと()の間にはスペースをあけて、()と{}の間は続けて書くことが多いです。
引数、つまり()内はスペースをあけません

0401_09_09

ifの後にelse ifを書く場合、if(){…}に続いていることを明確にするため}の隣にスペースをあけて書き始めます。

また、条件定義する時に同じ項目を使う場合は左項にまとめたりすると見やすいです。
≦≧はそれぞれ“<=”、“>=”と書きます。

キャメルケースとスネークケース

0401_11

関数定義に使う名前はキャメルケース(上の行)、それ以外の定義ではアンダーバーでつなげるスネークケース(下の行)を使います。

0401_15

また、戻り値が真偽値の時は“is~”という形式でキャメルケースを使って名前を付けます。

計算式

0401_13

計算式を記述する場合は、数字と記号の間にスペースをあけて書きます。
このとき記号は、足す“+”、引く“-”、掛ける“*”、割る“/”を使います。
通常の数式と同じで掛け算割り算が優先して行われるので、足してから掛けたい場合は()でくくります。

まとめ

細かい部分ではありますが、細かい部分が疎かになっているとコードが膨大になった時に散々な目にあうかも知れません。
私が高校大学でやってきた弓道でも、どんなに的に当たっても型が疎かではいけませんでした。
出来る人っていうのはそういう部分からしっかりしてるから結果的に出来てるんじゃないかなと思ったり。

あとjsが思った以上に計算地獄で、もともとない数学の頭をフル稼働してしんどいです。
でも書いたものが稼働してるのを見るとそんなの吹っ飛んじゃうんですけどね!
早くコードがすっと頭に入ってくるようになりたいです。押忍!

標準
jquery-title2
Design

jQueryを使ってみよう その1(動く目をつくる)

こんにちは!
昨日会社のヒーターでコートの袖を焦がしそうになった新人森田です。
わたあめみたいなにおいがしました。
暖かくなるのはいつなんでしょうか。

jQueryを使ってWebサイト作りたいなあとずっと思っていたんですが、前回Bootstrapでついに使うことが出来ました。
でも便利すぎたおかげで、ちゃんと使えるようになったわけではありません。
これは勉強するしかないなと思い立ちました。
ら、師匠がJavascript基礎講座を開いてくださいました。

教わりながら簡単なJavascriptを作ってみたので、
今回はその作り方を振り返りながら頭の中を整理してみたいと思います。

データのルール

関数と変数

Javascriptにはそれ自体が動作をもっている関数と、動作をもっていない変数があります。
変数はscssでも使ったことがあるし何となく使い方も分かるような気がします。
関数にはさらに“input = 引数(ヒキスウ)”“output = 戻り値、返り値”というのがあって、引数を与えて出てきた戻り値を色々と処理するわけです。

文系に進んで数学から逃げてきたと思いきや、まさかここで関数と出会うことになるとは。。
というか、そもそもプログラミングが数学っぽいものだったりしますね。
Javascriptを多少なりとも理解することで数学を克服したと思うことにします。

データ型

扱うデータの型は5種類です。
それぞれ記述の仕方によって区別されます。

  • 1  :int,integer,number(整数)
  • ‘…’    :string(文字列)
  • […] :データの順番が保持される配列
  • {…}   :データを格納するオブジェクト
  • 真偽値:true,false

これらのデータ型を使い分けていきます。

jQueryを使ってみる

予備知識がすごくアバウトですが、あとは実際に書きながら覚えていきましょう。
今回はjQueryを使って「マウスを追いかけて動く目」をつくってみます。

最初に顔のベース画像を用意します。
ティムバートン作品を意識してみました。

0305-1

 html,cssを書く

Webページ上にデータがないと動かせないので、htmlとcssを使って簡単なページを作ります。
この時のポイントは、目が動く範囲のdivを作っておいて、その中に黒目の部分を入れるということです。

0305-2

こんな感じです。ついでに口も作っておきました。
目や口はpositionで位置を調整してあります。
円形に可動範囲を限定しようとすると難しい処理が必要とのことで、ちょっと目ん玉飛び出しますがご了承ください。

jQueryを前提としているため、htmlファイルには自分で書くjsファイルの他にjQueryのjsファイルにもリンクが必要です。

jsを書く 1

準備が整ったところでjsファイルをいじりましょう。
今までノータッチだった未知の領域に一歩踏み出しちゃいます。
“main.js”と名付けて作業を始めます。

htmlと同じようにざっくりした部分から詳細設定を書き込んでいきます。

まずは実行タイミングを決めます。
青い文字は自分の覚え書き的なものですが結構主張しちゃっててすみません。

0305-3b

“$()”の()内に引数を入力します。
ここでは引数が“function”=無名関数というもので、“function(){}”の()に仮引数、{}には関数の中身を書き込むという形式になっています。
jsさんなかなか複雑です。

上の段落の記述で.readyと同じようにページ読み込みのタイミングでjsが実行されます。
そのオブジェクトの中に、次にどういう動きをするかを設定します。
また、それが正しく動作しているかを“console.log”を使って確認をします。

下の段落は、
「body内でマウスを動かすとtestという文字列が表示される」
という動作を定義してあります。

0305-4

bodyのwidthとheightが100%なので、body=画面となり、画面内でマウスを動かすと動かした分“test”が表示され続けることになります。

というわけで1つめはクリアです。

jsを書く 2

次はマウス(ポインタ)の位置に応じて目を動かしてみます。

目を動かすということは目のcssを変更するということです。
目のcssがどこにあるかをコンピューターに指示するためには、
目に割り当てたclassをセレクタに入れて、あらかじめjQuery化(jQueryが処理しやすい変数に変換)しておくことで動作がスムーズになります。
なのでページ読み込みと同時に“var”を使って変数定義しておきましょう。
これをしなくても動作はしますが、いちいちコンピューターがclassを探すことになって重くなる要因となります。

また、マウスの位置を取るには“mousemove”というイベントを使用します。
“mousemove”のイベントオブジェクトに格納されている“clientX”“clientY”を使うことでマウスの座標を知ることが出来ます。
そしてイベントオブジェクトには変数の名前を付けます。
“e”などに略されることが多く、今回はそれにならってfunctionの引数に“e”を書き込み、“e.clientX”という風に使います。

0305-5b

では“e.clientX”を使って左右の動きを付けてみます。

画面の中央に配置した顔を基準にしてどこが左でどこが右かというと、次のように考えます。
ウインドウ幅の半分の座標を中心として定義して、その増減で左右を認識させます。
後で上下の動きをつける時にも使うので、ウインドウ幅も最初に変数にしておくといいかも知れません。

“center_x”を定義したら、if文を使って「中心より左ならこう」「中心より右ならこう」と動くための条件を分けます。
ここでは(e.clientX >= center_x)という条件を使っています。
分かりやすく書くと「e.clientX ≧ center_x」つまり「中心より右」ということです。
それ以外を“else”として2つに条件分岐しています。

条件が決まったら、どういう動作をするかを書きます。
if文の中はどういう意味かというと、
変数化しておいた“$leftEye”“$rightEye”のcssを
「マウスが中心より右だったら左から70pxの位置に」
「マウスが中心より左だったら左から0pxの位置に」
変更する、という定義です。

なんでcssの値がこうなるかというと、

0305-6b

目のエリアが100×100px、目の大きさが30×30pxということを考慮して計算した結果の値なのです。

これでx座標(左右)の設定が出来ました。
xをyに変換して同様に書けば上下の設定も完了です。

たとえばマウスを画面の左上に動かしてみると、こんな顔になります。

0305-7

目が飛び出てるとギャグっぽくてこれはこれでありかも。

もし思った通りに動作しなかったら、プログラムエラーが出ていないかを確認してみてください。
アラートさんは常に冷静に何が足りないかを教えてくれます。

jsを書く 3

ここまでで、マウスの位置に応じて目が左上、左下、右上、右下に飛び出るというプログラムが書けました。
せっかくだからマウスが顔の範囲に入ってきたら目を真ん中に表示させてみます。

0305-8

if文の中にもう1つ条件分岐を書き込みます。

“else if”を使って、「e.clientX≧center_xより150px少ない値」&「e.clientX≦center_xより150px多い値」の両方の条件を満たした場合の動きをつくります。
±150pxの理由は、顔のwidthが300pxで、中心線から考えると150pxずつ幅があるからです。
この時にcssを左から35pxに変更することで目が中心に来ます。

上下も同様に、顔のheightが400pxということを踏まえてcenter_yから+200px、-200pxで条件と動きを設定します。

0305-9

これで、上図の青い範囲内にマウスが来た時に目がそれぞれの真ん中の位置にくるようになりました。

まとめ

慣れないjs構文を書くと、
文字列にすべきところにコーテーションがなくてエラー
閉じ括弧忘れてエラー
スペルミスしてエラー
と、初歩的なミスばっかりしてたような気がします。

でも実際動いてくれるのを見ると楽しい!
思い通りに使えるようになったらもっと楽しいんだろうなと思います。

今回作ったJavascriptは下記のリンクで実際に動かせますので動作確認したい方はどうぞ!
上図の青い範囲が重なっている部分(顔の範囲内)にマウスが来た時だけする動きがあったりしちゃうかも?

http://nnnzzz000.github.io/move-eye/

これからはjsももっと読んだり書いたりしていこうと思います!押忍!

標準
IMG_5256
Development

Vanilla JavaScriptを書いてみよう その3(タブUIを実装)

さて前回はJavaScriptで取得したhtml要素のclass属性を簡単に追加や削除が行えるように Element というクラスの実装を紹介しました。

今回はそのElementクラスをクラスを使ってタブUIを操作できるクラスを実装してみたいと思います。

まず部品として以下の2点が必要かと思いますので、それぞれに対応するクラス名称をつけました。

  • タブボタン => TabNavItem
  • タブ内容ボックス => TabContent

TabNavItem

TabNavItemの仕様として以下の項目があげられます

  1. 生のhtml要素を渡して初期化出来る
  2. 選択中に切り替えられる
  3. 非選択中に切り替えられる
  4. 生のhtml要素と比較して自分自身かどうかをチェックできる

1. 生のhtml要素を渡して初期化出来る

これはコンストラクタですね。new した時の初期化処理ですが、引数で受け取った生のhtml要素を前回作成した Element オブジェクトにして保持しておきます。
後は選択中を示すclass名もここで定義しておきました。

function TabNavItem(el) {
  this.el = new Vanilla.Element(el);
  this.current_class_name = 'tab-nav__item--current';
}

2. 選択中に切り替えられる

自身のElementオブジェクトに対して、選択中のclass名を持っていなければ追加します。

TabNavItem.prototype.toCurrent = function() {
  if (this.isCurrent()) return;
  this.el.addClass(this.current_class_name);
};

3. 非選択中に切り替えられる

自身のElementオブジェクトに対して、選択中のclass名を削除します。

TabNavItem.prototype.toUncurrent = function() {
  this.el.removeClass(this.current_class_name);
};

4. 生のhtml要素と比較して自分自身かどうかをチェックできる

実はこれもタブUIを実装する上で結構重要な機能です。
これはElementオブジェクトの持っている同名のメソッドに処理を渡しています。

TabNavItem.prototype.isEqual = function(targetElement) {
  return this.el.isEqual(targetElement);
};

TabNavItemの実装は以上です。まとめたコードがこちらです。

var TabNavItem = (function() {
  function TabNavItem(el) {
    this.el = new Element(el);
    this.current_class_name = 'tab-nav__item--current';
  }

  TabNavItem.prototype.toCurrent = function() {
    if (this.isCurrent()) return;
    this.el.addClass(this.current_class_name);
  };

  TabNavItem.prototype.toUncurrent = function() {
    this.el.removeClass(this.current_class_name);
  };

  TabNavItem.prototype.isCurrent = function() {
    this.el.hasClass(this.current_class_name);
  };

  TabNavItem.prototype.isEqual = function(targetElement) {
    return this.el.isEqual(targetElement);
  };

  return TabNavItem;
})();

TabContent

TabContentは仕様として以下の項目があげられます。

  1. 生のhtml要素を受け取って初期化出来る
  2. 選択中に切り替えられる
  3. 非選択中に切り替えられる

1. 生のhtml要素を受け取って初期化出来る

TabNavItemとほぼ同じですが、TabContentの場合はhtml要素のid属性を label というプロパティに保持しておきました。

function TabContent(el) {
  this.el = new Vanilla.Element(el);
  this.current_class_name = 'tab-content--current';
  this.label = this.el.id;
}

2. 選択中に切り替えられる

自身のElementオブジェクトに対して、選択中のclass名を持っていなければ追加します。

TabContent.prototype.toCurrent = function() {
  this.el.addClass(this.current_class_name);
};

3. 非選択中に切り替えられる

自身のElementオブジェクトに対して、選択中のclass名を削除します。

TabContent.prototype.toUncurrent = function() {
  this.el.removeClass(this.current_class_name);
};

TabContentの実装は以上です。まとめたコードはこちら

TabContent = (function() {
  function TabContent(el) {
    this.el = new Element(el);
    this.current_class_name = 'tab-content--current';
    this.label = this.el.id;
  }

  TabContent.prototype.toCurrent = function() {
    this.el.addClass(this.current_class_name);
  };

  TabContent.prototype.toUncurrent = function() {
    this.el.removeClass(this.current_class_name);
  };

  return TabContent;
})();

イベントに紐付けて動かしてみる

最低限の役者が揃いましたので実際に動す為のコードを書いてみたいと思います。
まずはなにはともあれDOMが構築されたタイミングを取れるようにwindowのloadイベントにハンドラをあててからの作業とですね。

addEvent(window, 'load', function() {
  // 各部品のhtml要素を取得
  var tabNav = document.querySelector('.tab-nav');
  var tabNavItemElements = var tabNav.querySelectorAll('.tab-nav__item');
  var tabContentElements = document.querySelector('.tab-contents').querySelectorAll('.tab-content');

  // 格納用の配列を初期化
  var tabNavItems = [];
  var tabContents = [];

  // TabNavItem と TabContent のインスタンスを生成
  for (var i in tabNavItemElements) {
    // 配列のプロパティ length を取り出してしまわないようにチェック
    if (typeof tabNavItemElements[i] === 'object') {
      tabNavItems.push(new TabNavItem(tabNavItemElements[i]));
    }
    if (typeof tabContentElements[i] === 'object') {
      tabContents.push(new TabContent(tabContentElements[i]));
    }
  }

  // タブボタンのクリックイベントを一気に登録する
  addEvent(tabNav, 'click', function(e) {
    // ループ中で使う変数を用意
    var tabNavItem = null;
    var tabContent = null;

    // クリックしたタブボタンのhref属性を取得
    var label = e.srcElement.href.replace(/^.+#/, '');

    // クリックしたタブボタンのli要素を取得
    var clickedItem = e.srcElement.parentNode;

    // 全TabNavItemを回しながら選択状態を切り替えていく
    for (var i in tabNavItems) {
      tabNavItem = tabNavItems[i];
      if (tabNavItem.isEqual(clickedItem)) {
        tabNavItem.toCurrent();
      } else {
        tabNavItem.toUncurrent();
      }

      // TabContentの数も一緒なので同じループで選択状態を切り替えていく
      tabContent = tabContents[i];
      if (tabContent.label === label) {
        tabContent.toCurrent();
      } else {
        tabContent.toUncurrent();
      }
    }
  });
});

以上でタブUIの全体の実装が完了です。

実際に動作するサンプルがこちらです。

ポイントは部品ごとにクラス化しておくこと、イベントハンドリングは全てのボタンに割り当てるのではなく親要素にあてておく、見た目の切り替えはcssで書いてjsはclass属性の付け替えなどにとどめておくこと等です。

標準
IMG_5256
Development

Vanilla JavaScriptを書いてみよう その2(タブUIを実装)

前回はイベントハンドリングとjQueryの様にクラス名でhtml要素を検索出来るquerySelectorを紹介しました。

今回はjQuery等の等のライブラリを一切使わずにタブUIを実装して見るための下準備をご紹介したいと思います。

デザイン

デザインは以下の様なもので、タブのボタンとその内容の文章が3つずつ存在し、選択されていないタブをクリックすると内容と共に選択中の表示に切り替わります。

スクリーンショット 2014-02-24 12.23.24

 

各タブに .tab-nav__item–current というクラスが付いていると選択中の表示になり、内容部分はデフォルトで display: none; に設定されているので .tab-content–current というクラスが付いているもののみ display: block; で可視化するという仕様です。

見た目の制御はcssで行うようにしていますので、JavaScriptからhtml要素のclass属性を操作できる必要があります。

クラスを定義してみる

class属性は element.className というプロパティを使って操作できますので、専用のクラス(ここで言うクラスはインスタンスを生成するためのオブジェクトという意味)を用意しておきましょう。

ところがJavaScriptにはクラスを定義する構文は用意されていません。ではどうやるのかというと、関数オブジェクトに備わっているprototypeという仕組みを利用することでクラス定義をエミュレート出来ます。
具体的には以下のように記述します。

var Person = (function() {
  function Person(name) {
    this.name = name;
  }

  Person.prototype.greet = function() {
    alert('Hello ! My name is ' + this.name);
  }

  return Person;
)();

Personクラスは初期化時に name という変数を受け取り自身の name プロパティに格納します。そして greet というメソッドを持っていて、nameプロパティを連結した挨拶文をアラートする動作をします。

このPersonクラスからインスタンスをインスタンスを生成するには new Person(‘name’) という形で初期化関数を実行します。

var yamagata = new Person('yamagata');

greetメソッドの実行はこうです

yamagata.greet();

Elementクラス

そして今回のために実装したElementクラスはこちらです。

var Element = (function() {
  function Element(el) {
    this.el = el;
    this.id = this.el.id;
  }

  Element.prototype.classes = function() {
    return this.el.className.split(/\s+/);
  };

  Element.prototype.removeClass = function(targetClass) {
    var classes = this.classes();
    for (var i in classes) {
      if (classes[i] === targetClass) {
        classes.splice(i, 1);
      }
    }
    this.el.className = classes.join(' ');
  };

  Element.prototype.addClass = function(targetClass) {
    var classes = this.classes();
    for (var i in classes) {
      if (classes[i] === targetClass) {
        return
      }
    }
    classes.push(targetClass);
    this.el.className = classes.join(' ');
  };

  Element.prototype.hasClass = function(targetClass) {
    var classes = this.classes();
    var exist = false;
    for (var i in classes) {
      if (classes[i] === targetClass) {
        exist = true;
      }
      if (exist) break;
    }
    return exist;
  };

  Element.prototype.isEqual = function(targetElement) {
    return this.el === targetElement;
  };

  return Element;
})();

class属性を操作する場合、複数のclassを扱うことを考慮しなければいけないので、スペースで分割した配列を返す classes メソッドを実装しました。
addClass と removeClass はその配列に対して操作を行う仕組みです。

配列に要素を追加する場合は、末尾に追加する push というメソッドがメソッドが便利です。
また、配列から要素を削除する場合は、spliceというメソッドが便利です。これは削除したい要素のインデックスとそのインデックスの位置から何個の要素を削除するかという個数を指定します。今回は常に1つの要素を消すように 2番目の引数には 1 を渡しています。

var fruits = ['apple', 'banana', 'melon'];
fruits.splice(1, 1); // => bananaが削除される

また特定のclass属性を持っているかチェックをする hasClass と html要素自体が一致しているかをチェックする isEqual も実装しておきました。

このElementクラスを使用するためにはhtml要素を渡して new しなければいけませんので、以下のようにしてタブのボタンをElement化します。

var tabNavItems = [];
var tabNavItemElements = document.querySelectorAll('.tab-nav__item');
for (var i in tabNavItemElements) {
  if (typeof tabNavItemELements[i] === 'object') {
    tabNavItems.push(new Element(tabNavItemElements[i]));
  }
}

.tab-nav__item が付いているhtml要素を全て取得し、1つずつnew Elementしているのですが、typeofで取り出した要素が確実にhtml要素であることを確認しています。
これはfor文では配列のプロパティである length (中身は整数)も取り出してしまうためです。

まとめ

class属性を操作する準備は整いました、普段jQueryで行っている処理もわりと簡単に作れてロジックを書く勉強にもなるのでおすすめです。一度くらい車輪の再発明をしてみるのもいいと思います。
次回はクリックイベントを監視してどのようにタブの切替を行うのかをご紹介します。

標準
IMG_5256
Development

Vanilla JavaScriptを書いてみよう その1

ブラウザ内でアニメーションをさせたり、ユーザーの操作に反応して何かを行う場合必要になるのがJavaScriptです。

最近でこそJavaScriptは便利なライブラリやプリプロセッサが充実してるので、JavaScriptを使ったプログラミングは簡単に始められて楽しいものですが、一昔前まではブラウザ間の差異に悩まされめんどくさいという印象が強かったのでは無いかと思います。

そこで登場したのがjQueryでした。便利なセレクターやメソッドチェーンで簡潔にわかりやすく、そしてクロスブラウザで動作するスクリプトを書けるとあって、これ以外に選択肢を考えることすら無くなったのではないかと思います。

ところで昔からweb制作ではIE対応に悩まされてきた方が多いと思いますが、時代は流れ悪名高いIE6や7の対応はほぼ無くなって2014年現在ではIE8以上としている場合が殆どではないでしょうか。IE8ですら最近は切り捨てられることも増えてきているようです。

さらに最近のブラウザのJavaScriptは進化していて、今までjQueryの領域だと認識されていた部分にも素のJavaScriptが追い付いてきているようです。タイトルにも書きましたが、Vanilla JavaScriptというのは新しいライブラリやフレームワーク等ではなく、素で真っ白な状態のJavaScriptという意味です。

Vanilla JavaScriptだと何がいいのか?jQuery等の読み込みが無くなるのでhttpリクエストをひとつ減らせます。ただ最近ではサイトの公開時にJavaScriptをファイル1つにまとめてを圧縮しておくことも多くなったのでそこまで大きなメリットのようには思えません。ただスマートフォンやタブレットが普及しサイトの半数近くがそれらのモバイルデバイスであり、PCにおいてもモダンブラウザが多数を占めているなら簡単なものはVanilla JavaScriptで書くことで読み込みや実行速度を高めることに一役買うでしょう。

またjQueryの内部ではなにが行われているのか?全ての処理がjQueryの独自実装で動いているのか?そんなことはありません。実はブラウザに同様の機能がある場合はそちらを使うように設計されています。ですのでアニメーションなどは行わずにシンプルなDOM操作のみの場合はjQueryの旨味を十分に発揮させていないことがあるのです。

今回はそんなVanilla JavaScriptではコードをどのように記述していくのかを紹介したいと思います。

イベントの登録を行ってみよう

まずはなにはなくともブラウザ上で動くJavaScriptといえばイベントハンドリングが出来ないと話になりません。なぜならhtmlが読み込まれDOMが構築された後でないと満足にページ内の操作が行えないからです。

body要素にonload属性を追加して関数を実行したり、windowオブジェクトのonloadプロパティに関数を代入する方法でも確実にDOM構築後にスクリプトを実行することが可能ですが、せっかくならjQueryで普通にやっていることを置き換える形で試してみたいと思います。

<script type="text/javascript">
   function start() {
     ...
   }
 </script>
 <body onload="start()">
   ...
 </body>

これでも動くし

<script type="text/javascript">
   window.onload = function() {
     ...
   }
 </script>

これでも動くけど…

<script type="text/javascript">
   jQuery(function($) {
     ...
   });
 </script>

せっかくならこれに置き換わる形で書こう!

JavaScriptでイベント登録を行う関数といえばaddEventListenerがありますが、残念ながらこれはIE8では動作しません。ではどうするか?IE8以前にはattachEventという関数があります。これをif文で使い分けるようにするaddEvent関数を作って対応しましょう。

function addEvent(obj, event_name, handler) {
   if (obj.addEventListener) {
     // addEventListenerが使える場合
     obj.addEventListener(event_name, handler, false);
   } else if (obj.attachEvent) {
     // attachEventが使える場合
     obj.attachEvent('on' + event_name, handler);
   }
 }

次にこれを使ってDOM構築が完了したイベントにハンドラを登録するには以下のようにします。

addEvent(window, 'load', function() {
   alert('Hello');
 });

上記のように書けばwindowのloadイベントに対して何度イベントハンドラを登録したとしても先の処理を上書きすること無く全てが実行されます。

addEvent(window, 'load', function() {
   alert('Hello');
 });
 addEvent(window, 'load', function() {
  alert('World');
 });

HelloにつづいてWorldもアラートされるはずです。

jQueryのようにHTML要素を取得できるquerySelector、querySelectorAllを使ってみよう

イベントハンドリングの壁は超えられたので次にhtml要素を取得してみましょう。

jQueryの大きな特徴としてcssのように使える便利なセレクターがあります。これはページ内にあるDOMノードをJavaScriptから見つけるために欠かせない手順ですが、従来のJavaScriptではあまり開発者にやさしくないものでした。

しかしモダンなブラウザはもちろんIE8以降で使える関数でquerySelectorとquerySelectorAllという2つがあります。前者はセレクタに該当する最初の要素を取得し、後者はセレクタに該当する全ての要素を取得して配列で返してくれます。

<h1>Hello</h1>

このような要素があったとして

addEvent(window, 'load', function() {
  var h1 = document.querySelector('h1');
  alert(h1.innerText);
 });

というスクリプトを書くとh1要素の中身のテキストがアラートされます。 ちなみにquerySelectorを使った場合はh1要素が複数あった場合最初の要素のみ取得されるので

<h1>Hello</h1>
<h1>World</h1>

この場合もHelloのみがアラートされます。

querySelectorAllを使った場合は要素は配列に格納されて返されますので

addEvent(window, 'load', function() {
  var h1s = document.querySelectorAll('h1');
  for (var i in h1s) {
    alert(h1s[i].innerText);
  }
});

と書くとHelloにつづいてWorldもアラートされます。

さらにこれらの関数の便利な点はDOMツリーのスコープが適用されるというところです。上記の例ではdocumentオブジェクトというwindowオブジェクトに続く2番めに大きいオブジェクトですので要素の検索はページ全体に渡ります。しかし2つ目のdiv要素の中にあるh2のテキストのみをアラートしたい場合はどうすればよいでしょうか。しかもh2にはclassもidも降ってないとしたら検索は更に困難になります。

そのような場合にquerySelectorのスコープを活用すると便利です。

<h2>zero</h2>
<div>
  <h2>first</h2>
</div>
<div>
  <h2>second</h2>
</div>

このような要素があるとして

addEvent(window, 'load', function() {
  var h2 = document.querySelectorAll('div')[1].querySelector('h2');
  alert(h2.innerText);
});

このようにすればsecondとアラートされます。
まず最初にdocumentの持っているスコープから2番目のdiv要素を見つけ、そのdiv要素の中にあるh2を見つけたという流れです。querySelectorAllで見つかった要素は配列に格納されているので2番目の要素は[1]で取り出せるというわけですね。

まとめ

いかがでしたでしょうか?このエントリーで書いたJavaScriptはIE8でも問題なく動きます。ちょっとした処理ならjQuery無しで書いてみようかな?という気が少しでも持てれば幸いです。
若干jQuery使用時に比べると簡潔ではありませんが、それでも工夫次第(例えばメソッドチェーンを多用しすぎないとか、別の処理は行を分ける等)で綺麗に書くことも可能だと思います。なによりライブラリに頼らないことでよりJavaScriptに対する理解が深まるのはいいことですよね。

次回では取得した要素に対して変更を行い、実践的な内容に挑戦してみたいと思います。

標準
Native American 12
Development

JavaScriptでネイティブアプリを開発できるTitanium MobileとAlloyをつかってみよう その3

前回はalloy generateコマンドでcontrollerとviewとstyleを生成してモーダルウィンドウを表示してみました。
今回は右から新しいウィンドウがスライドして現れる画面遷移を作成してみたいと思います。

コントローラーの初期状態

まずはメインのコントローラであるindex.jsの中身を以下のようにして、初期画面を表示するだけにしてみます。

$.index.open();

スクリーンショット 2014-01-31 10.09.19

ここで使っている $ はalloyの提供するBaseControllerクラスを継承したindexコントローラのインスタンスです。
また$.indexはビュー内のWindowにid属性がふられていない場合にビューファイルの名称でWindowオブジェクトにアクセスできるようです。

ビューを画面遷移に対応させる

ビューファイルを以下のように書き換えて右へ右へと画面遷移を出来るように準備します。

<Alloy>
    <NavigationWindow id="navigationWindow" platform="ios">
        <Window class="container" title="First Win">
             <Button title="click me" />
         </Window>
     </NavigationWindow>
</Alloy>

WindowをNavigationWindowというオブジェクトでラップしています。こうすることで画面上部にタイトルや前の画面に戻るためのナビゲーションバーが表示されるようになります。

ビューファイルでNavigationWindowを追加し、id属性を定義したのでコントローラーで $.index.open() のままだとエラーしてしまいます。
なので「navigationWindowというidのWindowを開く」というコードに変更します。

controllers/index.js

$.navigationWindow.open();

ビルドしてみると以下のように表示されます。

スクリーンショット 2014-01-31 10.27.42

 

ボタンのイベントハンドラを定義

そして中央に配置したボタンのタグにonClick属性を追加してここをタップすると遷移する動作を行うようにしてみます。

<Button title="click me" onClick="openWin" />

またコントローラーに戻って以下のようにボタンに紐付けたイベントハンドラを定義してみます。

function openWin(e) {
  console.log(e);
}

まずは単に受け取ったイベントオブジェクトをconsole.logしてみるだけにしました。このままビルド(titanium build -p ios)してボタンを押すと以下のようなログが出力されます。

[INFO] {
[INFO]     bubbles = 1;
[INFO]     cancelBubble = 0;
[INFO]     source = "[object __alloyId1]";
[INFO]     type = click;
[INFO]     x = "38.5";
[INFO]     y = "20.5";
[INFO] }

今回は特にイベントオブジェクトの中身に応じて処理を切り替えることはしませんが、こうして書いたコードを一つ一つビルドして確認すればなにか不具合が起きた時に手戻りが少なくて済むようになる事が多いのでなるべくこまめにconsole.logをするようにしています。

さて、このopenWinの中で新たなWindowを生成し画面遷移を起こさせてみたいと思います。

function openWin(e) {
  var win = Ti.UI.createWindow({
     title: 'Sub Win',
     backgroundColor: '#fff'
   });
   $.navigationWindow.openWindow(win);
}

TiとはTitaniumオブジェクトのエイリアスでどちらでも同じものです。Ti.UIというオブジェクトに様々なビューオブジェクトを生成するcreateXxxといったメソッドが定義されています。createWindowメソッドを使うと真っ黒で何も無いWindowが生成されるのでtitleに「Sub Win」、背景色を白に設定しました。

次に$.navigationWindowのopenWindowメソッドに生成した新しいWindowを渡すことでアニメーション付きで画面遷移をしてくれるようになります。
画面遷移の途中は早すぎてキャプチャできないですが遷移後は以下の様な画面が表示されます。

スクリーンショット 2014-01-31 10.49.34

真っ白なWindowを生成しただけですが左上に最初の画面に戻るためのボタンが用意されていますね。これがモーダルにはないNavigationWindowの特徴です。

まとめ

今回紹介した画面遷移はかなりポピュラーなUIデザインパターンなのでこれを覚えておくだけでも簡単なアプリが作れてしまいそうですよね。
しかしNavigationWindowはiOSにしか定義されていないクラスのようです。Androidは端末そのものに戻るボタンを実装しアプリケーション側では意識する必要がないようにデザインされているためでしょう。

要約すると

  1. NavigationWindowにidをふる
  2. コントローラーからふったidを参照して初期画面を表示する
  3. ボタンのonClick属性でイベントハンドラを定義する
  4. 新しいウィンドウを生成してNavigationWindowのopenWindowメソッドに渡す

以上です。

標準
Native American 12
Development

JavaScriptでネイティブアプリを開発できるTitanium MobileとAlloyをつかってみよう その2

こんにちは山形です。
さて今回は前回につづいてTitaniumのAPIを使って具体的にUIの配置等を行っていきたいと思います。

前回はツールのインストールなどを行いました。

alloy generateコマンド

Alloyをインストールするとalloyコマンドが使えるようになります。これがrailsを意識しているようなのでrailsに慣れている人ならわかりやすいかと思います。

まず画面を追加してみたいのでgenerate controllerコマンドをつかって画面を追加してみます。

alloy generate controller my_modal

こうすると
app/controllers/my_modal.js
app/styles/my_modal.tss
app/views/my_modal.xml
の3つのファイルが作成されます。

この段階でtitanium buildしてみても前回同様Hello Worldという白い画面が表示されるだけです。これはTitaniumのデフォルト画面であるindex.jsというコントローラが表示されているだけなのでindexからmy_modalを呼び出す形になります。

それでは順をおって説明していきます。

controller

まずはコントローラー。app/controllers/my_modal.js等ですね。やろうと思えばここに全てのコードを書くこともできます。

しかしAlloyをつかってわざわざMVCスタイルになっているので、コントローラーには画面の遷移や、ボタンのタップに反応してモデルを呼び出すなどにとどめておいたほうがよいでしょう。

最初に呼び出されるコントローラであるindex.jsに以下のコードを追加してmy_modalを開く処理を追加してみます。

var myModal = Alloy.createController(‘my_modal’).getView();
myModal.open({ modal: true });

ここでとりあえずtitanium buildしみると以下の様な画面になりました。

スクリーンショット 2014-01-22 11.13.52

 

「myModalにはopenという関数は無いよ」と書いてありますね。
この原因を探るためにviewファイルを見てみましょう。

view

app/views/my_modal.xml というファイルがmy_modalのviewファイルです。XMLで書かれていますがhtmlの様な感覚でマークアップしていけます。

中身はこんなコードになっています。

<Alloy>
<View class=”container”>
</View>
</Alloy>

これではエラーしてしまいますね。ViewというのはTitanium.UI.Viewクラスのインスタンスなのですが、Viewにはopenという関数はありません。

なのでViewの部分をWindowに置き換えてもう一度ビルドしてみます。

<Alloy>
<Window class=”container”>
</Window>
</Alloy>

スクリーンショット 2014-01-22 11.24.05

 

なんか黒いっすね…

これはWindowのデフォルト背景色が黒だからです。このままじゃよくわかんないのでstyleを変更してウィンドウの存在感を出してみたいと思います。

style

スタイルファイルはapp/styles/my_modal.tssです。tssというのはcssとjsonを掛けあわせたような雰囲気のする形式です。

tssでビューに対置したオブジェクトのプロパティを操作してスタイルを変えていくという感じです。
なのでWindowに対してbackgroundColorの値を変更してみます。

“Window”: {
backgroundColor: “green”
}

なんか普通じゃつまらないので緑色にしてみました。
ついでにビューLabelを追加してこれにも色をつけてみます。

<Alloy>
<Window class=”container”>
<Label>My Modal</Label>
</Window>
</Alloy>

“Window”: {
backgroundColor: “green”
}
“Label”: {
color: “red”
}

そして出来上がった画面がこちらです。

スクリーンショット 2014-01-22 11.45.16

 

まぶしい!ださいですね。

まとめ

軽い感じで起動と同時にモーダル画面を表示させてみましたが、Titaniumの手軽さが伝わったでしょうか??JavaScriptでかけるというのはこんなにもさくさく進めていけるのですね。
次回はもっと複雑な画面遷移をご紹介したいと思います。

標準
Native American 12
Development

JavaScriptでネイティブアプリを開発できるTitanium MobileとAlloyをつかってみよう その1

こんにちは。山形です。
最近はマラソン大会に出るために走り始めました。走った時間や距離を測るのにRuntasticというiPhoneアプリが便利なのですが、今お気に入りの隅田川沿いコースだとルートの解析が出来なくて困っています。GPS機能を妨害するものでもあるんでしょうか?

さて今回はiPhoneアプリ等をJavaScriptで開発できるツールTitanium Mobile(タイタニウムと読みます)を使ってみたので導入部分についてご紹介したいと思います。

JavaScriptとは

best-javascript-sites

JavaScriptは元々ブラウザ内で動くプログラミング言語として開発されました。
今日ではブラウザだけでなくサーバーサイドのスクリプト言語としても使われることが多くなりまりました。Google Chromeに搭載されているJavaScriptエンジンV8を利用したNode.jsや、Javaで実装されたRhino等がそれにあたります。

Titanium Mobileで使用するJavaScriptの種類としてはNode.js環境に近いものと考えていいようです。

Titanium Mobileとは

TITANIUM_logo1

先に触れましたがJavaScriptでネイティブのモバイルアプリをクロスプラットフォームに開発できるツールです。
つまりiOSアプリとAndroidアプリのソースコードを共有しながら同時にビルド出来るということです。

しかし現実はなかなか厳しようです。iOSとAndroidではUIの仕組みが違いますし、iOSにはあってAndroidには無い機能(そのまた逆も)あるからです。その場合コード内で「iOSならばこちらをAndroidならば…」といった条件分岐をすることで解決します。

なんだ結局両方のコードを書くのかと僕も思いましたが、標準的なUIを使っていればそのような場面は少ないですし、アプリケーションのコアになるロジック部分はUIに依存しないことが多いと思いますのでTitaniumを使うメリットは十分にあると感じました。

Alloyとは

alloy

Alloy(アロイ)はTitaniumのためのRailsのようなジェネレーターを備えたMVCフレームワークです。

Alloy自体はNode.jsのライブラリとして配布されています。Node.jsを使ったことのある人であればお馴染みの npm install alloy -g でインストールができます。そしてTitanium CLIと組み合わせることでIDEに頼らない開発環境が手にはいります。

僕はVimmerでRails開発者なのでこれはRailsを使ってきた自分にとってはかなり嬉しい要素でした。

環境を整える

さて実際に環境を整える方法ですが、まずなにはともあれiOS開発ツールであるXCodeをインストールしましょう。
これはAppStoreアプリを立ち上げてXCodeを検索しインストールボタンを押すだけです。

XCodeがインストールできたら今度はNode.jsをインストールしましょう。こちらのオフィシャルサイトからインストーラーが落とせます。

次にTitaniumのインストールはこちらのオフィシャルサイトからインストーラを落としてきましょう。

最後にAlloyのインストールは先に触れた npm install -g alloy で完了です。

プロジェクトを作成してみる

プロジェクトの作成はこちらで手順が紹介されていますが軽く順を追って紹介したいと思います。

まずターミナルでプロジェクトを作成するディレクトリまで移動して以下のコマンドを打ちます。

titanium create --name=sampleapp --id=jp.halenohi.sampleapp --platforms=iphone

nameにはアプリの名前、idはお持ちのドメインを逆転させてサブドメインに当たる部分にアプリ名を入れるのが良いようです。platformは今回はiphoneのみにしました。
Directory to place project: というオプションを聞かれるのですが既にプロジェクトを置くディレクトリにいる場合はそのままエンターでOKです。
こうするとsampleappというフォルダと中にいくつかのファイルとフォルダが作られます。

.gitignore
LICENSE
README
Resources
tiapp.xml

次にsampleappフォルダへ移動して以下のコマンドを打ちます。

cd sampleapp
alloy new

これでappとpluginsというフォルダが作成されました。
以上でプロジェクト作成は完了です。

Hello World

プロジェクトを作成したらコードを書き始める前にそのままビルドしてみます。

titanium build -p ios

pオプションでプラットフォームを指定します。
するとビルドが始まり以下の様な画面でiOSシミュレータが起動しました。

スクリーンショット 2014-01-20 12.41.10

 

Hello World成功です。

まとめ

まだアプリのコードは1行も書いてないですが、ツールをインストールしコマンドを幾つか打つだけでHello Worldが出来てしまいました。これは本当にRailsをやってきた僕には馴染みやすくて嬉しいですね。これでもうXCode上でjkjkとかescキーを誤打しなくて済みますね!

次回で少しUIの作成方法等についてご紹介したいと思います。

標準