B.TIL 11 : Computed

김기욱·2020년 12월 8일
0

B.TIL

목록 보기
12/15

Computed

데이터 자체의 변화를 감지하는 Watch 속성과 다르게 Computed는 method와 비슷하게 하나의 함수로서 작성됩니다. 그렇다면 method와 computed에 다른점은 무엇일까요?

export default{
data() {
  return {
    message : 'helloworld'
  }
}
computed: {
    reversedMessage: function () {
      return this.message.split('').reverse().join('')
    },
methods: {
  reversedMessage: function () {
    return this.message.split('').reverse().join('')
  }
}
}

computed 속성 대신 메소드와 같은 함수를 정의할 수도 있습니다. 최종 결과에 대해 두 가지 접근 방식은 서로 동일합니다. 차이점은 computed 속성은 종속 대상을 따라 저장(캐싱)된다는 것 입니다.

computed 속성은 해당 속성이 종속된 대상이 변경될 때만 함수를 실행합니다. 즉 message가 변경되지 않는 한, computed 속성인 reversedMessage를 여러 번 요청해도 계산을 다시 하지 않고 계산되어 있던 결과를 즉시 반환합니다.

Computed를 활용해서 계산서 템플릿 만들기

HTML

<template>
  <div class="box">
    <div class="parent-box">
      <div class="computer">
        <div class="coupon-box">
          <input
            type="checkbox"
            id="coupon"
            value="쿠폰 할인"
            @click="clickChanger('coupon')"
          />
          <label for="coupon">쿠폰 할인</label>
          <input
            class="discount"
            ref="coupon"
            type="number"
            min="0"
            v-model="couponDiscount"
            disabled
          />
        </div>
        <div>
          <input
            type="checkbox"
            id="normal"
            value="일반 할인"
            @click="clickChanger('normal')"
          />
          <label for="normal">일반 할인</label>
          <input
            class="discount"
            ref="normal"
            type="number"
            min="0"
            max="100"
            v-model="normalDiscount"
            disabled
          />
        </div>
        <div>
          <input
            type="checkbox"
            id="evt"
            value="이벤트 할인"
            @click="clickChanger('evt')"
          />
          <label for="evt">이벤트 할인</label>
          <input
            class="discount"
            ref="evt"
            type="number"
            min="0"
            max="100"
            v-model="eventDiscount"
            disabled
          />
        </div>
        <div>
          <input
            type="checkbox"
            id="staff"
            value="직원 할인"
            @click="clickChanger('staff')"
          />
          <label for="staff">직원 할인</label>
          <input
            class="discount"
            ref="staff"
            type="number"
            min="0"
            max="100"
            v-model="staffDiscount"
            disabled
          />
        </div>
        <div>
          원가 :
          <input
            type="text"
            ref="original"
            value="original"
            v-model="originalPrice"
          />
        </div>
      </div>
      <div class="display">
        <img
          class="image"
          src="https://image.brandi.me/cproduct/2020/10/17/21141610_1602936769_image1_L.jpg"
        />
        <div class="discount-box">
          <div class="discount-list">
            <div v-if="is_coupon_clicked">
              쿠폰적용가 {{ couponDiscount }}원
            </div>
            <div v-if="is_normal_clicked">일반 할인 {{ normalDiscount }}%</div>
            <div v-if="is_evt_clicked">이벤트 할인 {{ eventDiscount }}%</div>
            <div v-if="is_staff_clicked">직원 할인 {{ staffDiscount }}%</div>
            <div v-if="originalPrice" class="original-price">{{ price }}원</div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

HTML에서는 inputlabel을 활용해서 구성하고, 각각 v-model로 data에 있는 요소들과 바인딩을 해둡니다. 할인율은 -10% 할인이라는 수치는 논리적으로 성립되지 않으므로 HTML 인라인 속성으로 min값을 설정해둡니다.

input tag에서 type을 넘버로 설정하면 단순히 타이핑을 통해 input뿐만 아니라 마우스 커서와 미니 버튼을 통해 1씩 조정을 하는것도 가능해집니다.

label을 쓴 이유는 체크박스의 사용을 용이하기 위해서입니다.
labelvalue를 통해 넘버타입 input과 체크박스타입 input을 연결을 해두면 체크박스를 정확히 클릭안하고 옆에있는 넘버타입 input만 클릭해도 체크박스를 클릭 한 것과 동일한 효과를 줄 수 있습니다.

disabled라는 인라인 속성을 통해 사용/불능 상태로 조절할 수 있습니다. 이를 method와 활용한다면 동적으로 사용/불능 모드를 사용자가 설정할 수 있게 됩니다.

체크박스에 걸어둔 클릭이벤트에 파라미터를 담아서 보내 하나의 함수에서 다수의 태그를 상황마다 컨트롤 할 수 있게됩니다.

<script>
export default {
  data() {
    return {
      couponDiscount: 1000,
      normalDiscount: 10,
      eventDiscount: 10,
      staffDiscount: 10,
      originalPrice: "",
      is_coupon_clicked: false,
      is_normal_clicked: false,
      is_evt_clicked: false,
      is_staff_clicked: false,
    };
  },

  methods: {
    clickChanger(val) {
      if (val == "coupon") {
        this.is_coupon_clicked = !this.is_coupon_clicked;
        this.$refs.coupon.disabled = !this.$refs.coupon.disabled;
      } else if (val == "normal") {
        this.is_normal_clicked = !this.is_normal_clicked;
        this.$refs.normal.disabled = !this.$refs.normal.disabled;
      } else if (val == "evt") {
        this.is_evt_clicked = !this.is_evt_clicked;
        this.$refs.evt.disabled = !this.$refs.evt.disabled;
      } else if (val == "staff") {
        this.is_staff_clicked = !this.is_staff_clicked;
        this.$refs.staff.disabled = !this.$refs.staff.disabled;
      }
    },
  },

  computed: {
    price() {
      let originalPrice = parseInt(this.originalPrice);
      if (this.is_coupon_clicked) {
        originalPrice -= this.couponDiscount;
      }
      if (this.is_normal_clicked) {
        originalPrice -= (originalPrice * this.normalDiscount) / 100;
      }
      if (this.is_evt_clicked) {
        originalPrice -= (originalPrice * this.eventDiscount) / 100;
      }
      if (this.is_staff_clicked) {
        originalPrice -= (originalPrice * this.staffDiscount) / 100;
      }
      return originalPrice.toFixed().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    },
  },
};

data에는 여러 할인요소들과 (정률과 정액할인 둘다 존재) 시작가 그리고 각각의 태그들의 온오프스위치 역할을 하는 상태 데이터들로 구성되어있습니다.

clickChanger함수는 파라미터에 따라 각각의 disabled 상태를 동적으로 변경시켜줍니다. 여기서는 vue에서 엘리먼트조작을 하기위해 쓰이는 ref를 활용합니다.

대망의 computed입니다.

계산을 하기위해선 모든 요소는 반드시 INT속성이어야 합니다. 때문에 parseInt라는 자바스크립트 함수를 사용해 데이터에 존재하는 시작가를 INT속성화 시켜줍니다.

disabled 상태가 해제된 할인요소들만 할인가가 적용되야 하므로 조건문을 통해 해당 할인요소들 마다 할인율을 적용시켜줍니다.

다음은 각각의 할인요소들이 존재하고, 그 값이 존재할 때 시작가를 변화시키는 로직을 구현합니다.
정률을 퍼센테이지로 정액은 액수 그대로 경감시켜줍니다.
마지막으로 반환되는 값에 정규식을 써서 1000의자리 단위로 쉼표를 찍어줍니다.

profile
어려운 것은 없다, 다만 아직 익숙치않을뿐이다.

0개의 댓글