본문 바로가기

Local Oriented/Vue.js

Vue3 + Typescript + script setup

<!-- template 안에서는 props. 생략 가능 (.value 생략하는 것과 동등) -->

<template>

  <div ref="refDiv">...</div>

  <ChildComponent ref="refChild">...</ChildComponent>

  <OuterComponent ref="refOuter">...</OuterComponent>

</template>

 

<script setup lang="ts">

import { ref, onMounted, watch } from 'vue';
import ChildComponent from '@ChildComponent'; // ChildComponent.vue
import { OuterComponent } from '@OuterComponent'; // 외부 라이브러리

import * as CMP from '@Composable'; // 개발자가 만든 컴포저블 라이브러리 Composable.ts

 

// 타입기반 선언. 버전에 따라 import 필요. Parent vue 에서 v-bind 하려면 ref() 적용 요망

// primitive 는 사용하지 않는 것으로.. (사용해도 에러는 없는데..)

const props = defineProps<{ // javascript 에서는 defineProps({ ..., });

  prop1: Number, // props.prop1 로 사용. template 에서는 prop1 로 사용

  prop2: String, // props.prop2 로 사용. template 에서는 prop2 로 사용
}>();

 

// 타입기반 선언. vue 버전에 따라 import 필요

// child 의 template 에서 빌트인 $emit 메서드 사용 가능. @click="$emit('fooEmit')"

// 파라미터는 $emit('fooEmit', param), parent 에서는 @fooEmit="(p) => ..." 처럼..
const emit = defineEmits<{ // javascript 에서는 defineEmits([ '...', ]);

  // Parent vue 에서 함수  정의. const fooEmit = (p1: string, p2?: number) => { ... }

  // 동일한 key 사용 불가하므로, 공통 component 로 사용하는 경우 접미사를 다르게 하는 방식을 추천

  fooEmit: [param1: string, param2?: number], // Child vue 에서 emit('fooEmit', par1) 사용
}>();

// ref(null) 도 가능하지만, build 시 에러

const refDiv = ref<HTMLElement>(); // refDiv.value. value 에 ? 나 ! 를 상황에 맞게 적용

const refChild = ref<HTMLElement>(); // refChild.value.함수() 또는 refChild.value.변수 와 같이 사용

const refOuter = ref<OuterComponent>(); // refOuter.value 를 통해 라이브러리에서 제공하는 개체나 함수 사용

 

const foo1 = (p1: string, p2: number) => {
  ...

};

const foo2 = () => {

  let str = '...';

  let i = ...;
  foo1(str, i);

  CMP.foo3(); // foo3 는 컴포저블에서 export 한 함수

};

 

onBeforeMount(() => { // mount 되기 전에 template 에 적용할 사항이 있는 경우 기술

});

 

onMounted(() => {
  ... // ref 나 ref.value 가 undefined 일 수 있음에 유의. 이건 vue 오류로 보임

});

 

// props 에 primitive 가 아니라, object 주소가 넘어오는 경우.. 주소가 변경되지 않고 그 안의 값이 변한다면

// watch 로 감지하기 위해 주소 아랫단의 object 를 기술해야 함

watch(props, () => { // deep watch 가능. props 에 기술된 object 가 deep 구조인 경우 이의 변화를 인식
  ...
}

 

defineExpose({ // 버전에 따라 import

  // Parent vue 에 노출할 Child vue 의 개체 기술. 변수, 함수, 개체, ...

  // 이곳에 기술되지 않으면 Parent vue 에서 사용 불가(설정에 따라 다를 수 있음).

});

</script>

 

<style scoped><!-- scoped 처리하지 않는다면, 외부 .js 에 넣거나,

하나의 component 를 재사용 하는 경우나 App.vue 에서만 사용 -->

  ...

</style>

 

Composable 제공 함수는 작업 대상을 파라미터로 주입하는 방식 추천.

 

<... ref="ref1">...</...> 인 경우,

Options API 에서는 this.$refs.ref1 또는 this.$refs['ref1'] 과 같이 사용하지만,

Composition API 에서는 const ref1 = ref<Type>(); 으로 정의하고, ref1.value 로 사용.

Options API 보다 코딩량이 늘어나는 이유가 되기도 해서,
.value 를 많이 사용하는 개체라면..

script 상단에서 .value 를 담을 변수를 let 으로 정의하고,

onMounted() 에서 해당 변수에 .value 를 담아서 활용하는 것도 나쁘지 않음.

<div ref="refDiv1">...</div>

const refDiv1 = ref<HTMLElement>(); // 변수명은 ref 에서 기술한 명칭

refDiv1.value!.style.fontSize = '5px'; // ? 가 작동하지 않으면 ! 사용. 대체로 함수나 이벤트류는 ? 가능, 변수는 ! 사용