Vue.jsをはじめてみる#1 ~公式ガイドを読む編~


はじめに

CSSがすきなフロントエンドエンジニアのナユです。 フロントエンドエンジニア Advent Calendar 2016 12日目の記事です。

私はCSSがすきですが、フロントエンドエンジニアを名乗る以上はしっかりとしたJavaScriptがかける必要があります。 ですので、このアドベントカレンダーを機に「Vue.js」勉強ログをつけてみることにしました。

ありがとうアドベントカレンダー。これがなければゆうゆうと「来年は頑張る」とかいってたはず。

現状スキルセット

スキルセットとしては、 - ただ動くだけのjQuery/JavaScriptなら調べながら使えます。 - あとはHTML/CSSをかけます。 - Reactちょっとだけやったことあります

というレベル。ほぼマークアップエンジニアです。 いや、アクセシビリティはそんなに詳しくないので、戒めの意味でも「HTMLコーダー」レベルです。

今の課題は、「いいJavaScriptを書く」というところにあるかなと思っているので、知見を広げるために「Vue.js」というフレームワークを触ってみることにします。

同じくらいのスキルセットの人は一緒に頑張りましょう。 もっと上のレベルの方は、ご教授のほどよろしくお願いします!

概要を掴む

まずは、Vue.jsがなんなのか、あたりをつかみます。

vue.js 日本語公式ページあるの嬉しい。 軽くて速い、仮想DOM、ふむふむ。

公式ガイドは、HTML、CSS そして JavaScript の中レベルのフロントエンドの知識を前提にしています。フロントエンドの開発が初めてであるならば、最初のステップとして、フレームワークに直接入門するのは良いアイデアではないかもしれません。基礎を学んで戻ってきましょう!他のフレームワークでの以前の経験は役に立ちますが、必至ではありません。

はじめに - Vue.js

えっ、どうしようかな…… とりあえず、一通り触ってみて、わかるレベルでやっていきます。

インストール

少なくとも、触ってみるだけならば <script src="https://unpkg.com/vue/dist/vue.js"></script> を読み込むだけでいいっぽい。 この辺はjQueryと同じですね。

npmからインストールしてきてbuildして…ていうのはしっかりした開発か、自分が必要になったら改めて検討します。

まずはHello,World

<div id="app">
  {{ message }}
</div>
var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue!'
  }
})

html内の{{ message }}にappで定義したmessage:Hello Vue!が書き込まれるっていう風な動きですね。

newっていうのは、JavaScriptのnew演算子ですね。 ちょっと復習します。

new演算子?

JavaScriptには、オブジェクトという考え方があります。 そこで用いられるのがnew演算子です。 まずは、オブジェクトについて少し説明。

オブジェクト

名前をキーにアクセスできる配列の事を言います。 いろんなデータやデータ操作についてのあれこれがつまった入れ物のようなものです。

例えば「nayu」というオブジェクトを定義するときはこんな感じです。

var nayu = {
  name  : nayu,
  sex   : male,
  birth : 1993/04/28,
  part  : frontendengineer
}

こういう風に、オブジェクト内に名前をつけて情報を定義しておきます。 すると、「ナユの誕生日」をデータとして使いたい時にnayu.birthだとかnayu['birth']だとかでデータにアクセスできます(これらの違いは割愛)。 nayu,1993/04/28などのデータを プロパティ と呼びます。

これらは宣言したあとからも外から書き換えることができます。

さて、この、すごい入れ物であるオブジェクト。 今は「nayu」オブジェクトを自分で定義しましたが、JavaScriptにはもともといろいろなオブジェクトが用意されていて、呼び出すだけで様々なデータ操作が行えます。

では、もともと用意されたオブジェクトに直接外からアクセスしてデータを書き換える行為が発生したときはどうでしょう。

答えは、そのデータを使っている別の場所では予定と違うデータに書き換わってしまっていて、不都合が発生します。

そのため、用意されているオブジェクトを使う時は、「原本」ではなく「コピー」を作って使いましょうということになっています。

この、オブジェクトをコピーする行為を「インスタンス化」、できあがったコピーは「インスタンス」と呼びます。 (instanceは「事実、事例、実例」という意味があります。 実物のサンプルコピーということで、まさに実例ですね。)

Gitでいうとブランチを切ってきてそのエリアで作業する、みたいなものです。

さて、本題に戻りましょう。 今のnew演算子はインスタンスを作ることだということを踏まえて見てみると、この操作はVue.jsの元々用意しているオブジェクトVueをインスタンス化し、それの中身を書き換えてappという名前のオブジェクトとして定義した、ということが記述されているとわかります。

ふむふむ、なるほど、Vue.jsは、テンプレートを提供してくれているのですね。 コピーして、書き換えて、好きに使えよ、という感じでしょうか。

v-bindでデータバインディング

<div id="app-2">
  <span v-bind:title="message">
    Hover your mouse over me for a few seconds to see my dynamically bound title!
  </span>
</div>
var app2 = new Vue({
  el: '#app-2',
  data: {
    message: 'You loaded this page on ' + new Date()
  }
})

htmlの方で1点、みたこともないものが出てきましたね。 v-bind:titleとは何でしょうか…。

公式ガイドによると、ディレクティブというもののようです。 挙動を見ると、「title属性にmessageのプロパティを書き込んだ」という風に見えます。 HTMLにデータを書き込むことを「束縛する」と表現するのか…? データバインディング、みたいな単語はたまに聞くのですが、その辺も関連してくるのかな。 この辺はおいおい勉強していきましょう。

v-ifで条件分岐

<div id="app-3">
  <p v-if="seen">Now you see me</p>
</div>
var app3 = new Vue({
  el: '#app-3',
  data: {
    seen: true
  }
})

v-ifができました。if文っぽいですね。 seen:trueを返すと要素が出現、seen:falseを返すと要素が消滅します。 別にseenじゃなくてnyankoとかでも行けました。 要は、v-if="true"なのかv-if="false"なのかで判断するっていうことですね。うん、これはすぐわかった。

ちなみに、ガイドによると、消滅、更新、などのタイミングでのトランジションエフェクトもVueは提供してくれているようです。これはよさそうですね。

v-forでループ

<div id="app-4">
  <ol>
    <li v-for="todo in todos">
      {{ todo.text }}
    </li>
  </ol>
</div>
var app4 = new Vue({
  el: '#app-4',
  data: {
    todos: [
      { text: 'Learn JavaScript' },
      { text: 'Learn Vue' },
      { text: 'Build something awesome' }
    ]
  }
})

なるほど、徐々にVueのやり口が見えてきました。 todostextプロパティが尽きるまで<li>を描画するんですね。

XX in YYは、in YYは、JS側のtodosオブジェクトをさしてますね。 todoはHTML側で任意に設定されています。 textはtodosオブジェクト内で定義されています。 この辺の文法は、またしっかり学ぶ必要がありそうです。

consoleからapp4.todos.push({ text: 'New item' })を叩くと要素が増えました。 push()は配列の末尾にデータを突っ込むメソッドですね。

v-on,v-modelでユーザー入力の制御

<div id="app-5">
  <p>{{ message }}</p>
  <button v-on:click="reverseMessage">Reverse Message</button>
</div>
var app5 = new Vue({
  el: '#app-5',
  data: {
    message: 'Hello Vue.js!'
  },
  methods: {
    reverseMessage: function () {
      this.message = this.message.split('').reverse().join('')
    }
  }
})

v-on:click clickイベントらしきものができました。 clickするとreverseMessageメソッドを呼び出す感じですね。 定義の仕方は、methodsオブジェクトにreverseMessageを記述。 中身は普通のJavaScriptのfunctionですね。 内容的には、 - split(“):app5messageを一文字ずつ区切って配列に格納 - reverse():順番を全部ひっくり返す - join(“):連結(つなぎ部分に挿入する文字はなし)

そのインスタンスのみで通用する値、メソッドがあるってなんか不思議な気分ですね。 こういうのがない場合、グローバルに存在する関数はどこからでも呼出せていたので。 これだとel:#app-5内で通用する関数ってことですよね。 他の場所で使いたければ、都度指定する必要があるわけでしょう。

<div id="app-6">
  <p>{{ message }}</p>
  <input v-model="message">
</div>
var app6 = new Vue({
  el: '#app-6',
  data: {
    message: 'Hello Vue!'
  }
})

なるほど、データバインディングがなんとなくわかりました。 つまりは、リアルタイムに片方を、もしくはお互いを更新するってことですね? さっきのv-bindはJavaScriptからHTMLだったけれど、今回のv-modelは双方向ですね。

HTMLの<input>の要素がJavaScriptのmessageを書き換え、すぐさまHTMLの{{ message }}に反映するといった感じですね。 なるほどです。データバインディング、すばらしい。

コンポーネントシステム

これは多分、だいたいCSS設計のコンポーネントシステムとおなじようなものでしょう。。

コンポーネントの定義

Vue.component('todo-item', {
  template: '<li>This is a todo</li>'
})
<ol>
  <!-- todos 配列にある各 todo に対して todo-item コンポーネントのインスタンス作成する -->
  <todo-item></todo-item>
</ol>

なんとなく、感覚的にわかった感じはあります。

コンポーネントに値を渡す

<div id="app-7">
  <ol>
    <!-- todo オブジェクトによって各 todo-item を提供します。それは、内容を動的にできるように表します。-->
    <todo-item v-for="item in groceryList" v-bind:todo="item"></todo-item>
  </ol>
</div>
Vue.component('todo-item', {
  props: ['todo'],
  template: '<li>{{ todo.text }}</li>'
})
var app7 = new Vue({
  el: '#app-7',
  data: {
    groceryList: [
      { text: 'Vegetables' },
      { text: 'Cheese' },
      { text: 'Whatever else humans are supposed to eat' }
    ]
  }
})

流れ的には - <todo-item>コンポーネントはprops(値)の箱をもっていて、親コンポーネントからpropsを受け取る。 - v-bindを使ってtodo.textデータをHTML上の<todo-item>と紐付ける - HTML上に<todo-item>groceryListのアイテムの数だけ生成される

うーん、理屈はわかったんだけど、v-forあたりをうまくかけるかは微妙です。 いちいち参照しないとわかんなそう。すぐ慣れる気はします。


さて、ふんわりとした雰囲気は掴むことができました。 次回は引き続きガイドを進めつつ、わからない単語がでてきたら都度調べて、という風にやっていきます。

参考文献

改訂新版 JavaScript本格入門 vue.js