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

#bind()メソッドについて

```js
const module = {
  x: 42,
  getX: function() {
    return this.x;
  }
};

const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined

const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42
```

thisの意味するものがその時々で異なるので、bind(）メソッドを使って指定してあげるというイメージで合ってるかな？

*以下参考サイト

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/bind


#ビットコインの価格表示プログラム

```html
<div id="app">
  <h2>
    Bitcoin Price
  </h2>
  <section v-if="hasError">
    Error,
  </section>
  <section v-else>
    <div v-if="loading">
      Loading...
    </div>
    <div v-else> 
      <ul v-cloak>
        <li v-for="(rate, currency) in bpi">
          {{ currency }} : {{ rate.rate_float | currencyDecimal }}
        </li>
      </ul>
    </div>   
  </section>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
```

注意すべきは、v-ifディレクティブとv-elseディレクティブ。
rubyのif elseと同じように、v-ifがfalseの時にv-else以下のコードが表示される。

```js
var app = new Vue({
  //options
  el: '#app',
  data: {
  	bpi: null,
    hasError: false,
    loading: true
  },
  //マウントされた後に呼ばれる
  mounted: function() {
    axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
    //responseにAPIからの戻り値が入る
    .then(function(response){
      //console.log(response.data.bpi)
      //console.log(response.data.bpi.USD.rate_float)
      this.bpi = response.data.bpi
    }.bind(this))
    //コンソールにエラーを出力
    .catch(function(error){
      console.log(error)
      this.hasError = true
    }.bind(this))
    //finallyは処理の最後に行うことができる
    //これでLoading...マークが消えて価格が表示される
    .finally(function(){
      this.loading = false
    }.bind(this))
  },
  filters: {
    currencyDecimal(value) {
      //toFixedメソッドは小数点の桁数を引数に指定することができる。
      return value.toFixed(2)
    }
  }
})
```

#様々なテンプレート制御ディレクティブ

##v-once

初回だけテキストバインディングを行いたい時に使う。

つまり、初回だけテンプレートを評価する

```html
<div id="app">
  <p v-once>
    {{ message }}
  </p>
  <button v-on:click="clickHandler">
    Click!
  </button>
</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!'
  },
  methods: {
    clickHandler: function(event) {
      this.message = this.message.split('').reverse().join('')
    }
  }
})
```

上記ではボタンがクリックされるとmessageプロパティの文字を反転させるプログラムを組んでいるが、テンプレート側にv-onディレクティブが記載されているため、初回の
Hello Vue.js!は表示されるが、ボタンを押して文字が反転することはない。

これはv-onceが初回だけバインディングする機能によるもの。

##v-pre

要素と全ての子要素のコンパイルをスキップしたい時に使う。

生のマスタッシュタグを表示したい
XSS対策
コンパイルのスピードを上げたい

そんな時に使うらしい。


```html
<div id="app">
  <p v-pre>
    {{ 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: 'Hello Vue.js!'
  }
})
```

本来は{{ message }}によってブラウザにHello Vue.js!と表示される。

しかし、pタグにv-preディレクティブを追加すると、コンパイルが行われずに

{{ message }} とブラウザに表示されるようになる。


##v-html

プレーンなhtmlを挿入したい時に使う

本来はXSS対策のため、ユーザーが<p>アイウエオ</p>と文字列を入力しても

```
<p>アイウエオ</p>
```

と表示される。

ただ、v-html="プロパティ名"を追加すると、それがhtmlタグとして評価される


```html
<div id="app">
  <p>
    {{ message }}
  </p>
  <p v-html="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: 'Hello <span style="color:red">Vue.js!</span>'
  }
})
```
htmlファイルにpタグが2つあるが、

一つ目は

```
Hello <span style="color:red">Vue.js!</span>
```

と表示され、

v-htmlがついている2つ目は

```
Hello Vue.js!
```

と表示される。

##v-cloak

cloakは日本語で覆い隠すという意味。

ページを表示開始してからインスタンスの作成が終わるまでの間に、
マスタッシュタグやコンパイル前のテンプレートが表示されてしまうのを防ぎたい。

v-cloakディレクティブを使ったチラつき防止のやり方

1.インスタンスのコンパイルが終了するまで、非表示にしたい要素に、v-cloakディレクティブを追加。

2.cssでv-cloakがついている要素を非表示にする

3.v-cloakディレクティブは、インスタンスの準備が終わると、自動的に取り除かれる。

```html
<div id="app">
  <p v-cloak>
    {{ message }}
  </p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```
pタグにv-cloakをつける

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

```css
[v-cloak] {
  display: none;
}
```

v-cloakをセレクタとしてcssを書けば、インスタンスの準備中だけマスタッシュタグを非表示にすることができる。

##v-text

マスタッシュの代わりに、ディレクティブを使いたい時。

v-text="プロパティ名"とすることで、マスタッシュ構文を使わずにプロパティを表示することができる。

ただ、基本的にはマスタッシュ構文に統一するのがおすすめ。

```html
<div id="app">
  <p>
    {{ message }}
  </p>
  <p v-text="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: 'Hello Vue.js'
  }
})
```

#バインディング式

マスタッシュ構文の中では、プロパティにメソッドを呼び出したり、三項演算子で場合分けをしたりすることができる。


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

```html
<div id="app">
  <p>
    {{ message }}
  </p>
  <p>
    {{ number + 1 }}
  </p>
  <p>
    {{ message.split('').reverse().join('')}}
  </p>
  <p>
    {{ ok? 'Yes' : 'No' }}
  </p>
  <p>
    {{ ok? message : '' }}
  </p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

このようにマスタッシュ構文内で計算をしたり、メソッドを呼び出したりできる。
ただ、var app = ~~ のような代入はすることができないので注意。

=の右側に書ける処理ならマスタッシュ構文内でも書けると覚えておこう。


#フィルタ(ローカルフィルタ)

数字を千円区切りのカンマ区切りで表示したい。

ポイント！！！

Vue.jsでは、式の終わりに任意のフィルタを追加することができる。

```
{{ 式 | フィルタの名前 }}
```

上記のようにフィルタを呼び出す。


```html
<div id="app">
   <p>
     {{ price | numberFormat }}
   </p>
   <input type="text" v-bind:value="price | numberFormat">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

```js
var app = new Vue({
  //options
  el: '#app',
  data: {
  	price: 29800000
  },
  filters: {
    numberFormat: function(value) {
      return value.toLocaleString()
    }
  }
})
```

このように、filtersの中にフィルター名を決めて処理を書いていく。

フィルターはマスタッシュ構文内だけではなく、

```html
<input type="text" v-bind:value="price | numberFormat">
```

このようにプロパティを書けるところなら| フィルター名　で呼び出すことができる。


#フィルタ(グローバルフィルタ)

グローバルフィルターを定義するには

```
Vue.filter(フィルタ名, フィルタの動作)
```

とする

```html
<div id="app">
   <p>
     {{ price | numberFormat }}
   </p>
   <input type="text" v-bind:value="price | numberFormat">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

```js
Vue.filter('numberFormat', function(value) {
  return value.toLocaleString()
})

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

このように定義する。
グローバルフィルターを定義したことで、#appの要素以外でもフィルターを呼び出すことができるってこと。

#フィルターの連結

日本円をUSDに変換して、さらに3桁ずつで区切りたい。

ポイントはフィルタは複数連結することが可能ということ。

```js
//日本円をドルに変換
Vue.filter('toUSD', function(jpy) {
  return jpy / 100
})
//変換したドルを3桁ずつ区切る
Vue.filter('numberFormat', function(value) {
  return value.toLocaleString()
})

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

ここでは、複数のグローバルフィルタを用意する。

```html
<div id="app">
   <p>
     {{ jpyPrice | toUSD | numberFormat }}
   </p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```
上記のように|を複数使って、フィルターを連結することができる。


#フィルタの引数

長い文字列を、20文字...のように変換したい。

ポイントはフィルタをview側で呼び出す時に引数を指定できるということ。

```js
//lengthは何文字に省略するか、suffixは省略後の...のような文字列をどうするか
Vue.filter('readMore', function(text, length, suffix) {
  return text.substring(0, length) + suffix
})

var app = new Vue({
  //options
  el: '#app',
  data: {
  	text: 'In publishing and graphic design, Lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document or a typeface without relying on meaningful content. Lorem ipsum may be used before final copy is available, but it may also be used to temporarily replace copy in a process called greeking, which allows designers to consider form without the meaning of the text influencing the design.'
  }
})
```

```html
<div id="app">
   <p>
     {{ text | readMore(30, '...') }}
   </p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

readMoreフィルターでは引数が3つあるが、view側で呼び出す時は2つになっている点に注意。

この場合は、length, suffixをview側のフィルターを呼び出す引数で指定してあげれば良い。


#v-bind省略記法

```html
完全な構文
<a v-bind:href="url">LINK</a>

省略記法
<a :href="url">LINK</a>
```

v-bindを省略して:だけにすることができる。

```js
var app = new Vue({
  //options
  el: '#app',
  data: {
　　　url: 'google.com'
  }
})
```


```html
<div id="app">
   <p>
     <a v-bind:href="url" target="_blank">Link1</a>
     <a :href="url" target="_blank">Link2</a>
   </p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

二つのリンクがあるが、どちらも同じ。


#算出プロパティ

算出プロパティ　computedとは、
関数によって算出したデータを返すことができるプロパティ

算出プロパティを使って処理をまとめてみよう

```html
<div id="app">
  <p>
    {{ message.split('').reverse().join('') }}
  </p>
  <p>
    {{ reversedMessage }}
  </p>
</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!'
  },
  computed: {
  	reversedMessage: function() {
      return this.message.split('').reverse().join('')
    }
  }
})
```

算出プロパティに関しては、computed:以下に処理を書いていく。
Rubyでいうヘルパーみたいなものだと思っている。

今回はreversedMessageという算出プロパティを定義した。
これを

```html
<p>{{ reversedMessage }}</p>
```

このようにview側に書くだけで、文字を反転させて表示できる。
しかもこれを何回も使い回すことができる。

#メソッドと算出プロパティの違い

```html
<div id="app">
  <p>
    {{ message.split('').reverse().join('') }}
  </p>
  <p>
    {{ reversedMessage }}
  </p>
  <p>
    {{ reversedMessageMethod() }}
  </p>
</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!'
  },
  //算出プロパティ。プロパティなので呼び出す時にカッコがいらない。
  computed: {
  	reversedMessage: function() {
      return this.message.split('').reverse().join('')
    }
  },
  //メソッド。メソッドなので呼び出す時はカッコがいる。
  methods: {
    reversedMessageMethod: function() {
      return this.message.split('').reverse().join('')
    }
  }
})
```

一つ目の違いは、プロパティは呼び出す時に()が必要ない。対して、メソッドは呼び出す時に()が必要になる。

2つ目は、getterとsetter。これは以降で解説。

3つ目は、キャッシュがあるかどうか。プロパティはキャッシュがあるが、メソッドにはない。

ということで、使えるならなるべくプロパティを使った方が良いってこと？

#算出プロパティのgetter,setter

プロパティはgetterだけではなく、setterも定義できるのがmethodとの違い。

税抜き価格を入れると、税込価格を表示するプログラムを見ていこう

```html
<div id="app">
  <p>
    base price: <input type="text" v-model="basePrice">
  </p>
  <p>
    tax included price: <input type="text" v-model="taxIncludedPrice">
  </p>
  
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

```js
var app = new Vue({
  //options
  el: '#app',
  data: {
　  basePrice: 100
  },
  computed: {
    taxIncludedPrice: {
      get: function() {
        //parseIntは整数値を返す
        return parseInt(this.basePrice * 1.08)
      },
      set: function(taxIncludedPrice) {
        //Math.ceilは引数として与えた数以上の最小の整数を返します。
        this.basePrice = Math.ceil(taxIncludedPrice / 1.08)
      }
    }
  }
})
```

getterとsetterは文字通り、値を取得するのか、それとも値をセットするのか、というもの。

前提として、v-modelなのでviewからtaxIncludedPriceの値をセットすることが可能。

set:以下では、viewからセットされた税込価格をさらに1.08で割って税抜き価格をbasePriceに代入している。

これにより、税込価格を入れても税抜き価格が算出されるような形になる。

#算出プロパティのキャッシュ

comuputed キャッシュされる
methods キャッシュされない

ランダムな数字を取得する処理を算出プロパティとメソッドの両方でやってみる。

```html
<div id="app">
  <h2>Computed</h2>
  <ol>
    <li>{{ computedNumber }}</li>
    <li>{{ computedNumber }}</li>
    <li>{{ computedNumber }}</li>
  </ol>
  <h2>Methods</h2>
  <ol>
    <li>{{ methodsNumber() }}</li>
    <li>{{ methodsNumber() }}</li>
    <li>{{ methodsNumber() }}</li>
  </ol>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16"></script>
```

```js
var app = new Vue({
  //options
  el: '#app',
  
  computed: {
    computedNumber: function() {
    	return Math.random()
    }
  },
  methods: {
    methodsNumber: function() {
    	return Math.random()
    }
  }
})
```
この場合、算出プロパティは3つのランダムな数字が全て同じ値になる。
なぜなら、キャッシュされるから。

対して、メソッドの場合は毎回異なる数字になる。
なぜなら、キャッシュされないから。