Vue.js超入門〜基本文法と具体的使い方など〜

9月にVueについて学習しました。その学習レポート。

Vueで何ができるの?

まずは何ができるかですが、辞書的な説明だと下記のような2点がよく取り上げられています。

辞書的な説明
  1. JavaScriptでユーザーインターフェース(UI)部品を作るためのフレームワーク
  2. two way data binding=双方向データバインディングができる

ただ、これじゃなんのこっちゃ分からないので僕なり(js素人)にいろいろ勉強したみた結果として概要を噛み砕くと、

僕的な説明
  1. 使い回しできる部品が作れる(ちょうどWPのショートコードのような感じ)
  2. 入力されたデータがリアルタイムで表示に反映される(=双方向データバインディング)

ちなみに双方向データバインディングの例としてよく用いられるのがこれ。

データを更新すると見た目に反映され、見た目を更新すればデータに反映されるといった具合。

Vueのメリットは下のような感じ。

  • モダンでカッコいい(大事)
  • 最近人気高め
  • 日本語ドキュメント充実
  • コード見やすい
  • コード書きやすい

もともとjsを勉強している時からjsは書いてて疲れると言うか気持ちよくない。そこで『何かしらFW使いたいなぁ、でもjQueryの悪評ひどいしなぁ』とか思っていたら発見したのがVueです。こだわりないのでjQuery勉強しても良かったのですが、『Vue書けます』の方がカッコいい。Reactは意味不明すぎて無理でした

デモ

こちらは学習1日目に作ったもの。こんな感じのことができるよ〜ってのが明確化すると学習モチベが上がりがち。

ちなみに先のjQueryとVueの違いについては下のPenがわかりやすいです。

少し複雑になるとjQueryと記述量に差が出てきますね〜。

//jQuery

(function() {
  var counter = 0
  var list = ['Apple', 'Banana', 'Strawberry']

  init()

  $(document).on('click', '#add', function() {
    addItem('Orange' + (++counter).toString())
  })
  $(document).on('click', '.remove', function(event) {
    $(event.target).parent().remove()
    updateLength()
  })

  function init() {
    for (var i = 0; i < list.length; i++) {
      addItem(list[i])
    }
  }

  function addItem(name) {
    $('#list').append('<li>' + name + ' <button class="remove">remove</button></li>')
    updateLength()
  }

  function updateLength() {
    $('#length').text($('#list li').length)
  }
})()

//同じ機能をVueで作るとこんな感じ

new Vue({
  el: '#app',
  data: {
    counter: 0,
    list: ['Apple', 'Banana', 'Strawberry']
  },
  computed: {
    length: function() {
      return this.list.length
    }
  },
  methods: {
    addItem: function() {
      this.list.push('Orange' + (++this.counter).toString())
    }
  }
})

って言うわけで復習がてらVueの初歩的・基本的な部分についてまとめていきます。

なお、ここで出てきたコードを全て写経するのが一番手っ取り早く慣れるための最適な手段かなと思います〜。僕もVueのインストール用スクリプトタグ以外全てコピペ使わずに手書きです。

準備

ここではCodePenを使用していきます。JSFiddleとかでも良いと思います。わざわざローカルにファイル作って〜ってやるよりよっぽど早いですね。

HTMLテンプレとCSSリセットの準備

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
  </head>
  <body>
    
  </body>
</html>
*,*::before,*::after{
  padding: 0;
  margin: 0;
  box-sizing: border-box;
}

一般的なHTML/CSSをまずは書いときましょー。

Vueのインストール

HTMLファイル内に

<script src="https://cdn.jsdelivr.net/npm/vue"></script>

を入れるとVueが使えるようになります。(body閉じタグ前が好ましい)

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
  </head>
  <body>
    <!--追加-->
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  </body>
</html>

たったこれだけ。

双方向データバインディングを感じる(v-model)

記事冒頭で見せたinputにデータが入力されるとUIに反映されるアレを作ります。

僕がやった教材では、divタグに#appを追記してVueを使っていくケースが多かった(と言うか全部そうだった)ので、慣習?文化?にならいます。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
  </head>
  <body>
    <div id="app">
      <!--ここにVue関連のコードを書くイメージ-->
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue"></script>
  </body>
</html>

また、ついでにinputタグも作っておきましょう。

あと、これ以降はheadなどのVueの学習に不要な要素は省略して記述します。(コード長くなっちゃうので)

<div id="app">
  <input type="text" placeholder="入力すると...">
</div>

それではUIにひもづくモデル作りに入ります。

let vuemodel = new Vue({
  //ここにVue書いていく
})

この型が基本です。letで変数vuemodelを定義してそこにVueを書いていく。また、vuemodelはvmと省略して書かれることが多いそう。別に変数名自体は何でも良いとは思うんですが、とりあえず真似ときます。

ここまでできたらこのVueがどの領域と結びつくかをelementで定義します。elementはelと省略形で書かれます。今回はdiv#appに紐づけたいので、#appをelに記述。

let vm = new Vue({
  el : '#app'
})

=でなく、:を使うのは慣れるまで引っかかりそう。ここまででvuemodelがdiv#appに紐付くVueであると言うところまで書けました。万歳。

続いてdataを作っていきます。キーと値で定義できます。

let vm = new Vue({
  el : '#app',
  data : {
    message: '' //空の値
  }
})

これで空の値を持つmessageと言うキーが完成。あとはこのキーをビューに表示するだけ。

キーをビューに表示するには二重の波括弧 {{}}を使います。

<div id="app">
  <input type="text" placeholder="入力すると...">
  <p>{{message}}</p>
</div>

現段階ではmessageは空の値なのでpタグの中に何も表示されないのですが、例えばmessageの値にHello Worldを入れてみるとpタグにはHello Worldが表示されます〜。

ここまでで、dataからUIへの反映ができています。次にUI(ここではinput)からdataへの反映ができるようにします。

今回はinputタグを通してデータへ値を受け渡しするので、inputタグの中に必要な記述をします。それがv-modelです。

<div id="app">
  <input type="text" placeholder="入力すると..." v-model="message" >
  <p>{{message}}</p>
</div>

こんな風にinputタグにv-modelを書き、messageを指定してあげるとinputに入力されたデータがVue側へと渡ります。

あとは適当にCSS書いて

body{
  margin: 30px;
  text-align: center;
}

input{
  padding: 15px;
  width: 300px;
  margin-bottom: 15px;
  border: 0;
  border-bottom: 1px solid #333;
  transition: all 1s;
}

input:focus{
  outline: none;
  border-bottom: 1px solid red;
}

p{
  font-family: serif;
  font-size: 32px;
  color: red;
}

良い感じにすれば、

完成!双方向データバインディングです。カッコいい。

参考:https://jp.vuejs.org/v2/guide/forms.html

繰り返し処理がしたくて疼くあなたへの処方箋(v-for)

それでは新しいPenを作成し、今度は繰り返し処理です。

<div id="app">
  <ol>
    <li></li>
  </ol>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.13"></script>

ここまで準備できたら、先ほどと同様にVueを書いていきます。

let vm = new Vue({
  el : '#app',
  data : {
  }
})

先ほどはmessageキーに一つの値だけしか入れられないような作りでしたが、キーは配列[item1, item2, item3]の形を取れば複数の値を持つこともできます。

let vm = new Vue({
  el : '#app',
  data : {
    favorite : ['お肉', '栗', 'リンゴ'] //配列
  }
})

この配列の値を単品でビュー側で表示するには、

<div id="app">
  <ol>
    <li>{{ favorite[0] }}</li>
  </ol>
</div>

のようにすれば取り出せます。ちなみに配列の一番目の値を取り出すには[0]、二番目の値を取り出すのは[1]と、三番目の数字を取り出すには[2]といった具合です。

本題の繰り返し処理をするには、v-forを使います。繰り返しをしたい箇所のタグに含めればOK。

<div id="app">
  <ol>
    <li v-for="food in favorite">{{food}}</li>
  </ol>
</div>

こんな感じです。v-forは

<li v-for="好きな文字列 in キー名">{{好きな文字列}}</li>

こんな感じで使うわけですが、好きな文字列よりはキー名を複数形にしてその単数形にするか、itemとかするとわかりやすいかも。

分かりやすい例)

<li v-for="item in menu">{{item}}</li>

<li v-for="food in foods">{{food}}</li>

ここまででコードは完成したのでまとめると、

<div id="app">
  <ol>
    <li v-for="food in favorite">{{food}}</li>
  </ol>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.13"></script>
let vm = new Vue({
  el : '#app',
  data : {
    favorite : ['お肉', '栗', 'リンゴ']
  }
})

こんな感じなのですが、せっかくなので、入力同期も自分で考えて付け加えて下のPenのようなものを作ってみてもいいかもですね。

ちなみに、これをもう少し応用するとデータの保持や削除もできますし、簡易Todoリストが作れます。

クリックでソイヤさせる(v-on:)

それでは新しいPenを作成します。何度も繰り返しですが、繰り返ししないと僕は覚えられないので付き合ってください。今回はボタン使うのでボタンをば。

<div id="app">
  <button>クリック</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
let vm = new Vue({
  el : '#app'
})

ここまではelementの下にdataを書いていましたが、今度はmethods(メソッド)を書いていきます。ここらは普通のjsですね。

let vm = new Vue({
  el : '#app',
  methods : {
    soiya(){
//  soiya : function(){ でも同じ
      alert('ウェイソイヤ');
    }
  }
})

これで神々しきsoiyaメソッドができました。このsoiyaメソッドをビュー側で呼び出すには、v-on:イベントを使います。

<div id="app">
  <button v-on:click="soiya">クリック</button>
</div>

これでボタンがクリックされた時にソイヤメソッドが読み込まれます。ソイヤ!

ちなみにv-on:はよく使うものなので、@という省略形があります。

<!--どちらも同じ-->
<button v-on:click="soiya">ハァ〜、ソイヤっ!</button>
<button @click="soiya">ハァ〜、ソイヤっ!</button>

あとはイベント関係ですが、

<!--クリック-->
<button @click="soiya">ハァ〜、ソイヤっ!</button>
<!--ダブルクリック-->
<button @dblclick="soiya">ソイソイ!</button>
<!--マウスオーバー(カーソルを上に当てた状態)-->
<button @mouseOver="soiya">ウェイ!</button>

色々あります。詳しくはこちらのQiitaが参考になるかと。

ここまでできたらソイヤ集ができ上がりです。ソイヤ!

ソイヤの表示・非表示を切り替える(v-if)

新しくPenを作成。繰り返し。

<div id="app">

</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.13"></script>
let vm = new Vue({
  el : '#app',
})

タグにv-ifを含めるとキーの値が真だった時のみ描画されます。

例えば、

<div id="app">
  <div v-if="soiya">ウェイ</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.13"></script>

があり、

let vm = new Vue({
  el : '#app',
  data : {
    soiya : true
//  soiya : false こちらの場合表示されない
  }
})

とある時、soiyaキーの値はtrueなので、ウェイが表示されます。

このデータの真偽値を先ほどのv-onの処理で切り替えたい時は

<div id="app">
  <button @click="soiya=!soiya">ソイヤ</button> <!--追加-->
  <!-- 「=!」は「=」の否定形 -->
  <div v-if="soiya">ウェイ</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.13"></script>

こんな感じにしてあげると、下のPenのような表示・非表示の切り替えができます。

超イイネ!ボタンを繰り返し使う(components)

それでは、新規Pen作成。

<div id="app">

</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
let vm = new Vue({
  el : '#app',
})

今回は超イイネ!!ボタンを作りますが、Vue独自な書き方をします。

<div id="app">
  <super-like></super-like> <!--任意の文字列で大丈夫-->
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

あたかもHTMLのタグかのように独自タグを作っていいという書き方です。

ただ、当然このままだとロクに使えず、変なマークアップになってしまうので、Vueの方で<super-like>はコンポーネントだよと明記します。

コンポーネントがあることを示すにはcomponentsで括ります。

let vm = new Vue({
  el : '#app',
  components : {
    'super-like' : superLike //左側にcomponent名、右側にオブジェクト名
  }
})

これで、div#app内の<super-like>コンポーネントはsuperLikeというオブジェクトだよという意味になります。オブジェクト名はキャメルケース(つなぎ目が大文字の形)です。

ここまでできたら後は通常のjsのように変数としてsuperLikeを定義します。ここで使うのはVue.extendtemplateです。そのまんまですね。

let superLike = Vue.extend({
  template : '<button>超イイネ!!</button>'
})

let vm = new Vue({
  el : '#app',
  components : {
    'super-like' : superLike //左側にcomponent名、右側にオブジェクト名
  }
})

これで<super-like>タグは再利用可能なテンプレートになりました。複数個書けば当然その書いた分だけ設置できます。イイネ!

HTMLがシンプルで良い感じですね。

ただ、templateには一つだけ注意点があって、

let superLike = Vue.extend({
//  template : '<button>CLICK</button>' これは当然OK
//  template : '<button>CLICK</button><button>CLICK</button>' これはダメ
})

というように二つのブロックを設置することができません。二つ以上の要素を持つテンプレートを作りたい場合は、

let superLike = Vue.extend({
  template : '<div><button>CLICK</button><button>CLICK</button></div>'
})

というように、何らかの親要素(ここではdiv)で囲ってあげて一つの要素にしなければならないという制限があることだけ覚えておきましょ〜。

超イイネ!!ボタンの超イイネ!!数をカウントアップ

このセクションは新規Penを作ってもForkでも構わないかと。とりあえず下記のコードを前提に進めていきます。

<div id="app">
  <super-like></super-like>
  <super-like></super-like>
  <super-like></super-like>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
let superLike = Vue.extend({
  template : '<button>超イイネ!!</button>'
})

let vm = new Vue({
  el : '#app',
  components : {
    'super-like' : superLike
  }
})

ここまで準備出来たら、ボタンがクリックされるたびにカウントアップされる機能をつけていきます。

必要なのはカウントを記録するデータ部分クリックされるたびにカウントをするメソッドです。

まず、クリックされるたびにカウントアップするというのは、過去にやった@clickでイベントを設定すれば作っていけます。メソッド名はcountとかにしておきます。

let superLike = Vue.extend({
  template : '<button @click="count">超イイネ!!</button>'
                        // ↑追記
})

let vm = new Vue({
  el : '#app',
  components : {
    'super-like' : superLike
  }
})

ここまでで、super-likeタグでsuperLikeオブジェクトが呼び出され、そのテンプレートのボタンをクリックするたびにcountメソッドが読み込まれるという処理が出来上がりました。

superLikeオブジェクトの中にcountメソッドを作っていきます。処理は単純に1をプラスすれば良いだけですね。ここではnumというデータを使うと仮定して、numに1つずつ足していく処理を書いていきます。

let superLike = Vue.extend({
  template : '<button @click="count">超イイネ!!</button>',
  methods : {
    count : funtion(){
      this.num ++ ;
    //this.num += 1;でも大丈夫
    }
  }
})

let vm = new Vue({
  el : '#app',
  components : {
    'super-like' : superLike
  }
})

あとは、データとしてnumを定義すればいいだけなのですが、componentのdataは関数で返さなければならないというルールがあるので、少し書き方がこれまでとは異なります。

let superLike = Vue.extend({
  template : '<button @click="count">超イイネ!!</button>',
  data : function() { //こんな感じにすれば関数でデータを返せる
    return {
      num : 0
    }
  },
  methods : {
    count : function() {
      this.num ++ ;
    }
  } 
})

let vm = new Vue({
  el : '#app',
  components: {
    'super-like' : superLike
  }
})

あとは template の buttonタグの中に {{ num }} とか書いてカウント数を呼び出せば、出来上がり。

クラスの動的処理(v-bind:)

今まで散々狂った見出し使っておいてここに来て息切れしてしまいすみません。新しくPenを作成しましょう。

<div id="app">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
let vm = new Vue({
  el : '#app',
})

せっかくなので、ここまで準備できたら自分で考えながら下記の条件を満たすコードを書いてみるのもいいかもですね。

  • HTMLでは<soiya>タグを使う
  • <soiya>タグでは<button>タグが描画される(<button>タグ内の文言は任意の文字列でok)
  • <soiya>で呼び出された<button>をクリックした時、uxeiメソッドが呼び出される
  • uxeiメソッドでは”ソイヤ!”がalertされる
  • 上に<h2>で見出しをつける(任意の文字列でok)

我ながら意味不明すぎるのですが、多分ここまでで出てきた知識を割と手広く拾える問題なのかなと思います。

<div id="app">
  <h2>アラート</h2>
  <soiya></soiya>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
let soiya = Vue.extend({
  template : '<button @click="uxei">ウェイ</button>',
  methods : {
    uxei : function(){
      alert('ソイヤ!');
    }
  }
})

let vm = new Vue({
  el : '#app',
  components : {
    'soiya' : soiya
  }
})

こんな感じですね。適当にcssでお化粧します。下記のPenからコピペしてもいいですし、自分で作ってみてもいいと思います〜。

See the Pen クラスの動的処理1 by Takasaki (@tkskds) on CodePen.

それでは、次に下記条件を満たすコードを付け足していきます。自分で考えてやってみましょ〜。なお、既存のコードは必要に応じて変更しましょう。

  • 続けてその下に<h2>タグで見出しをつける(任意の文字列でok)
  • HTMLファイル内に<button>タグを書いていく
  • <button>がクリックされるたびにsoiメソッドが読み込まれる
  • soiメソッドではyaというデータに1プラスされていく
  • <button>の下に<p>タグを用意する(<p>タグ内は任意の文字列)
  • <p>タグにはyaの数字を表示する

それでは書いていきます〜。

See the Pen クラスの動的処理2 by Takasaki (@tkskds) on CodePen.

で、ここからが本題のクラスの動的処理(v-bind)。

先ほど作ったデータyaをカウントできるボタンを使い、yaが10の倍数の時にクラスの付与を切り替えできるようにします。

実現するには真偽値を取れるデータをもう一つ用意し、ここではuxeiとします。

let vm = new Vue({
  el : '#app',
  components : {
    'soiya' : soiya
  },
  data : {
    ya : 0,
    uxei : true //追加
  },
  methods : {
    soi : function(){
      this.ya ++ ;
    }
  }
})

このsoiメソッドに機能を追加していきます。カウント数が10になったのをキッカケにuxeiの真偽値を入れ替えればいいので、

let vm = new Vue({
  el : '#app',
  components : {
    'soiya' : soiya
  },
  data : {
    ya : 0,
    uxei : true
  },
  methods : {
    soi : function(){
      this.ya ++ ;
      if ( this.ya % 10 == 0){
        this.uxei=!this.uxei
      }
    }
  }
})

これで10で倍数時に条件分岐してuxeiの真偽値が入れ替わります。

そのデータの変更をビューで取得する際に使うのが、v-bindです。

<div id="app">
  <h2>アラート</h2>
  <soiya></soiya>
  <h2>ソイヤ</h2>
  <button @click="soi">ソイソイ</button>
  <p>現在{{ ya }}ソイヤ目</p>
  <h2>動的処理</h2>
  <p v-bind:class="{'uxei':uxei}" class="uxeiuxei">ウェイ</p>
  <!--v-bind:class="{'付与されるクラス名':真偽値}"-->
  <!--真だった時にクラスが付与される-->
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

真の時にクラスが付与されます。データyaが10の倍数になるたびにこの真偽値は切り替えられますが、今回は最初の定義時にtrueでしたので、pタグにはuxeiクラスとuxeiuxeiクラスが当てられています。以後yaの値が10の倍数を迎えるたびにuxeiが外されたり付与されたりといった具合ですね。

ここまで出来てもクラスの内容を書かなければ何も変化がビュー側で起こらないので、今回はuxeiクラスが付与されているときは元気なさそうな感じで、uxeiクラスが外されたときは元気な感じにします。そうですね、意味不明ですね。

.uxeiuxei{
  font-size: 3em;
  color: red;
}

.uxei{
  font-size: 1em;
  color: #333;
}
/*!importantでもいいですが、cssは後方の優先度が高いのでこの方(!important未使用)が好ましい*/

また、先ほど使ったv-if合わせて使い、データuxeiが真のときは余計に元気なさそうに見せるために三点リーダーを付与します。

<h2>動的処理</h2>
<p v-bind:class="{'uxei':uxei}" class="uxeiuxei">
  ウェイ<span v-if="uxei">...</span>
</p>

これで完成品がこう。

See the Pen クラスの動的処理3 by Takasaki (@tkskds) on CodePen.

最後は復習とv-bindに触れたいがために意味不明な流れになってしまいましたが、とりあえずこれで超基本的な部分はさらえました。

ちなみにv-onは@と省略ができたようにv-bind:は:だけでも同じ意味になります。

<p v-bind:class="{'uxei':uxei}"> == <p :class="{'uxei':uxei}">

また、データから引っ張ってくる感じがv-modelと同じように思えますが、どうやらv-bindは単方向、v-modelは双方向だそう。

つまり、ビュー側からデータへ、データからビューへという双方向のやりとりをするときはv-modelを、データからビューへという単方向の場合はv-bind。

僕自身まだVueに触れて2〜3日なのとjsにそこまで明るいわけでもないので説明が不十分であったり、非効率なコードを書いているかもしれません。ご愛嬌。

基本文法(ディレクティブ)まとめ

v-XXで始まるテンプレートをディレクティブと呼びます。

v-model
  ……データの受け渡しに使用(双方向)

例) <input v-model="message">

v-for
  ……繰り返し処理に使用

例)<li v-for="favorite in favorites">{{favorite}}</li>
例)<li v-for="item in todos">{{item}}</li>

v-on:(=@)
  ……イベントの設定に使用

例)<button @click="soiya">ソイヤ</button>

v-if
  ……真偽値によって描画の切り替えをするときに使用

例)<p v-if="soiya">そいや!</p>

v-bind:(=:)
  ……データの受け渡しに使用(単方向)

例)<p v-bind:class="{'uxei':uxei}" class="uxeiuxei">

とりあえずここまで。また2〜3週間くらい勉強したら修正や加筆予定。

おまけ

無料で作れる!Vueでアプリを作るための参考ページ9選

コメントを残す

メールアドレスが公開されることはありません。