Day2：3日でVue.jsを用いたアプリケーションを動かす

# 2日目の取組の記録

### 【Story】
・Componentを使うぞ!!!
・脱SPAしてProjectを使うぞ!!!!
・なんかそれっぽく動くものができた...!!!


### 【Vue.jsの応用①】
*コンポーネントの基本
script内でHTMLのタグを自動生成して返してくれるから楽

```vue

<!DOCTYPE html>
<html>
<head>
    <title>My first Vue app</title>
    <script src="http://localhost:8098"></script>
    <script src="https://unpkg.com/vue"></script>
</head>

<body>
        <style>
        .hello{
            font-size:20pt;
            font-weight:bold;
            border:1px solid magenta;
            padding:5px 10px 0px 10px;
            margin:10px;
        }
        </style>

        <h1>Vue.js</h1>

        <div id = "app">
            <hello/>
        </div>

        <script>
            Vue.component(
                'hello',
                {template: '<p class="hello">Hello!</p>'}
            )
        
            var app = new Vue({
                el: '#app',
            });
        
        </script>
</body>
</html>
```

*やったことはこんな感じ

・コンポーネント内に変数を利用する

```vue
<body>
        <style>
        .hello{
            font-size:20pt;
            font-weight:bold;
            border:1px solid magenta;
            padding:5px 10px 0px 10px;
            margin:10px;
        }
        
        </style>

        <h1>Vue.js</h1>

        <div id = "app">
            <hello/>
        </div>

        <script>
            Vue.component(
                'hello',
                {
                    data:function(){
                        return { 
                            message:'これはメッセージです。'
                        };
                    },
                    template: '<p class="hello">{{message}}</p>',
                }
            )
        
            var app = new Vue({
                el: '#app',
            });
        
        </script>
</body>
```


・コンポーネント内の変数にHTMLから値を引き渡す

```vue
 <body>
        <style>
        .hello{
            font-size:20pt;
            font-weight:bold;
            border:1px solid magenta;
            padding:5px 10px 0px 10px;
            margin:10px;
        }
        </style>

        <h1>Vue.js</h1>

        <div id = "app">
            <div><hello name="Taro" /></div>
            <div><hello name="Hanako" /></div>
        </div>

        <script>
            Vue.component(
                'hello',
                {
                    //props:['name'],
                    props:{ name:String },
                    template: '<p class="hello">Hello , {{name}}</p>',
                }
            )
        
            var app = new Vue({
                el: '#app',
            });
        
        </script>
</body>
```

・コンポーネントの再利用
※変数値はリスト型で指定
※v-for/v-bindを利用

```vue
<body>
        <style>
        .hello{
            font-size:20pt;
            font-weight:bold;
            border:1px solid magenta;
            padding:5px 10px 0px 10px;
            margin:10px;
        }
        
        </style>

        <h1>Vue.js</h1>

        <div id = "app">
            <hello v-for="item in data" v-bind:name="item" />
        </div>

        <script>
            Vue.component(
                'hello',
                {
                    props:['name'],
                    template: '<p class="hello">Hello , {{name}}</p>',
                }
            )
        
            var app = new Vue({
                el: '#app',
                data:{
                    data:['Hana','Taro','Mana']
                }
            });
        
        </script>
</body>
```

・ ユーザーが入力した内容をコンポーネントに反映する

```vue
<body>
        <style>
        .hello{
            font-size:20pt;
            font-weight:bold;
            border:1px solid magenta;
            padding:5px 10px 0px 10px;
            margin:10px;
        }
        </style>

        <h1>Vue.js</h1>

        <div id = "app">
            <div><hello v-bind:name="name" /></div>
            <div><input type="text" v-model="name"></div>
        </div>

        <script>
            Vue.component(
                'hello',
                {
                    props:['name'],
                    template: '<p class="hello">Hello , {{name}}</p>',
                }
            )
        
            var app = new Vue({
                el: '#app',
                data: {
                    name:'no-name'
                }
            });
        
        </script>
</body>
```

・クリックしたら回数が1ずつ増えていくカウンターを作る
※v-onを利用

```vue
<body>
        <style>
        .hello{
            font-size:20pt;
            font-weight:bold;
            border:1px solid magenta;
            padding:5px 10px 0px 10px;
            margin:10px;
        }
        </style>

        <h1>Vue.js</h1>

        <div id = "app">
            <hello />
        </div>

        <script>
            Vue.component(
                'hello',
                {
                    data:function(){
                        return {counter:0};
                    },
                    template: 
                    '<p v-on:click ="counter++;" class="hello">clicked:{{counter}}.</p>',
                }
            )
        
            var app = new Vue({
                el: '#app',
            });
        
        </script>
</body>
```

・カウンターをメソッド化して条件分岐
※v-on/v-ifを利用

```vue
<body>
        <style>
        .red {
        color:white;
        background-color:red;
        }
        </style>

        <h1>Vue.js</h1>

        <div id = "app">
            <hello />
        </div>

        <script>
        var hello = Vue.component(
            'hello',
            {
                data:function(){
                    return {
                        counter:0,
                        isRed:false,
                    }
                },

                methods:{
                    doAction:function(event){
                        this.counter++;
                        if(this.counter > 10){
                            this.counter = 0;
                        }
                        if(this.counter % 2){
                            this.isRed = false;
                        } else {
                            this.isRed = true;
                        }
                    },
                },

                template: '<p v-bind:class="{red:isRed}" ' + 
                'v-on:click="doAction" class="hello">clicked: {{counter}}.</p>',

            })

        var app = new Vue({
            el:'#app',
            });

        </script>
</body>
```

・ユーザーが入力するとどんどん加算されるメソッドを作るよ

```vue
<body>
        <style>
        </style>

        <h1>Vue.js</h1>

        <div id = "app">
            <hello />
        </div>

        <script>
        Vue.component(
            'hello',
            {
                data:function(){
                    return {
                        num : 0,
                        message : 'type a number'
                    };
                },

                methods:{
                    calc:function(event){
                        var total=0;
                        for (var i=1; i<=this.num; i++ ){
                            total += i;
                        }
                        this.message = "total: " + total; 
                    }
                },

                template:'<div><p class="hello">{{message}}</p>' +
                    '<div><input type="number" v-on:input="calc" v-model="num">' +
                    '</div></div>'
            }
        );

        var app = new Vue({
            el:'#app'
        });
        </script>
</body>
```

算術プロパティを使ってみるよ
※computed

```vue
 <body>
        <style>
        </style>

        <h1>Vue.js</h1>

        <div id = "app">
            <hello />
        </div>

        <script>
        Vue.component(
            'hello',
            {
                data:function(){
                    return {
                        num:0,
                    }
                },
                computed:{
                    calc:function(event){
                        var total=0;
                        for(var i=1; i<=this.num; i++){
                            total +=i;
                        }
                        return "total: " + total;
                    }
                },
                template:'<div><p class="hello">{{calc}}</p>'+
                    '<div><input type="number" v-model="num"></div></div>'
            }
        );

        var app = new Vue({
            el: '#app',
        });
        </script>
</body>
```

・ローカルコンポーネントを使ってみるよ
※今までのはグローバルコンポーネント

```vue
<body>
        <style>
        </style>

        <h1>Vue.js</h1>

        <div id = "app">
            <div><hello /></div>
            <div><hello /></div>
            <div><hello /></div>
        </div>

        <script>
            var app = new Vue({
                el:'#app',
                components:{
                    hello:{
                        data:function(){
                            return {
                                counter:0,
                            };
                        },
                        
                        template:'<p v-on:click="counter++;" class="hello">' +
                                'clicked: {{counter}}.</p>',
                        }
                    }
            });

        </script>
</body>
```

＊v-onとcomputedの違いって何？
イベント：ユーザが操作するなどしてイベントが発生すると呼び出される
算術プロパティ：依存する値が更新された時に実行

### 【Vue.jsの応用②】
*プロジェクトを利用してみる
プロジェクトの作り方はコマンドライン経由で実施

```vue
vue create プロジェクト名
npm run serve
```

ホットデプロイなので変更内容がリアルタイムで反映される
＊フォルダ構成はこんな感じ

|ファイル名|概要|
|---|---|
|favicon.ico|アイコンファイル|
|index.html|デフォルトのWEBページ用HTMLファイル|
|main.js|アプリケーションのプログラム|
|App.vue|アプリケーションで使うコンポーネントファイル|
|logo.png|ロゴのイメージファイル|
|HelloWorld.vue|コンポーネントファイル|

![vueJSのフォルダ構成 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542096/9479026a-596c-84c3-7a5d-ab1f3f0b8827.png)

<img width="300" alt="picture.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542096/9479026a-596c-84c3-7a5d-ab1f3f0b8827.png">

＊それぞれのファイルについて

・index.html
appタグに対してjsで操作を行っていく
<div id="app"></div>

```vue
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>07-project</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but 07-project doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

```

・main.js
[マウントについて]
elプロパティがない → 手動でマウントする必要がある
$mount('app') → id="app"のタグにVueのオブジェクトをマウントして利用している

[vueコンポーネントのインポートについて]
import App from './App.vue'

```vue
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')
```

・App.vue
[インポート時のデフォルト設定]
export defaultはスクリプトファイルをimportでインポートしたとき、デフォルトで用意されるものを指定

export default {

}


[タイトルの変更]
<button v-on:click="doAction">change title</button>
App.vueのdoActionから入力された内容(this.message = input)を

<HelloWorld v-bind:title="message"
子コンポーネントのtitle変数に引き渡す

```vue
<template>
表示するタグを記載
</template>
<script>
タグの動作を定義したjavascriptを記載
</script>
<style>
レイアウトの内容を記載
</style>
```

```vue
<template>
  <div id="app">
    <HelloWorld v-bind:title="message" v-on:result-event="appAction"/>
    <hr>
    <p>{{result}}</p>
    <button v-on:click="doAction">change title</button>
  </div> 
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'app',
  components: {
    HelloWorld
  },

  data: function(){
    return {
      message:'HELLO',
      result:'no event'
    }
  },
 
  methods:{
    appAction: function(message){
      this.result = '(*** you send:"' + message + '".***)'
    }
  },

  methods:{
    doAction:function(){
      var input = prompt("new title:"); // 小さい画面を表示して情報を受け取る
      this.message = input;
    }
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
```

・HelloWorld.vue
[プロパティの指定]
props: {
 title : String,
 }

[データの設定]
data:function(){
 return{
 };
 }

[クリックしたらinputの内容を書き換える]
<input type="text" v-model="input">
<button v-on:click="doAction">Click</button>

[***～***の表示]
this.$emit('result-event', this.input);
result-eventが定義されている親のタグにインプットされた内容を引き渡す

```vue
<template>
  <div class="hello">
    <h1>{{title}}</h1>
    <p>{{message}}</p>
    <hr>
    <div>
      <input type="text" v-model="input">
      <button v-on:click="doAction">Click</button>
    </div>  
  </div>
</template>

<script>

export default {
  name: 'HelloWorld',
  props: {
    title : String,
  },

  data:function(){
    return{
      message: 'お名前は？',
      input:'no name',
      title:'HELLO'
    };
  },

  methods:{
    doAction: function(){
      this.message = 'こんにちは、' + this.input + 'さん' ;
      this.$emit('result-event', this.input);
    }
  }
}
</script>

<style>
div {
  margin:0px;
  padding: 0px;
  text-align:left;
}
h1 {
  font-size:72pt;
  font-weight:bold;
  text-align:right;
  letter-spacing:-8px;
  color:#f0f0f0;
  margin:0px;
}
p {
    margin:0px;
    color:#666;
    font-size:16pt;
}
</style>
```