web初心者が1週間でVueを使ってみた. part1-基礎学習編

#この記事
web初心者が,配属された部署でVue使うから勉強してと言われて,暗闇の中1週間Vueで学んだことをまとめる.
基礎のキにすら値しないと思うけど,まとめるために書きました.
part1でvueとvuexの使い方まとめて,
part2で単一コンポーネントからatomic designまでまとめたい.

##vue
Key-word

* javascript's framework
* Model-View-ViewModel
* webcomponent
* https://jp.vuejs.org/

##element
vue用のcssライブラリ(フレームワークではないらしくレスポンシブルとかは対応されていない?)
今回は見た目盛るためだけに採用.
残念ながら日本語docはなし.
https://element.eleme.io/#/en-US

##vuex
vueの「状態管理パターン + ライブラリ」
いろいろやってみたけど,データとビューは経験的も分離するべきだし.
vueのみvue+vuexのコードを見比べると保守性もあがる.
https://vuex.vuejs.org/ja/

#カウンターアプリ
ドキュメントやいろんな記事でテンプレートのごとく使われているものをわざわざ作って行きます.
そして,見比べていきたいと思います.
詳細はドキュメントを参照..
https://jp.vuejs.org/

環境は,JSFiddle.
https://jsfiddle.net/

###環境を整える
vue,vuex,elementuiをResourcesに追加
![image.png](https://qiita-image-store.s3.amazonaws.com/0/283053/c1e7c7b5-7256-dbf8-bdc8-5a726efb2ce5.png)

最初使わないけど,cssも

```css
@import url("//unpkg.com/element-ui@2.4.8/lib/theme-chalk/index.css");
```

### hello world的なやつ

html側に以下記載

```html
<div id="app">
  <!-- data利用時は,mustacheで -->
  <p>{{count}}</p>
</div>
```

javascript側に以下記載

```javascript
const vm = new Vue({
    el: "#app", //element指定
    data: {
        count: 0 //デフォルト値をkey:valueで指定
    }
})
```

0と表示されればOK.

### カウントするボタンを準備する

まずhtml側にボタンを追加する.
せっかくcssライブラリ使ってるのでそのボタンを採用.

```html
<div id="app">
  <p>{{count}}</p>
  <el-button type="danger" v-on:click="counter(-10)">10</el-button> <!--ココ追加-->
</div>
```

cssライブラリにありがちなボタンが表示されたらOK.ライブラリの読み込みはうまくいっている.
次にカウントする機能を追加.

```javascript
const vm = new Vue({
    el: "#app", //element指定
    data: {
        count: 0 //デフォルト値をkey:valueで指定
    },
    methods: {//ココを追加
        counter: function (n) {//引数を足すだけ関数
            const count = this.count + n
            this.count = count
        }
    }
})
```

これでボタンをクリックすると-10,-20...となればOK.
イベントはv-on:clickでクリックイベントを拾っているだけ.

### 肉付け
それっぽくする.

```html
<div id="app">  
  <!--ココ追加 element から採用-->
  <div class="block">
    <el-progress type="circle" :percentage="count" color="#8e71c7"></el-progress>
  </div>
  <br>
  <p>{{count}}</p>
  <el-button type="danger" v-on:click="counter(-10)">10</el-button>
  <!--ココ追加 buttonで追加幅を広げただけ-->
  <el-button type="danger" v-on:click="counter(-1)">1</el-button>
  <el-button type="primary" v-on:click="counter(1)">1</el-button>
  <el-button type="primary" v-on:click="counter(10)">10</el-button>
</div>
```
![カウント.gif](https://qiita-image-store.s3.amazonaws.com/0/283053/eb3f5fc7-1af4-c57f-733d-28e92cf2e06d.gif)
それっぽくはなったけど,100%を超えたりする..限界突破は微妙なので制限を設ける.

```javascript
const vm = new Vue({
    el: "#app",
    data: {
        count: 0
    },
    methods: {
        counter: function (n) {
            const count = this.count + n
            //0-100までの確認と10ボタンのせいで必要になった制限..
            if (0 <= count && count <= 100) {
                this.count = count
            } else if (count < 0) {
                this.count = 0
            } else if (count > 100) {
                this.count = 100
            }
        }
    }
})
```
これで限界突破しなくなりました.

###おまけ
80%超えたらアイコンを表示する.

```html
<div id="app">
  <div class="block">
    <el-progress type="circle" :percentage="count" color="#8e71c7"></el-progress>
  </div>
  <br>
  <p>{{count}}</p>
  <!--ココ追加 v-showで表示非表示する-->
  <div v-show="iconFlag">
    <i class="el-icon-success"></i>
  </div>
  <el-button type="danger" v-on:click="counter(-10)">10</el-button>
  <el-button type="danger" v-on:click="counter(-1)">1</el-button>
  <el-button type="primary" v-on:click="counter(1)">1</el-button>
  <el-button type="primary" v-on:click="counter(10)">10</el-button>
</div>
```
```javascript
const vm = new Vue({
    el: "#app",
    data: {
        count: 0,
        iconFlag: false//アイコンフラグ
    },
    methods: {
        counter: function (n) {
            const count = this.count + n
            if (0 <= count && count <= 100) {
                this.count = count
            } else if (count < 0) {
                this.count = 0
            } else if (count > 100) {
                this.count = 100
            }
            //80点でフラグアイコン表示
            if (count >= 80) {
                this.iconFlag = true
            } else {
                this.iconFlag = false
            }
        }
    }
})
```
![カウント2.gif](https://qiita-image-store.s3.amazonaws.com/0/283053/83076747-2265-cad4-772d-e233885706ef.gif)

これで表示非表示もOK,入力チェックとかでalertとかでなくテキスト赤で表示などで使える.(アイコンが表示されてボタンの位置が変わるのは..ご愛嬌..)
完成品
https://jsfiddle.net/binary2/hL7tgamn/3/

これでなんとなく使い方は分かりました.
まだまだ機能はたくさんあるので,詳細は公式docを参照ください.

#vuex
今までのソースを見ると,Vueインスタンスがデータを持っている.(単一コンポーネントだとしっくり来たのでpart2で.)
これでシステムを作ると保守性が低く,だんだん負債がたまっていくのが分かる.
![image.png](https://qiita-image-store.s3.amazonaws.com/0/283053/40d75e0d-21a4-bd54-75be-b266b9ddc631.png)

上記のイメージがしっくりくる.
Vue ComponentsとVuexで分けて,役割を分離する.

##カウンターアプリソースを改修
やることはjavascriptのvueインスタンスからデータ操作部分を引き抜きます.
条件値を判断しているところは分離への理解に関係ないので省きます.
ざっくり,

* データ部分
* カウント部分
* アイコン表示非表示部分

を修正します.

```javascript
const vm = new Vue({
    el: "#app",
    data: {//データそのもの
        count: 0,
        iconFlag: false
    },
    methods: {
        counter: function (n) {//this.countはデータ操作
            const count = this.count + n
            //80点でフラグアイコン表示
            if (count >= 80) {//this.iconFlagはデータ操作
                this.iconFlag = true
            } else {
                this.iconFlag = false
            }
        }
    }
})
```

storeインスタンスを作り,vueインスタンスから移動していきます.

```javascript
const store = new Vuex.Store({
    state: {//data
        count: 0,
        iconFlag: false
    },
    getters: {//getter
        count(state) {
            return state.count
        },
        iconFlag(state) {
            return state.iconFlag
        }
    },
    mutations: {//データ操作,payloadはkey:valueで引数を与えるのを推奨されている.
        counter: function (state, payload) {
            state.count = state.count + payload.count
        }
    }
})

const vm = new Vue({
    el: "#app",
    computed: {//data->computedで定義,getter経由で取得する.
        count() {
            return store.getters.count
        },
        iconFlag() {
            return store.getters.iconFlag
        }
    },
    methods: {//commitでデータ操作
        counter(n) {
            store.commit('counter', {
                'count': n//payload部分
            })
        }
    }
})
```

動作は同じだけど,コードがだいぶ変わりました.
vueインスタンスはgetterからデータ取得,commitから操作依頼を出すイメージ?
storeインスタンスはデータのそのもの,データ変更操作などを行う.
完成品
https://jsfiddle.net/binary2/mdhLa91x/87/

#まとめ
初めて,javascriptフレームワークという品物を扱った.
ずっと闇雲にドキュメント見て分からないけど進めて,このまとめにいたりました.
多分vue-vuexの利便性のリすらも理解できてないかもしれないけど,
vue-vuexの基礎的な分離はできるようになったと信じたい.(正直親子のデータやり取りなど,全然正解が分からないし..)

続いて,ローカル環境でいろいろやってみたものをまとめたいです.
先が長いなー

[part2](https://qiita.com/binary2/items/575dedc3bea5d02a53f9#_reference-7d936416cd131ce5ec91)へ

#更新履歴
hellow world-> hello world はずかしい..
コードも自動でインデントとか調整してくれるの入れたので,直しました..
こっちにpart2へのリンクを忘れていた。すでに半年たっているけど..