# CH4 データの監視と加工

# S16 算出プロパティで処理を含むデータを作成

120~ページ

# 算出プロパティの使い方

120ページ

<p>{{ width }} の半分は {{ halfWidth }}</p>
new Vue({
  el: '#app',
  data: {
    width: 800
  },
  computed: {
    // 算出プロパティhalfWidthを定義
    halfWidth: function() {
      return this.width / 2
    }
  }
})
DEMO

800 の半分は 400

guide-ch4-demo01

# 算出プロパティを組み合わせて使用しよう

121ページ

<p>X: {{ halfPoint.x }}</p>
<p>Y: {{ halfPoint.y }}</p>
new Vue({
  el: '#app',
  data: {
    width: 800,
    height: 600
  },
  computed: {
    halfWidth: function() {
      return this.width / 2
    },
    halfHeight: function() {
      return this.height / 2
    },
    // 「width × height」の中心座標をオブジェクトで返す
    halfPoint: function() {
      return {
        x: this.halfWidth,
        y: this.halfHeight
      }
    }
  }
})

# ゲッターとセッター

122ページ

<input v-model.number="width"> {{ width }}
<input v-model.number="halfWidth"> {{ halfWidth }}
new Vue({
  el: '#app',
  data: {
    width: 800
  },
  computed: {
    halfWidth: {
      get: function() {
        return this.width / 2
      },
      // halfWidth の2倍の数値を width に代入する
      set: function(val) {
        this.width = val * 2
      }
    }
  }
})
DEMO
800
400
guide-ch4-demo03

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

123ページ

<p>算出プロパティ</p>
<ol>
  <li>{{ computedData }}</li>
  <li>{{ computedData }}</li>
</ol>
<p>メソッド</p>
<ol>
  <li>{{ methodsData() }}</li>
  <li>{{ methodsData() }}</li>
</ol>
new Vue({
  el: '#app',
  computed: {
    computedData: function() { return Math.random() }
  },
  methods: {
    methodsData: function() { return Math.random() }
  }
})
DEMO

算出プロパティ

  1. 0.5619131594924511
  2. 0.8040442586959189

メソッド

  1. 0.4065500693975048
  2. 0.5736991423688305
guide-ch4-demo04

# リストの絞り込みに利用しよう

124ページ

<div id="app">
  <input v-model.number="budget"> 円以下に絞り込む
  <input v-model.number="limit"> 件を表示
  <p>{{ matched.length }} 件中 {{ limited.length }} 件を表示中</p>
  <ul>
    <!-- v-forでは最終結果、算出プロパティのlimitedを使用する -->
    <li v-for="item in limited" v-bind:key="item.id">
      {{ item.name }} {{ item.price }}円
    </li>
  </ul>
</div>
new Vue({
  el: '#app',
  data: {
    // フォームの入力と紐付けるデータ
    budget: 300,
    // 表示件数
    limit: 2,
    // もとになるリスト
    list: [
      { id: 1, name: 'りんご', price: 100 },
      { id: 2, name: 'ばなな', price: 200 },
      { id: 3, name: 'いちご', price: 400 },
      { id: 4, name: 'おれんじ', price: 300 },
      { id: 5, name: 'めろん', price: 500 }
    ]
  },
  computed: {
    // budget以下のリストを返す算出プロパティ
    matched: function () {
      return this.list.filter(function (el) {
        return el.price <= this.budget
      }, this)
    },
    // matchedで返ったデータをlimit件返す算出プロパティ
    limited: function () {
      return this.matched.slice(0, this.limit)
    }
  }
})
DEMO
円以下に絞り込む 件を表示

3 件中 2 件を表示中

  • りんご 100円
  • ばなな 200円
guide-ch4-demo05

# ソート機能を追加しよう

126ページ

このサンプルコードでは Lodash を使用しています。「lodash.min.js」を読み込んでください。

<div id="app">
  <input v-model.number="budget"> 円以下に絞り込む
  <input v-model.number="limit"> 件を表示
  <button v-on:click="order=!order">切り替え</button>
  <p>{{ matched.length }} 件中 {{ limited.length }} 件を表示中</p>
  <ul>
    <!-- v-forでは最終結果、算出プロパティのlimitedを使用する -->
    <li v-for="item in limited" v-bind:key="item.id">
      {{ item.name }} {{ item.price }}円
    </li>
  </ul>
</div>
new Vue({
  el: '#app',
  data: {
    order: false,
    // フォームの入力と紐付けるデータ
    budget: 300,
    // 表示件数
    limit: 2,
    // 元になるリスト
    list: [
      { id: 1, name: 'りんご', price: 100 },
      { id: 2, name: 'ばなな', price: 200 },
      { id: 3, name: 'いちご', price: 400 },
      { id: 4, name: 'おれんじ', price: 300 },
      { id: 5, name: 'めろん', price: 500 }
    ]
  },
  computed: {
    // budget以下のリストを返す算出プロパティ
    matched: function() {
      return this.list.filter(function(el) {
        return el.price <= this.budget
      }, this)
    },
    // sortedを新しく追加
    sorted: function() {
      return _.orderBy(this.matched, 'price', this.order ? 'desc' : 'asc')
    },
    // limitedで使用するリストをsortedに変更
    limited: function() {
      return this.sorted.slice(0, this.limit)
    }
  }
})
DEMO
円以下に絞り込む 件を表示

3 件中 2 件を表示中

  • りんご 100円
  • ばなな 200円
guide-ch4-demo06

# S17 ウォッチャでデータを監視して処理を自動化

128~ページ

# ウォッチャの使い方

128ページ

オプションを使用しない場合

new Vue({
  // ...
  watch: {
    監視するデータ: function (新しい値, 古い値) {
      // valueが変化したときに行いたい処理
    },
    'item.value': function (newVal, oldVal) {
      // オブジェクトのプロパティも監視できる
    }
  }
})

オプションを使用する場合

new Vue({
  // ...
  watch: {
    list: {
      handler: function (newVal, oldVal) {
        // listが変化したときに行いたい処理
      },
      deep: true,
      immediate: true
    }
  }
})

インスタンスメソッドで登録する場合

this.$watch('value', function(newVal, oldVal) {
  // ...
})

オプション付きのインスタンスメソッドで登録する場合

this.$watch('value', function (newVal, oldVal) {
  // ...
}, {
  immediate: true,
  deep: true
})

# 一度だけ動作するウォッチャ

130ページ

new Vue({
  el: '#app',
  data: {
    edited: false,
    list: [
      { id: 1, name: 'りんご', price: 100 },
      { id: 2, name: 'ばなな', price: 200 },
    ]
  },
  created: function() {
    var unwatch = this.$watch('list', function () {
      // listが編集されたことを記録する
      this.edited = true
      // 監視を解除
      unwatch()
    }, {
      deep: true
    })
  }
})

# 実行頻度の制御

130ページ

このサンプルコードでは Lodash を使用しています。「lodash.min.js」を読み込んでください。

<input type="text" v-model="value">
new Vue({
  el: '#app',
  data: {
    value: '編集してみてね'
  },
  watch: {
    value: _.debounce(function (newVal) {
        // ここへコストの高い処理を書く
        console.log(newVal)
      },
      // valueの変化が終わるのを待つ時間をミリ秒で指定
      500)
  }
})

# フォームを監視してAPIからデータを取得しよう

133ページ

このサンプルコードでは axios を使用しています。「axios.min.js」を読み込んでください。

<div id="app">
  <select v-model="current">
    <option v-for="topic in topics" v-bind:value="topic.value">
      {{ topic.name }}
    </option>
  </select>
  <div v-for="item in list">{{ item.full_name }}</div>
</div>
new Vue({
  el: '#app',
  data: {
    list: [],
    current: '',
    topics: [
      { value: 'vue', name: 'Vue.js' },
      { value: 'jQuery', name: 'jQuery' }
    ]
  },
  watch: {
    current: function (val) {
      // GitHubのAPIからトピックのリポジトリを検索
      axios.get('https://api.github.com/search/repositories', {
        params: {
          q: 'topic:' + val
        }
      }).then(function (response) {
        this.list = response.data.items
      }.bind(this))
    }
  },
})

# S18 フィルタでテキストの変換処理を行う

134~136ページ

# フィルタの使い方

134ページ

new Vue({
  el: '#app',
  data: {
    price: 19800
  },
  filters: {
    localeNum: function (val) {
      return val.toLocaleString()
    }
  }
})

# 複数のフィルタをつなげて使用する

136ページ

new Vue({
  el: '#app',
  filters: {
    // 小数点以下を第2位に丸めるフィルタ
    round: function (val) {
      return Math.round(val * 100) / 100
    },
    // 度からラジアンに変換するフィルタ
    radian: function (val) {
      return val * Math.PI / 180
    }
  }
})
180 度は {{ 180 | radian | round }} ラジアンだよ

# S19 カスタムディレクティブ

137~ページ

# カスタムディレクティブの使い方

137ページ

new Vue({
  el: '#app',
  directives: {
    focus: {
      // 紐付いている要素がDOMに挿入されるとき
      inserted: function (el) {
        el.focus() // 要素にフォーカスを当てる
      }
    }
  }
})
<input type="text" v-focus>

# 使用可能なフック

139ページ

Vue.directive('example', {
  bind: function (el, binding) {
    console.log('v-example bind')
  },
  inserted: function (el, binding) {
    console.log('v-example inserted')
  },
  update: function (el, binding) {
    console.log('v-example update')
  },
  componentUpdated: function (el, binding) {
    console.log('v-example componentUpdated')
  },
  unbind: function (el, binding) {
    console.log('v-example unbind')
  }
})

# S20 nextTickで更新後のDOMにアクセスする

143~144ページ

# 更新後のDOMの高さを取得しよう

144ページ

<button v-on:click="list.push(list.length+1)">追加</button>
<ul ref="list">
  <li v-for="item in list">{{ item }}</li>
</ul>
new Vue({
  el: '#app',
  data: {
    list: []
  },
  watch: {
    list: function () {
      // 更新後のul要素の高さを取得できない…
      console.log('通常:', this.$refs.list.offsetHeight)
      // nextTickを使えばできる!
      this.$nextTick(function () {
        console.log('nextTick:', this.$refs.list.offsetHeight)
      })
    }
  }
})