CH4 데이터 감시하고 가공하기

S16 산출 속성으로 처리를 포함한 데이터 만들기

106~페이지

산출 속성 사용 방법

106페이지

<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

산출 속성을 조합해서 사용하기

107페이지

<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
      }
    }
  }
})

게터와 세터

108페이지

<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

산출 속성 캐시 기능

109페이지

<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.40774244857729536
  2. 0.41589396584377436

메소드

  1. 0.6382572160079505
  2. 0.39272511762462625
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: 3000,
    // 출력할 개수
    limit: 2,
    // 데이터 리스트
    list: [
      { id: 1, name: '사과', price: 1000 },
      { id: 2, name: '바나나', price: 2000 },
      { id: 3, name: '딸기', price: 4000 },
      { id: 4, name: '오렌지', price: 3000 },
      { id: 5, name: '메론', price: 5000 }
    ]
  },
  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개를 출력하고 있습니다.

  • 사과 1000원
  • 바나나 2000원
guide-ch4-demo05

정렬 기능 추가하기

113페이지

현재 샘플 코드에서는 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: 3000,
    // 출력할 개수
    limit: 2,
    // 데이터 리스트
    list: [
      { id: 1, name: '사과', price: 1000 },
      { id: 2, name: '바나나', price: 2000 },
      { id: 3, name: '딸기', price: 4000 },
      { id: 4, name: '오렌지', price: 3000 },
      { id: 5, name: '메론', price: 5000 }
    ]
  },
  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개를 출력하고 있습니다.

  • 사과 1000원
  • 바나나 2000원
guide-ch4-demo06

S17 워처로 데이터 감시해서 처리 자동화하기

115~121페이지

워처 사용 방법

115페이지

옵션을 사용하지 않는 경우

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
})

한 번만 동작하는 워처

118페이지

new Vue({
  el: '#app',
  data: {
    edited: false,
    list: [
      { id: 1, name: '사과', price: 1000 },
      { id: 2, name: '바나나', price: 2000 },
    ]
  },
  created: function() {
    var unwatch = this.$watch('list', function () {
      // list가 편집되었는지 기록하기
      this.edited = true
      // 감시 제거하기
      unwatch()
    }, {
      deep: true
    })
  }
})

실행 빈도 제어하기

118페이지

현재 샘플 코드에서는 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밀리 초 동안 대기하기
      500)
  }
})

입력 양식을 감시하고 API로 데이터 가져오기

120페이지

현재 샘플 코드에서는 Lodash를 사용하고 있습니다. 실제 운용할 때는 'lodash.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) {
      // 깃허브 API에서 토픽 리포지토리 검색하기
      axios.get('https://api.github.com/search/repositories', {
        params: {
          q: 'topic:' + val
        }
      }).then(function (response) {
        this.list = response.data.items
      }.bind(this))
    }
  },
})

S18 필터로 텍스트 변환 처리하기

122~125페이지

필터 사용 방법

122페이지

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

여러 개의 필터를 연결해서 사용하기

124페이지

new Vue({
  el: '#app',
  filters: {
    // 소수점 이하 두 번째 자리까지 끊는 필터
    round: function (val) {
      return Math.round(val * 100) / 100
    },
    // 도 단위를 라디안 단위로 변환하는 필터
    radian: function (val) {
      return val * Math.PI / 180
    }
  }
})
180도는 {{ 180 | radian | round }} 라디안입니다 .

S19 사용자 정의 디렉티브로 데이터를 감시하면서 DOM 조작하기

126~131페이지

사용자 정의 디렉티브 사용 방법

126페이지

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에 접근하기

132~134페이지

변경 후의 DOM 높이 확인하기

133페이지

<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)
      })
    }
  }
})