핵심문법(Data) - plgrim-hannah/vue-study GitHub Wiki

#1. 이벤트 핸들링

1) 인라인 핸들러

- 이벤트가 트리거 될 때, 실행되는 인라인 javaScript 기능   
- 어떤 기능을 동작하는 코드가 HTML Element 내에 직접 할당되는 것을 의미함
<template>
  <div>
    <button v-on:click="count++">인라인 핸들러</button>

    <h1>{{ count }}</h1>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0,
    };
  },
};
</script>

<style lang="scss" scoped></style>

2) 메서드 핸들러

- 컴포넌트 scrpit  부분에 정의된 메서드(함수)를 이벤트 핸들러에 할당해주는 방식
<template>
  <div>
    <button v-on:click="changeName">메서드 핸들러</button>
    <h1>{{ name }}</h1>
  </div>
</template>

<script>
export default {
  data() {
    return {
      count: 0,
      name: "Vue.js",
    };
  },
  methods: {
    changeName() {
      this.name = "변경된 이름입니다";
    },
  },
};
</script>

<style lang="scss" scoped></style>

#2. Computed

1) 정의
- 함수처럼 코드를 작성하지만, return 시키는 데이터를 사용하여 데이터 취급을 하는 공통으로 사용하는 로직
- 복잡한 로직을 미리 처리하여 반복된 로직 처리를 방지하는 계산 형태의 데이터를 만드는 속성

2) 사용 이유
- 너무 많은 연산을 스크립트 또는 템플릿 HTML로 처리하면 복잡해지고 유지 보수가 어려워지기 때문에 Computed 속성을 이용하여 이를 해결함

3) 주의 점
- 함수 형태로 작성되나 데이터로 취급되기 때문에 이중 괄호로 출력시 괄호 없이 변수만 쓴다. (예. {{ comptedText }} )

  • key point
    • 두 가지 접근 방식 동일
      • 인라인에 연산식을 직접 대입
      • computed 객체 안에 선언
    • methods와 차이점
      • methods는 호출한 횟수만큼 동작
      • computed 속성은 캐싱이 Default로 여러 번 요청해도 계산을 다시 하지 않음
    • Caching
<template>
  <h3>{{ text }}</h3>
  <h3>chageText 함수 호출 값 : {{ changeText() }}</h3>
  <h3>chageText 함수 호출 값 : {{ changeText() }}</h3>
  <h3>chageText 함수 호출 값 : {{ changeText() }}</h3>

  <h3>computedText 함수 호출 값 : {{ computedText }}</h3>
  <h3>computedText 함수 호출 값 : {{ computedText }}</h3>
  <h3>computedText 함수 호출 값 : {{ computedText }}</h3>
</template>

<script>
export default {
  data() {
    return {
      text: "computed 테스트 데이터 문구입니다.",
    };
  },
  // methods에 선언된 함수와 동일한 로직일 때,
  // 캐싱 기능이 없는 methods는 호출될 때마다 console 값이 출력되었다.
  // 반면에, computed는 캐싱 기능이 있기 때문에 최초 계산 될때 단 한번만 출력된다.
  computed: {
    computedText() {
      console.log("Computed 기능을 생성하였습니다");
      return this.text.split("").reverse().join("");
    },
  },
  methods: {
    changeText() {
      console.log("함수 호출");
      console.log(this.text);

      return this.text.split("").reverse().join("");
    },
  },
};
</script>

<style lang="scss" scoped></style>

📌 methods vs computed

  • methods는 실행시키는 횟수만큼 재실행된다. image

  • computed는 최초 계산 시 단 한번만 동작한다 image

#3. Watch

1) 정의
- 어떤 데이터를 감시하고 있다가(지켜보고 있다가) 그 데이터의 값이 변했을 때,
그것을 감지하여 그와 관련된 함수, 로직, 연산 등 다양한 기능을 추가적으로 활용할 수 있도록 도와주는 속성

2) 특성
- 데이터 변경에 대한 응답으로 비동기 또는 시간이 많이 소용되는 조작을 수행하려는 경우 유용함 - 특정 프로퍼티 변경 시점에 특정 액션(call api, push route 등) 취하고자 할 때 적합함

3) 활용 예시

  • 게시판 페이지 변경

  • 선택한 페이지에 대한 리스트만 불러오는 경우

  • 변경된 페이지 번호(페이지네이션 번호)만 감지

  • 📌 정리

    • messgae : function {} 형태로 쓰임 (호출할 때는 변수명만)
    • 데이터 뿐만 아니라 computed로 계산된 형태의 데이터도 watch로 감지할 수 있다.
    • 보통 게시판에서 한 컬럼을 선택했을 때, 고유한 id 값이 바뀜을 감지하고
      이때, 그 id 값에 따른 상세 데이터를 호출할 때, 주로 사용한다
<template>
  <button @click="changeMessage">
    {{ message }}
  </button>
  {{ watchMessage }}
</template>

<script>
import { watch } from "vue";

export default {
  data() {
    return {
      message: "안녕하세요. Vue.js watch test 입니다.",
      watchMessage: "",
    };
  },
  watch: {    
    // 보통 게시판에서 한 컬럼을 선택했을 때, 고유한 id 값이 바뀜을 감지하고
    // 이때, 그 id 값에 따른 상세 데이터를 호출할 때, 주로 사용한다
    message() {
      this.watchMessage = "Watch 동작!!!";
    },
    id() {
      // 해당 상세 데이터를 조회하는 api 호출 (예시)
    }
  },
  methods: {
    changeMessage() {
      console.log("함수호출");
      this.message = "변경된 message 데이터입니다";
    },
  },
};
</script>

<style lang="scss" scoped></style>

#4. Props와 Emits

image

  • Props, Emits 모두 단반향 컴포넌트

  • Props참고

    • Props로 받은 데이터의 타입은 설정이 가능하고 그 데이터 값은 불가함(readOnly)
  • Emit 참고

    • 첫 번째 인자 : 부모 컴포넌트에서 사용될 이벤트 이름
    • 두 번째 인자 : 보낼 데이터 또는 이벤트

✏ Props 예제

1) Options API

<!--App.vue-->
<template>
  <div>
    <ChildComponent
      v-bind:sendProps1="title"
      v-bind:sendProps2="creatAt"
      v-bind:sendProps3="obj"
    />
  </div>
</template>

<script>
import ChildComponent from "./components/ChildComponent.vue";
export default {
  components: {
    ChildComponent,
  },
  data() {
    return {
      title: "부모컴포넌트에 선언된 데이터입니다",
      creatAt: 2024,
      obj: {
        id: 2000,
        name: "hannah",
      },
    };
  },
};
</script>

<style lang="scss" scoped></style>
<!--ChildComponent.vue-->
<template>
  <div>{{ sendProps1 }}</div>
  <div>{{ sendProps2 }}</div>
  <div>{{ sendProps3.id }}</div>
  <div>{{ sendProps3.name }}</div>
</template>

<script>
export default {
  props: {
    sendProps1: String,
    sendProps2: Number,
    sendProps3: Object,
  },

  data() {
    return {};
  },
};
</script>

<style lang="scss" scoped></style>

2) Composition API

  • composition API 사용 시, 반응형 데이터는 ref<T>로 반응형 객체는 reactive<T>로 선언한다.

  • 객체의 경우 interface를 만들어서 멤버 변수의 타입을 지정해주고, 객체 타입으로 이용한다.

  • defineProps는 import 할 필요 X, toRefs는 import 해주어야한다.

  • defineProps, toRefs 내장함수를 통해 Prop 받은 데이터를 활용하여 템플릿 부분에 호출하여 사용한다.

  • toRefs 를 사용하면 props.sendProps1 로 사용했던 변수명을 sendProps1로 간단하게 쓸 수 있다.

<!--App.vue-->
<template>
  <div>
    <ChildComponent
      v-bind:sendProps1="title"
      v-bind:sendProps2="creatAt"
      v-bind:sendProps3="obj"
    />
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from "vue";
import ChildComponent from "./components/ChildComponent.vue";

// composition API 사용 시, 반응형 데이터는 ref<T>로 반응형 객체는 reactive<T>로 선언함
// 객체의 경우 interface를 만들어서 멤버변수의 타입을 지정해주고, 객체 타입으로 이용한다.

interface Obj {
  id: number;
  name: String;
}

const title = ref<String>("부모컴포넌트에 선언된 데이터입니다");
const creatAt = ref<number>(2024);
const obj = reactive<Obj>({
  id: 2000,
  name: "hannah",
});
</script>

<style lang="scss" scoped></style>

<!--ChildComponent.vue-->
<template>
  <div>{{ sendProps1 }}</div>
  <div>{{ sendProps2 }}</div>
  <div>{{ sendProps3.id }}</div>
  <div>{{ sendProps3.name }}</div>
</template>

<script setup lang="ts">
import { toRefs } from "vue";

interface Obj {
  id: number;
  name: String;
}

// 1. 컴포지션 API 에서 타입스크립트 활용하는 방법
// 1.1 Props 받은 데이터 형식에 맞는 데이터를 지정해준다.

// Prop 받은 데이터 이름 자체에 미리 선언 해둔 타입을 설정해준다.
interface Props {
  sendProps1: String;
  sendProps2: Number;
  sendProps3: Obj;
}

const props = defineProps<Props>();
const { sendProps1, sendProps2, sendProps3 } = toRefs(props);
</script>

<style lang="scss" scoped></style>

image

✏ Emits 예제

1) Composition API

  • defineEmits(["전달할 이벤트 이름"]) 형식으로 사용
  • event에 바인딩할 변수는 .value까지 붙여서 써준다.
    (아래의 예제에서 data로 쓰면 오류 날 수 있음. data.value = "자식 컴포넌트에서 선언된 데이터입니다.")
<!--ChildComponent.vue-->
<template>
  <button @click="sendEvent">자식컴포넌트에서 만든 버튼</button>
</template>

<script setup lang="ts">
import { ref } from "vue";

const data = ref<String>("자식 컴포넌트에서 선언된 데이터입니다.");


const emit = defineEmits(["send-event"]);
const sendEvent = () => {
  emit("send-event", data.value);
};
</script>

<style lang="scss" scoped></style>
<!--App.vue-->
<template>
  <div>
    부모 컴포넌트 레이아웃
    <ChildComponent @send-event="parentEvent" />
  </div>
</template>

<script setup lang="ts">
import ChildComponent from "./components/ChildComponent.vue";

const parentEvent = (event: string) => {
  console.log(event);
};
</script>

<style lang="scss" scoped></style>

2) Options API

<!--ChildComponent.vue-->
<template>
  <button @click="sendEvent">자식컴포넌트에서 만든 버튼</button>
</template>

<script>
export default {
  data() {
    return {
      text: "자식 컴포넌트에서 선언된 데이터입니다.",
    };
  },
  methods: {
    sendEvent() {
      this.$emit("send-event", this.text);
    },
  },
};
</script>

<style lang="scss" scoped></style>
<!--App.vue-->
<template>
  <div>
    부모 컴포넌트 레이아웃
    <ChildComponent @send-event="parentEvent" />
  </div>
</template>

<script>
import ChildComponent from "./components/ChildComponent.vue";
export default {
  components: {
    ChildComponent,
  },
  methods: {
    parentEvent(event) {
      console.log(event);
    },
  },
};
</script>

<style lang="scss" scoped></style>

image

#5. v-model

image

  • 데이터 바인딩 ?

    • 두 데이터 또는 정보의 소스를 일치 시키는 기법으로 화면에 보이는 데이터와 브라우저 메모리에 있는 데이터를 일치 시키는 방법
  • 양방향 데이터 바인딩 ?

    • 컨트롤러(자바스크립트 변수에 담긴 데이터)와 뷰(HTML에 입력한 데이터)가 일치 되는 형상
    • HTML에 입력한 value 값이 입력되는 즉시 데이터의 변경을 감지하여 데이터가 변경되는 시점에 DOM 객체에 렌더링을 해주거나
      페이지 내에서 모델의 변경을 감지하여 자바스크립트 실행뷰에서 변경함 (실시간 갱신 )
 <template>
  <div>
    <input type="text" v-model="inputValue1" />
    <input
      type="text"
      v-model="inputValue2"
      @input="inputValue2 = $event.target.value"
    />
    <!--onChange onInput => v-on => @change, @input-->
  </div>
  <div>{{ inputValue1 }}</div>
  <div>{{ inputValue2 }}</div>
</template>

<script>
export default {
  data() {
    return {
      inputValue1: "",
      inputValue2: "",
    };
  },
};
</script>

<style lang="scss" scoped></style>

⇒ 한글의 경우 input 태그 특성 상 입력이 끝나면 끝까지 감지 되지 않는다.
보통 form 태그 입력 후 버튼을 누르는 등 다른 action을 취하기 때문에 사용에는 큰 문제가 없으나
좀 더 정교하게 바꿀 필요가 있다면 @input="inputValue2 = $event.target.value" 이렇게 실시간 감지 이벤트를 걸어준다!

📌 @click vs v-on:click

onClick onChange onInput => v-on => @click,, @change, @input

=> 기본형이냐 축약형이냐… 기능 똑같음.

◽ 표현법

// 기본문법
<a v-on:click=“method()></a>

// 단축표현
<a @click=“method()></a>

// 동적 argument의 단축표현
<a @[event]=“method()></a>

◽ 이벤트 여러 개 할당하기

// @click=[method1(), method2()] 이렇게 써준다.
<div @click=[method1(), method2()]></div>
⚠️ **GitHub.com Fallback** ⚠️