Vue.jsの基礎を学ぶ(4日目)

#フォーム入力バインディング

##複数行テキスト

textareaでは{{}}を使ったデータバインディングは使えない

その代わりにv-modelディレクティブを設定して使う。

```html
<div id="app">
  <pre>{{ message }}</pre>
  <textarea v-model="message"></textarea>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

```js
var app = new Vue({
  //options
  el: '#app',
  data: {
    message: 'Hello Vue.js!'
  }
})
```

##チェックボックス

・単体のチェックボックス・・・boolean値

・複数のチェックボックス・・・配列

##チェックボックス単体

```html
<div id="app">
  <input type="checkbox" id="checkbox" v-model="checked">
  <label for="checkbox">{{ checked }}</label>
  <pre>{{ $data }}</pre>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

```js
var app = new Vue({
  //options
  el: '#app',
  data: {
    checked: false
  }
})
```

これで、チェックボックスにチェックを入れるとtrueが表示される。
外すとfalseに戻る。

チェックボックスは真偽値で表されるから、v-model=の値も真偽値を示すプロパティとなる。

##チェックボックス複数

```html
<div id="app">
  <input type="checkbox" id="red" value="Red" v-model="colors">
  <label for="red">Red</label>
  <input type="checkbox" id="green" value="Green" v-model="colors">
  <label for="green">Green</label>
  <input type="checkbox" id="blue" value="Blue" v-model="colors">
  <label for="blue">Blue</label>
  <p>
    {{ $data }}
  </p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

```js
var app = new Vue({
  //options
  el: '#app',
  data: {
    colors: []
  }
})
```

複数のチェックボックスを使うときは、配列で表される。


##ラジオボタン

ラジオボタンのデフォルトの値の型は文字列となる。

```html
<div id="app">
  <input type="radio" id="red" value="Red" v-model="color">
  <label for="red">Red</label>
  <input type="radio" id="green" value="Green" v-model="color">
  <label for="green">Green</label>
  <p>
    {{ color }}
  </p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

```js
var app = new Vue({
  //options
  el: '#app',
  data: {
    color: ''
  }
})
```

redのラジオボタンにチェックを入れるとcolorプロパティの値がRedになる。
greenにチェックを入れるとcolorプロパティがGreenとなる。

Red Greenの両方入ることはない。


##セレクトボックス単体

セレクトボックスの単体選択のデフォルト値の型は文字列

```html
<div id="app">
  <select v-model="selected">
    <option disabled value="">Please select one</option>
    <option>Red</option>
    <option>Green</option>
    <option>Blue</option>
  </select>
  <p>
    {{ selected }}
  </p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

```js
var app = new Vue({
  //options
  el: '#app',
  data: {
    selected: ''
  }
})
```

##セレクトボックス複数

セレクトボックス複数選択のデフォルトの値の型は配列

```html
<div id="app">
  <select v-model="selected" multiple>
    <option disabled value="">Please select one</option>
    <option>Red</option>
    <option>Green</option>
    <option>Blue</option>
  </select>
  <p>
    {{ selected }}
  </p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

```js
var app = new Vue({
  //options
  el: '#app',
  data: {
    selected: []
  }
})
```

#v-modelバインディングの修飾子

##.lazy

バインドのタイミングを遅延させることができる

```html
<div id="app">
  <input type="text" v-model.lazy="message">
  <p>{{ message }}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

```js
var app = new Vue({
  //options
  el: '#app',
  data: {
    message: ''
  }
})
```

本来v-modelで双方向データバインディングを作ると、フォームに入力したと同時にバインディングされたが、今回は

```html
<input type="text" v-model.lazy="message">
```

.lazy修飾子が付いているので、フォームに文字を入力し、タブキーなどで入力を確定させないとバインディングされない。

##.trim

入力値から前後の空白を削除して、データに代入できる

```html
<div id="app">
  <p>
    <input type="text" v-model.trim="message">
  </p>
  <p>
    <input type="text" v-model="message">
  </p>
  <pre>{{ $data }}</pre>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

```js
var app = new Vue({
  //options
  el: '#app',
  data: {
    message: ''
  }
})
```

注意点は取り除かれるのは前後の空白だけ。
ちなみに全角のスペースも取り除かれる。


##.number

入力値を数値型に型変換してからデータに代入する

ユーザーが入力した年齢に+10するプログラムを作りたい

```html
<div id="app">
  <p>
    <input type="number" v-model.number="age">
  </p>
  <p>{{ age + 10 }}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

```js
var app = new Vue({
  //options
  el: '#app',
  data: {
    age: 0
  }
})
```

.numberを付けないと、{{ age + 10 }}が上手く機能しない。

それは、type="number"を持つinputタグでも返す値は文字列型だからである。

そのため、.numberを付けて返す値を数値に変換してから返すようにする必要がある。

#コンポーネント

##グローバル登録

Helloと出力するコンポーネントを作成したい。

```html
<div id="app">
  <hello-component></hello-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

```js
Vue.component('hello-component', {
  template: '<p>Hello</p>'
})

var app = new Vue({
  //options
  el: '#app',
})
```

注目すべきは

```js
Vue.component('hello-component', {
  template: '<p>Hello</p>'
})
```

Vue.component('コンポーネント名', {})
の形で定義する。

定義したら

```html
<hello-component></hello-component>
```

コンポーネント名のタグを書くことで使うことができる。


##ローカル登録

特定のVueインスタンス配下でしか利用しないと分かっているコンポーネントはスコープを制限することができる。

先ほどのコードをローカル登録に書き換えよう。

```html
<div id="app">
  <hello-component></hello-component>
  <hello-component></hello-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

htmlは変わらない。

```js
var helloComponent = {
	template: '<p>Hello</p>'
}

var app = new Vue({
  //options
  el: '#app',
  components: {
  	'hello-component' : helloComponent
  }
})
```

ローカル登録の仕方は、

```js
var helloComponent = {
    template: '<p>Hello</p>'
}
```

変数を定義する。

次に

```js
var app = new Vue({
  //options
  el: '#app',
  components: {
    'hello-component' : helloComponent
  }
})
```

componentsオプションに、

```
'viewのタグで使う名前' : 定義した変数名
```
という形で紐付ける。

それを

```html
<hello-component></hello-component>
```

このように呼び出すことができる。
もちろん、今回は#app要素内でしか使うことはできない。
なぜなら、Vueインスタンスがel: '#app'とマウントしてるから。

##コンポーネント名

ハイフンを1つ以上含むケバブケースを利用する必要がある。

```
ex)
hello-component ◯

hello ×
helloComponent ×
```

##コンポーネントのオプション

ボタンを押すとクリック数をカウントして表示するボタンをコンポーネントで作成したい。

```html
<div id="app">
  <button-counter></button-counter>
  <button-counter></button-counter>
  <button-counter></button-counter>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

```js
Vue.component('button-counter', {
  //コンポーネントの場合はdataオプションは関数で書かなければいけない。
	data: function() {
  	return {
    	count: 0
    }
  },
  //templateの要素は単一である必要がある。
  //複数のタグを使いたければdivタグで囲うなどの対策をする。
  template: '<button v-on:click="count++">{{ count }}</button>'
})

var app = new Vue({
  //options
  el: '#app',
})
```

注目すべきは、コンポーネント内にdataオプションが入っていること。
この場合、コンポーネントごとに独自のcountプロパティを持つことになる。

何回使い回しても、独自のcountプロパティを持つ。

ただし、コンポーネント内では、dataオプションを直接指定するのではなく、

functionを使って関数で指定してあげる必要がある。


#トランジション

p要素をフェードアウト/フェードインしながら表示・非表示を切り替えるプログラムを作りたい。

```html
<div id="app">
  <button v-on:click="show=!show">
    Change
  </button>
  <transition>
    <p v-show="show">
      Hello Transition
    </p>
  </transition>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

```css
.v-enter-active,
.v-leave-active{
  transition: opacity 5s;
}

.v-enter,
.v-leave-to{
  opacity: 0;
}
```

```js
var app = new Vue({
  //options
  el: '#app',
  data: {
  	show: false
  }
})
```

まず、ポイントは、transition効果を使いたい要素をtransitionタグで囲む。

```html
<transition>
    <p v-show="show">
      Hello Transition
    </p>
  </transition>
```

次に、v-if,v-showで要素の表示・非表示を行う場合、

表示される時に

v-enter-active と　v-enterクラスが、

非表示になる時に

v-leave-active　と　v-leave-toクラスが付与される。

このクラスはボタンを押されてから要素が表示される５秒間、または要素が非表示になる５秒間だけクラスが付与される。

```css
.v-enter-active,
.v-leave-active{
  transition: opacity 5s;
}

.v-enter,
.v-leave-to{
  opacity: 0;
}
```

#VueRouter

シングルページアプリケーションを構築するためのルーティングライブラリ

##SPAとは

初めに1つのhtmlをロードし、
以降はユーザーの操作に応じて、
Ajaxでサーバからデータを取得して、
動的にページを更新するWebアプリケーション


##router-link

```html
<div id="app">
      <!-- railsで言うlink_toのようなもの -->
      <router-link to="/top">Go to Top</router-link>
      <router-link to="/users">Go to User</router-link>
    </div>
```

aタグに変換される。


##router-view


```html
<div id="app">
      <!-- railsで言うlink_toのようなもの -->
      <router-link to="/top">Go to Top</router-link>
      <router-link to="/users">Go to User</router-link>
      <!-- railsで言うyieldのようなもの -->
      <router-view></router-view>
    </div>
```

routerviewタグの中に、描画する各テンプレートが入る。
railsのyield的なものだと思う。

##spaの基本形

```html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>Real time search</title>
  </head>
  <body>
    <div id="app">
      <!-- railsで言うlink_toのようなもの -->
      <router-link to="/top">Go to Top</router-link>
      <router-link to="/users">Go to User</router-link>
      <!-- railsで言うyieldのようなもの -->
      <router-view></router-view>
    </div>

    <script src="https://unpkg.com/vue@2.6.10"></script>
    <script src="https://unpkg.com/vue-router@3.0.6"></script>
    <script>
      // トップページとユーザーページで使うコンポーネント
      const Top = { template: '<div>Top</div>' }
      const User = { template: '<div>User</div>' }

      // 以下でルートとそこで使うコンポーネントを紐づけている
      const router = new VueRouter({
        routes: [
          {
            path: '/top',
            component: Top
          },
          {
            path: '/users',
            component: User
          }
        ]
      })
      const app = new Vue({
        //routerと言うプロパティに24行目で定義したrouterインスタンスが渡されている？
        router : router
        //routerと短縮表記可能
      }).$mount('#app')
    </script>
  </body>
</html>
```

##paramsを使ってuserのidを表示する

```html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>Real time search</title>
  </head>
  <body>
    <div id="app">
      <!-- railsで言うlink_toのようなもの -->
      <router-link to="/top">Go to Top</router-link>
      <router-link to="/users/123">Go to User</router-link>
      <!-- railsで言うyieldのようなもの -->
      <router-view></router-view>
    </div>

    <script src="https://unpkg.com/vue@2.6.10"></script>
    <script src="https://unpkg.com/vue-router@3.0.6"></script>
    <script>
      // トップページとユーザーページで使うコンポーネント
      const Top = { template: '<div>Top</div>' }
      const User = { template: '<div>User {{ $route.params.userId }}</div>' }

      // 以下でルートとそこで使うコンポーネントを紐づけている
      const router = new VueRouter({
        routes: [
          {
            path: '/top',
            component: Top
          },
          {
            path: '/users/:userId',
            component: User
          }
        ]
      })
      const app = new Vue({
        //routerと言うプロパティに24行目で定義したrouterインスタンスが渡されている？
        router : router
        //routerと短縮表記可能
      }).$mount('#app')
    </script>
  </body>
</html>
```

ポイントは

```html
{
  path: '/users/:userId',
  component: User
 }
```

ここでid付きのurlを定義して

```html
 const User = { template: '<div>User {{ $route.params.userId }}</div>' }
```

ここでidを取得している。


##名前付きルート

```html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>Real time search</title>
  </head>
  <body>
    <div id="app">
      <!-- railsで言うlink_toのようなもの -->
      <router-link :to="{ name: 'top' }">Go to Top</router-link>
      <router-link :to="{ name: 'user', params: { userId: 123 }}">Go to User</router-link>
      <!-- railsで言うyieldのようなもの -->
      <router-view></router-view>
    </div>

    <script src="https://unpkg.com/vue@2.6.10"></script>
    <script src="https://unpkg.com/vue-router@3.0.6"></script>
    <script>
      // トップページとユーザーページで使うコンポーネント
      const Top = { template: '<div>Top</div>' }
      const User = { template: '<div>User {{ $route.params.userId }}</div>' }

      // 以下でルートとそこで使うコンポーネントを紐づけている
      const router = new VueRouter({
        routes: [
          {
            path: '/top',
            name: 'top',
            component: Top
          },
          {
            path: '/users/:userId',
            name: 'user',
            component: User
          }
        ]
      })
      const app = new Vue({
        //routerと言うプロパティに24行目で定義したrouterインスタンスが渡されている？
        router : router
        //routerと短縮表記可能
      }).$mount('#app')
    </script>
  </body>
</html>
```

注目すべきは

```html
const router = new VueRouter({
        routes: [
          {
            path: '/top',
            name: 'top',
            component: Top
          },
          {
            path: '/users/:userId',
            name: 'user',
            component: User
          }
        ]
      })
```

```html

<div id="app">
      <!-- railsで言うlink_toのようなもの -->
      <router-link :to="{ name: 'top' }">Go to Top</router-link>
      <router-link :to="{ name: 'user', params: { userId: 123 }}">Go to User</router-link>
      <!-- railsで言うyieldのようなもの -->
      <router-view></router-view>
    </div>
```

path:の下にname:''で名前を指定する。

router-linkタグで、:to="{ name: '名前付きルート' }"
と指定してあげれば完了。

##ネストされたroute

```html
<!DOCTYPE html>
<html>
 <head>
   <meta charset="UTF-8">
   <title>Nested routes - Vue Router</title>
 </head>
 <body>
  <div id="app">
    <router-link to="/">Home</router-link>
    <router-link to="/users/123">User</router-link>
    <router-link to="/users/123/profile">Profile</router-link>
    <router-link to="/users/123/posts">Posts</router-link>
    <router-view></router-view>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/vue-router@3.0.6/dist/vue-router.min.js"></script>
  <script>
    const User = {
      template: `
        <div class="user">
          <h2>User {{ $route.params.userId }}</h2>
          <router-view></router-view>
        </div>
      `
    }

    const Profile = {
      template: `
        <div class="profile">
          <h2>Profile {{ $route.params.userId }}</h2>
        </div>
      `
    }
    const Posts = {
      template: `
        <div class="posts">
          <h2>Posts {{ $route.params.userId }}</h2>
        </div>
      `
    }

    const router = new VueRouter({
      routes: [
        {
          path: '/users/:userId', component: User,
          children: [
            {
              path: 'profile', component: Profile
            },
            {
              path: 'posts', component: Posts
            }
          ]
        }
      ]
    })

    var app = new Vue({
      router
    }).$mount('#app')
  </script>

  <style>
    body {
      color: white;
      background: #fcebb6;
    }

    .user {
      background: #5e412f;
      padding: 5px;
    }

    .profile {
      background: #78c0a8;
      padding: 5px;
    }

    .posts {
      background: #f07818;
      padding: 5px;
    }
  
  </style>
 </body>
</html>
```

注目すべきは

```html
const router = new VueRouter({
      routes: [
        {
          path: '/users/:userId', component: User,
          children: [
            {
              path: 'profile', component: Profile
            },
            {
              path: 'posts', component: Posts
            }
          ]
        }
      ]
    })
```

children:[]内にネストさせるルートとコンポーネントを指定している点だ。

また、

```html
const User = {
      template: `
        <div class="user">
          <h2>User {{ $route.params.userId }}</h2>
          <router-view></router-view>
        </div>
      `
    }
```

Userコンポーネントでは<router-view>タグが入っている。
ここに、profileもしくはpostsコンポーネントが入る。


##リダイレクト

```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Redirect - Vue Router</title>
  </head>
  <body>
    <div id="app">
      <router-link to="/">Home</router-link>
      <router-link to="/a">A</router-link>
      <router-link to="/b">B</router-link>
      <router-view></router-view>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue-router@3.0.6/dist/vue-router.min.js"></script>
    <script>
      const B = {
        template: '<div><h2>This is B</h2></div>'
      }
      const router = new VueRouter({
        routes: [
          {
            path: '/a',
            redirect: '/b'
          },
          {
            path: '/b',
            component: B
          }
        ]
      })

      const app = new Vue({
        router
      }).$mount('#app')
    </script>
  </body>
</html>
```

注目すべきは

```html

const router = new VueRouter({
        routes: [
          {
            path: '/a',
            redirect: '/b'
          },
          {
            path: '/b',
            component: B
          }
        ]
      })
```

path: '/b'にはコンポーネントを指定しているが、

path: '/a'には、viewが無いので、コンポーネントを指定しない。

そして、redirect: '/b'と書いてあげることで、'/a'リンクをクリックすると、'/b'にリダイレクトされるようになる。


##名前付きルートへのリダイレクト

やり方は以下

```html
const router = new VueRouter({
        routes: [
          {
            path: '/a',
            redirect: { name: 'page-b'}
          },
          {
            path: '/b',
            name: 'page-b',
            component: B
          }
        ]
      })
```

まず、name:で名前付きルートの作成。

次にredirect: { name: '名前付きルート'　}

とすればok

##エイリアス

urlが置換されないリダイレクト

```html
<!DOCTYPE html>
<html>
 <head>
   <meta charset="UTF-8">
   <title>Alias - Vue Router</title>
 </head>
 <body>
   <div id="app">
     <router-link to="/">Home</router-link>
     <router-link to="/a">A</router-link>
     <router-link to="/b">B</router-link>
     <router-view></router-view>
   </div>
   <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.min.js"></script>
   <script src="https://cdn.jsdelivr.net/npm/vue-router@3.0.6/dist/vue-router.min.js"></script>
   <script>
     const A = {
       template: '<div><h2>This is A</h2></div>'
     }
     const router = new VueRouter({
       routes: [
        {
          path: '/a',
          component: A,
          alias: '/b'
        }
       ]
     })

     const app = new Vue({
       router
     }).$mount('#app')
   </script>
 </body>
</html>
```

注目すべきは

```html
const router = new VueRouter({
       routes: [
        {
          path: '/a',
          component: A,
          alias: '/b'
        }
       ]
     })
```

この場合、 '/a'と'/b'のurlの時は、componentAが呼び出されるよーって意味。


#Vue CLI

Vue.jsを使ったアプリ開発をサポートするためのコマンドラインインターフェイス

##Node.js

サーバで動作するプログラムをJavaScriptで書くための技術

##NPM

Node Package Managerの略。
Node.jsのモジュールを管理するツール

##単一ファイルコンポーネント

Vue.jsのコンポーネントを単独のファイルとして作成する機能。

拡張子は.vue

テンプレート、css、jsを1つのファイルとして作成することができる。

再利用性が高く、保守性も高い。

ただ、単一ファイルコンポーネントはvue.js独自の仕組みなのでGoogle Chromeなどのブラウザで実行できない。

そのため、ブラウザで動作可能にするように、変換する必要がある。
これをビルドと呼ぶ。

##単一ファイルコンポーネントの作成

```HelloNuxt.vue
<template>
  <div>
   <h1>Hello Nuxt!</h1>
  </div>
</template>

<script>
</script>

<style scoped>
</style>
```

これがほぼ最小単位の単一ファイルコンポーネント。
componentsディレクトリの中に新しいファイルを作成してコードを書いていく。

##単一ファイルコンポーネントの利用

先ほど作ったHelloNuxt.vueコンポーネントを利用したい。

驚きだったのが、Vueの場合、viewフォルダーの中身も.vueが拡張子のファイルだったのだ。

例えば、Home.vue内でHelloNuxt.vueコンポーネントを使う場合

```Home.vue
<template>
  <div class="home">
    <HelloNuxt/>
  </div>
</template>

<script>
// @ is an alias to /src
import HelloNuxt from '@/components/HelloNuxt.vue'

export default {
  name: 'Home',
  components: {
    HelloNuxt
  }
}
</script>
```

このように設定する。

こうすると、HelloNuxtに書いたテンプレートやcss、jsがview側に反映される。