componentを利用した文字カウンター

# 概要
- componentを利用。
- componentそれぞれに固有の属性値を持たせて利用する。
- computedで算出する。

# propsについて
HTMLとJSでそれぞれ属性名の命名規則が決まっているので準拠すること。
## HTML・テンプレート側
- JSで利用するためにhtmlに設定する属性名は全て小文字（大文字は不可）で、単語を繋げる場合はハイフン繋ぎで書く。
- 無効な書き方をすると参照できない。

```html:無効な例
<ex-component maxLength="10"></ex-component>
```

```html:有効な例
<ex-component max-length="10" message="sample text"></ex-component>
```

- 数値や真偽値などの値を設定する場合はバインドさせる。バインドさせない場合は文字列として扱われる。

```html:バインドの例
<ex-component :max-length="10" :is-disable="true"></ex-component>
<!--省略表記-->
<ex-component :max-length="10" :is-disable="true"></ex-component>
```

## JS側
- props内の配列に属性名を設定する。
- 設定しないとHTML側に書いた属性が無視される。
- HTML側にハイフン繋ぎで設定した属性名は、キャメルケースにして設定する。
- 正しく設定できると、methodやcomputed、data関数内で `this.属性名` で参照できる。

```js:設定の例
Vue.component("ex-component", {
  template: "#ex-component",
  props: ["message", "maxLength"],
...
```

```js:参照の例
Vue.component("ex-component", {
    data: function(){
        this.message // messageを参照
    },
    computed: {
       test: function() {
            this.message; // messageを参照
        },
    },
    method: {
        method1: function(){
            this.maxLength; // max-lentghを参照
        }
    }
```

## 参考
- [キャメルケース 対 ケバブケース](https://jp.vuejs.org/guide/components.html#キャメルケース-対-ケバブケース)

# computedについて
- 依存している値が変化すると自動的に計算して結果を算出してくれる。
- `v-on`を使ったバインドをさせなくて良い。
- 簡潔に書ける。
- 処理中に別の関数を呼び出すことは出来ない。

```js:computedの例
Vue.component("ex-component", {
    computed: {
        wordCount: function() {
          /* this.wordCountの値がここで返された値になる */
          return this.message.length;
        },
...
```

## 参考
- [算出プロパティ](https://jp.vuejs.org/guide/computed.html)

# サンプルコード
 - [実行サンプル](http://codepen.io/yama-t/pen/OXZmdP)
 - [jQuery実装版](http://codepen.io/yama-t/pen/XKwqJW)

```html
<div id="app">
  <word-counter :max-word="100" :max-line="5" message="sample text"></word-counter>
  <word-counter :max-word="50" :max-line="3"></word-counter>
  <word-counter :max-word="200" :max-line="10" message="word 
break"></word-counter>
  <word-counter :max-word="5" :is-disable-line-count="true" message="word 
break"></word-counter>
</div>

<script type="x/template" id="word-counter">
  <div class="counter">
    <textarea class="area" rows="4" cols="40" v-model="message">{{message}}</textarea>
    <p class="count" :class="{error: isWordOver}">
      <span class="countNum">文字数：{{wordCount}}</span>
      <span class="countMax">{{maxWord}}</span>
    </p>
    <p class="line" v-if="isDisableLineCount">改行できません</p>
    <p v-else class="line" :class="{error: isLineOver}">
      <span class="countNum">行数：{{lineCount}}</span>
      <span class="countMax">{{maxLine}}</span>
    </p>
  </div>
</script>
```

```css
.countNum + .countMax:before {
  content: " / ";
}

.error {
  color: #FF0000;
}
```

```js
Vue.component("word-counter", {
  template: "#word-counter",
  props: ["message", "maxWord", "maxLine", "isDisableLineCount"],
  data: function() {
    this.message = this.message || '';
  },
  computed: {
    wordCount: function() {
      return this.message.length;
    },
    lineCount: function() {
      var newLineArr = this.message.match(/\n/g) || [],
        count = newLineArr.length + 1;

      if (this.message.length === 0) {
        count = 0;
      }

      return count;
    },
    isWordOver: function() {
      return this.wordCount > this.maxWord;
    },
    isLineOver: function() {
      return this.lineCount > this.maxLine;
    }
  }
});

new Vue({
  el: "#app"
});
```

# まとめ
- キー操作があるたびに随時変化を反映させる場合、computedが便利。
- ボタンをクリックするなど、ユーザーからのアクションがあって初めて値を反映させたい場合はmethodを使うといい。

# 外部リンク
- [コンポーネント - vue.js](https://jp.vuejs.org/guide/components.html)
- [Vue.jsでHTML内のテキスト・属性を参照したい](https://teratail.com/questions/45526)