【Vue.js】Vue.jsの基礎知識

# Vue.js とは

- javascriptのフレームワークの一つ。
- JQueryよりも記述が簡単。
- **ディレクティブ機能**により、HTMLとjavascriptの間でデータ連携を行う役割を果たす。
- Raectが単方向のデータバインディングであるのに対し、Vue.jsは**双方向**のデータバインディングが可能（※）。
- React、Angularに並び人気があるフレームワーク。
- ECMAScript 5 準拠のブラウザに対応。IE8以前のバージョンはサポートされていないため注意。
（詳しくは[こちら](https://caniuse.com/#feat=es5)を参照）

※**双方向データバインディング**：
UI、データのいずれか一方が更新されれば、もう一方も更新される仕組みのこと。（＝データとUIが常に同期される）

# Vue.jsの読み込み（インストール）

事前にお使いのブラウザに**Vue Devtools**をインストールしておくことをお勧めします。
筆者はchromeを使うので拡張機能[vuejs-devtools](https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd)を入れました。

## Vue.jsの読み込み方法 

1. CDN ←プロトタイピングや学習を目的とする場合はこちらがオススメ
2. NPM
3. [直接組み込み](https://jp.vuejs.org/v2/guide/installation.html)

今回は学習用なので、CDNを読み込みました。

下記コードをbody終了タグの直前に挿入すれば完了。

```html:html
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script>
or
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
```


（例１）html内にスクリプトを記述する場合

```html:html
<body>
  <!-- html -->
  <div>
     <span>TEST</span>
  </div>

  <!-- js -->
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
      // js記述部分
  </script>
</body>
```

（例２）jsファイルを別途作成する場合

```html:html
<body>
  <!-- html -->
  <div>
     <span>TEST</span>
  </div>

  <!-- js -->
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="js/test.js"></script>  // vue.jsの下で読み込むこと
</body>
```

# Vue.jsの基礎
## 目次

１．マスタッシュ構文（単方向データバインディング）
２．ディレクティブ
　　２－１．v-bind
　　２－２．v-if
　　２－３．v-show
　　２－４．v-for
　　２－５．v-on
　　２－６．v-model（双方向データバインディング）
３．コンポーネント

## １．マスタッシュ構文（単方向データバインディング）

### マスタッシュ構文とは？
`{{ }}`で囲った構文のこと。（`{{ }}`がマスタッシュ＝口ひげに見えるからこのような名前になったとか）
マスタッシュ構文を使用することで、Vueインスタンス内に作ったdataオブジェクトのプロパティを反映させることができます。


### まずは「Hello World」

次のようなディレクトリ構造で作成していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/e933ee31-ed22-9877-3094-866750d45570.png)

まずはhtml内に次のように書いてみましょう。

```html:main.html
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<link rel="stylesheet" href="css/common.css">
		<link rel="stylesheet" href="css/main.css">
		<title>Main</title>
		
	</head>
	<body>
		<div id="app">
			{{ message }}
		</div>
		
		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
		<script src="js/main.js"></script>
	</body>
</html>
```

- `<div>`タグに`app`というidを付与し、その中にマスタッシュ構文で`{{ message }}`と記述しました。
- この時点でhtmlを開いても、`{{ message }}`がテキストとして表示されるのみです。


次にjsファイルに次のように記述。

```js:main.js
var app = new Vue({

	el: '#app',
	data: {
		message: 'Hello World!'
			
	}
})

```

- `var 変数名 = new Vue({ ... })` で新規のVueインスタンスが作成できます。
- `el:`（elementの略）に`#app`と指定することで、`<div id="app">`内にのみ有効なVueインスタンスとすることが出来ます。
 （id名の先頭に`#`を付けるところはCSSでの指定方式と同じです。）
- `data: {}`内に`message: 'Hello World!'`と記述します。


### 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/4c50b826-660f-f4e7-986e-4c8c50f8d43c.png)
js側で宣言したmessageの内容がDOMに反映されていることが分かります。



## ２．ディレクティブ

### ディレクティブとは？
`v-`から始まるデータバインディング（HTMLとjavascriptを紐づける）を行うための機能。

### ２－１．v-bind
`v-bind`で要素属性のバインディングを行うことが出来ます。

```html:main.html
		<div id="app-2">
			<span v-bind:title="message">
				今何時？
			</span>
		</div>
```
```js:main.js
var app2 = new Vue({
	
	el: '#app-2',
	data: {
		message: '現在時刻は ' + new Date().toLocaleString()
	}
	
})
```

【html】

- `v-bind:[属性名]=""`で要素属性にdataオブジェクト内のプロパティをバインディングします。

【js】

- マスタッシュ構文の時と同様、Vueインスタンスを作成し、`el:`に`<div>`タグのidを記述します。
- dataオブジェクト内には`message: '現在時刻は ' + new Date().toLocaleString()`と記述します。
（`new Date().toLocaleString()`で、ローカル言語に合わせた書式の日時を取得できます。）



#### 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/546e9719-e991-b50a-5b5f-3f0fc26bb8b6.png)
「今何時？」にカーソルを合わせると、title属性にバインディングされた現在日時が表示されました。

#### 注意点
タグの属性内にマスタッシュ構文を使うことは出来ません。
属性に適用したい場合は上記の手順で`v-bind`を使用した書き方にしてください。

```html:main.html
		<div id="app-2">
			<span title={{ message }}>  ←このような記述は出来ません！
				今何時？
			</span>
		</div>
```


### ２－２．v-if

`v-if`で要素の表示/非表示を切り替えることが出来ます。

```html:main.html
		<div id="app-3">
			<span v-if="seen">
				見えるかな？
			</span>
		</div>
```
```js:main.js
var app3 = new Vue({

	el: '#app-3',
	data: {
		seen: true
	}

})
```

- js側で`seen`プロパティを作成します。
- html側で表示/非表示を切り替えたい要素内に`v-if="seen"`と記述します。

#### 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/10b225d0-1798-55be-2712-a66bb195578e.png)
`seen: true`のため、「見えるかな？」というテキストが表示されました。

試しに[F12]でデベロッパーツールを起動し、コンソールから`app3.seen = false`と打ってみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/9dca3795-bf1d-fea7-a877-268eba96dd61.png)

「見えるかな？」が非表示になりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/514d2314-4334-0b53-1d3b-ec196dd6113c.png)

DOMを見るとコメントアウトになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/117a613a-5320-4351-9758-b1862fe0f255.png)


### ２－３．v-show

`v-show`でも`v-if`と同じように、要素の表示/非表示を切り替えることが出来ます。

```html:main.html
		<div id="app-3">
			<span v-show="seen">
				見えるかな？
			</span>
		</div>
```
```js:main.js
var app3 = new Vue({

	el: '#app-3',
	data: {
		seen: true
	}

})
```

#### v-ifとv-showの違い

`v-if`でfalse指定した際には要素内がコメントアウトになったのに対し、
`v-show`の場合は`display: none;`が付与されます。（cssのdisplayプロパティと同じはたらき）
`v-if`より軽いため、頻繁に表示/非表示を変える場合は`v-show`がおすすめです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/14617caa-20e2-de05-d755-d57b2f30248f.png)


### ２－４．v-for

`v-for`を使って、配列内のデータを反映させることが出来ます。

```html:main.html
		<div id="app-4">
			<ol>
				<li v-for="todo in todos">
					{{ todo.text }}
				</li>
			</ol>
		</div>
```
```js:main.js
var app4 = new Vue({

	el: '#app-4',
	data: {
		todos: [
			{ text: 'りんご' },
			{ text: 'みかん' },
			{ text: 'ぶどう' }
			
		]
	}
	
})
```

- dataオブジェクト内に`todos`という配列を作成します。
- `v-for="[変数] in [配列名]"`で配列の内容を取得するループ処理を作成出来ます。
- マスタッシュ構文内で[変数]を使用することが出来ます。


#### 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/e673dd3e-3f45-d911-65c1-3f4169cf193d.png)
dataオブジェクト内に作った配列をDOMに反映させることができました。


### ２－５．v-on

`v-on`でmethods内の処理を実行させることが出来ます。

```html:main.html
		<div id="app-5">
			<p>{{ message }}</p>
			<button v-on:click="reverseMessage">メッセージをひっくり返すよ</button>
		</div>
```
```js:main.js
var app5 = new Vue ({
	
	el: '#app-5',
	data: {
		message: 'stressed'
	},
	methods: {
		reverseMessage: function() {
			this.message = this.message.split('').reverse().join('')
		}
	}
})
```

- dataオブジェクトに加えて`mothods`オブジェクトを作成します。
- `methods`オブジェクト内に`reverseMessage`というfunctionを作成します。
- function内にmessageの文字列を逆にする処理を記述します。（`this`はVueインスタンス(app5)自身を指しています。）
- html側には、messageのマスタッシュ構文とその下に`<button>`タグを記述します。
- `<button>`タグ内に`v-on:[イベント]="[処理名]"`の形で記載すると、Vueインスタンスのmethods内の処理が呼び出されます。
- 今回はクリック時に`reverseMessage`を実行したいので、`v-on:click="reverseMessage"`と記述します。

#### 結果
ボタンクリック前
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/8586a09c-b5cf-5186-5542-8f4cd9932d83.png)
ボタンクリック後
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/47e2e1f2-1a93-9714-1260-aa87dbe52944.png)



### ２－６．v-model（双方向データバインディング）

**【双方向データバインディングの特徴】**
　・jsのdata側とテンプレート側の両方で変更可能。
　・テンプレートの値を変更すると、dataオブジェクトのプロパティも変更される。

```html:main.html
		<div id="app-6">
			<p>{{ message }}</p>
			<input v-model="message">
		</div>
```
```js:main.js
var app6 = new Vue({
	
	el: '#app-6',
	data: {
		message: 'こんにちは！'
	}
})
```

- `<p>`タグの中にマスタッシュ構文を使い`message`の内容（こんにちは！）を出力するようにしました。
- 直後の`<input>`タグで`v-model="[オブジェクト名]"`と指定することで、`<p>`タグ同様`message`の内容を適用しています。

#### 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/ebe43db4-9996-f093-379b-62b9ebd432d6.png)
テキスト、テキストボックスの両方に`message`の内容が出力されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/5e7d0e02-5ca7-1067-f436-5548561533c5.png)
試しに下のテキストボックスの文字列を変更すると、上のテキストもそれに連動して書き換えられます。


## ３．コンポーネント

#### コンポーネントとは？
必要なパーツ(template(HTMLタグ)、methods等)を「コンポーネント」としてパッケージ化できる機能。
一度コンポーネントとして登録すれば再利用が可能なため、同じ組み合わせのタグを繰り返し使う時などに便利。

>本項はコチラの動画の記述を参考にいたしました。
>[Vue.js入門 #08：コンポーネントで再利用可能なパーツを作ろう](https://www.youtube.com/watch?v=vD7fZY2F_Kc)

```html:main.html
		<div id="app-7">
			<alert-box>IDが未入力です。</alert-box>
		</div>
```
```js:main.js
Vue.component('alert-box',{
	template: `
	<div class="alert">
		<strong>Error!</strong>
		<slot></slot>
	</div>
	`
})
var app7 = new Vue({
	el: '#app-7'
})
```
```css:main.css
.alert{
    background-color: #fcc;
    padding: 10px;
    border: 1px solid #f33;
}
```

- `Vue.component('[コンポーネント名]',{template: [HTMLタグ]})`で、コンポーネントを登録します。
- `template:`内には、コンポーネント化したいHTMLタグを記述します。
- `<slot>`タグは、コンポーネントを使用時にタグ中に記述したテキスト（「IDが未入力です。」）を反映させるための独自タグです。
- あわせて、Vueインスタンスの作成も忘れず行ってください。
- コンポーネント化したタグに`alert`というクラスを付与し、cssにてスタイル編集を行っています。
- `<[コンポーネント名]>`で、登録したコンポーネントを使用することが出来ます。

#### 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/5ce7815b-324e-2d84-aefe-82a689d4f5f1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/25107207-745f-10e7-821b-c397b99153d6.png)

- `<alert-box>`タグで囲った箇所が、コンポーネントとして登録したHTMLタグ（`<div class="alert">...`）に置き換わっています。
- `<alert-box>`タグ内に記述したテキスト（「IDが未入力です。」）が、`<slot>`タグによって文字列として適用されています。


#### コンポーネントの再利用

次のように、`<alert-box>`を繰り返し使うと・・・

```html:main.html
		<div id="app-7">
			<alert-box>IDが未入力です。</alert-box>
			<alert-box>IDが未入力です。</alert-box>
			<alert-box>IDが未入力です。</alert-box>
			<alert-box>IDが未入力です。</alert-box>
		</div>
```

その分だけコンポーネントが適用されます。
このように、一度登録したコンポーネントは再利用可能なことが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/2395e4dc-6a4a-d069-611a-73fdbadd8553.png)

#### mothodsの追加
コンポーネント内にはHTMLタグだけでなく、処理も記述することが出来ます。

```js:main.js
Vue.component('alert-box',{
	template: `
	<div class="alert" v-on:click="caution">
		<strong>Error!</strong>
		<slot></slot>
	</div>
	`,
	methods: {
		caution: function(){
			alert('クリックされました。');
		}
	}
})
var app7 = new Vue({
	el: '#app-7'
})
```

- `template:`内の`<div>`タグに、`v-on:click="caution"`を追記しました。
- `methods:`を追記し、画面上に「クリックされました。」というアラートを表示させる`caution`処理を追記しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/71ea445d-feb7-d3db-e3b0-c5bc34d7da89.png)

[Error!]をクリックすると、アラートが表示されました。


# さいごに
本記事で紹介したものは基礎知識となります。
ディレクティブ機能などの独自の記述が多いですが、慣れればシンプルで非常に書きやすいフレームワークだと感じました。
学習目的であればCDNで読み込みも簡単なので、ご興味のある方は是非お試しいただければと思います。


# Vue.js学習に役に立ったサイトまとめ

[公式サイト（ガイド）](https://jp.vuejs.org/v2/guide/)
[公式サイト（Vueオプションオブジェクト一覧）](https://jp.vuejs.org/v2/api/)
[基礎から学ぶVue.js](https://cr-vue.mio3io.com/)
[【Vue.js】vue.jsの基礎（yuta-38さん）](https://qiita.com/yuta-38/items/6eccdb1ec1ee46c5a42c)
[【Vue.js】Vue.jsの基礎（smkhkcさん）](https://qiita.com/smkhkc/items/b564c03222b5f9f23cfb)
[Vue.js入門（動画）](https://www.youtube.com/playlist?list=PLh6V6_7fbbo-SZYHHBVFstU2tp0dDZMAW
)