HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
💌
JJong’s Archive
/
🏞️
Vue
/
컴포넌트

컴포넌트

Select
Nov 27, 2023
  • 케밥 케이스 : 소문자, 대시로
  • 파스칼 케이스 : 추천, but CDN 방법에서는 안 먹힌다는걸 주의
 

컴포넌트 등록

  1. 전역으로 등록하는 방법
      • createApp(App).component(’컴포넌트명’, 컴포넌트모듈)
      • 지역등록 과정을 거치지 않고 바로 쓸 수 있다.
  1. 지역적으로 등록하는 방법(일반적)
      • 쓰고 싶은 컴포넌트에서 import하고, components 속성으로 등록!
 

props

  • html에서는 케밥케이스, 컴포넌트 내에서는 카멜케이스
  • 컴포넌트의 props 속성으로 받는다
<template>{{message}}</template> <script> export default { props: ['message'] } </script>
  • v-bind: 속성이 아닌 v-bind 속성 값으로 속성들이 담긴 객체를 할당해서 props를 한번에 줄 수 있다
const user = { name: "aj", age: 12, hobby: "reading a book" } <Hello v-bind="user" /> //v-bind:name, :age, :hobby 한번에
  • props는 받는 컴포넌트 쪽에서에서는 변경불가하다.
    • 해결방법1) 해당 props 값으로 가지는 data를 추가해서 그 data를 조작
    • 해결방법2) 외부에서 이벤트 메서드를 처리, 하위 컴포넌트에서는 emit으로 이벤트를 발생시키는 방법
    • <template>{{message}}</template> <script> export default { props: ['message'], data() { return { msg: this.message } } } </script>
      해결방법1
  • props의 타입을 지정할 수 있다.
    • 지정된 타입 외의 props가 오면 경고가 뜬다
    • export default { props: { message: String, age: [String, Number], } }
  • 특정 props가 들어오지 않을 때를 대비해 기본값을 지정할 수 있다
    • required 속성이 없다면 들어오지 않았을 때 오류가 나진 않음
    • export default { props: { ... email: { type: String, default: "leon@abc.com", required: true } } }
 

non-props 속성

  • 컴포넌트에 props를 넘겨준다면, 받는 컴포넌트에서 아무런 지정을 해주지 않아도 template 내 태그에 그대로 적용된다
    • 그러나 받는 컴포넌트의 최상위 요소가 두개 이상이면, 적용되지 않는다(상속)
    • //App.vue <template> <Hello class="hello" style="font-size: 100px;" @click="msg += '!'" /> </template> //Hello.vue <template> <h1>Hello</h1> => h1에 class, style, onClick 속성이 붙는다 </template>
  • 받는 컴포넌트에서 vue 내장 객체인 $attrs로 props를 받아올 수 있다
    • $attrs : props로 넘겨는 주는데 등록은 하지않는 속성들로 이루어진 객체(=non-props)
    • <template> <h1 :class="$attrs.class">Hello</h1> <h2 :style="$attrs.style">Hahah</h2> <h3 @click="$attrs.onClick">so What?</h3> </template> <script> export default { //props 속성 없음 } </script>
    • 객체로 한번에 받아올 수 있다
    • <template> <h1 v-bind="$attrs">Hello</h1> //class,style, @click <h2 :style="$attrs.style">Hahah</h2> .. </template>
  • props로 받아온다면 $attrs와 에 해당되지 않고, 최상위요소가 한개일 때 묵시적으로 적용되지도 않는다
    • <template> <h1 :class="$attrs.class">Hello</h1> <h2>Hahah</h2> <h3 @click="$attrs.onClick">so What?</h3> </template> <script> export default { props: { style: Object } } </script>
  • non-props를 쓰지 않으려면 컴포넌트의 속성 중 inheritAttrs를 false로 준다(기본값은 true)
    • <script> export default = { inheritAttrs: false } </script>
 

커스텀 이벤트

  • eval로 커스텀 이벤트를 발생시키고, 해당 컴포넌트의 props로 핸들러를 등록한다
  • props를 부모, 자식 서로 갱신시키는 양방향 갱신!!
//Hello.vue <template> <h1 @click="#emit('please')">hello</h1> //커스텀 이벤트 발생 </template //App.vue <template> <Hello @please="reverseMsg" /> //커스텀 이벤트 핸들러 </template>
  • emits 옵션을 통해서 커스텀 이벤트를 등록할 수 있다
    • 커스텀 이벤트 목록을 명시적으로 확인 가능
    • 묵시적으로 넘어오는 native 이벤트와 이름과 같으면 덮어쓴다 ⇒ 명시적으로 써야 함
    • //App.vue <template> <Hello @click="msg += ?!">hello</h1> </template> //Hello.vue <template> <h1>안녕</h1> //App에서 click이벤트(네이티브)가 묵시적으로 넘어오지만 </template> <script> export default = { emits: ['click'] // 얘가 덮어씀(이제 $emit('click')으로 써야함) } </script>
  • emits 옵션에서 반환값을 표시할 수 있고, 함수의 기능을 추가할 수 있다
    • //App.vue <template> <Hello @click="msg += ?" @please="msg+=!">hello</h1> </template> //Hello.vue <template> <h1 @click="$emit('click')">안녕</h1> <h2 @click="$emit('please', 10)">hello</h2> //두번째 인수로 number </template> <script> export default = { emits: { click: null, //App.vue의 click이벤트만 please: number => { //App.vue의 please이벤트+추가기능 if (number > 10) { return true } else { console.error('') return false } } } } </script>
  • v-model라는 props를 넘겨주고, modelValue라는 이름으로 props를 받아온 후 update 이벤트를 발생시키면, 부모의 데이터를 변경할 수 있다 ⇒ 부모-자식 양방향 데이터
    • v-model: 새이름 으로 넘겨주면, modelValue이름 대신에 새이름으로 받을 수 있다
    • //App.vue <template> <h1>{{ msg }}</h1> <Hello v-model="msg" /> //props 넘겨주기, emit으로 인해 msg가 변경됨 </template> //Hello.vue <template> <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" > // 1. update 이벤트 발생하고 modelValue와 연결 // 2. input의 value를 App으로 넘겨줌 -> App의 msg가 변경됨 (양방향 데이터) </template> <script> export default { props: { modelValue: { //props받기 type: String, default: '' } }, .. </script>
  • v-model을 2개 이상 만들 수 있음
    • //App.vue <template> <h1>{{ msg }}</h1> <h1>{{ name }}</h1> <Hello v-model:message="msg" v-model:name="name" /> </template> //Hello.vue <template> <input :value="message" @input="$emit('update:message', $event.target.value)" > <input :value="name" @input="$emit('update:name', $event.target.value)" > </template> <script> export default { props: { message: { type: String, default: '' }, name: { type: String, default: '' } }, .. </script>
 

컴포넌트 Slots

  • 컴포넌트를 호출할 때 content를 넣어주면, 해당 컴포넌트의 <slot> 태그에서 받을 수 있다
  • slot의 content를 넣어줘서 기본값을 줄 수 있다
//App.vue <template> <Hello><h3>hihi</h3></Hello> //content를 넣어줌 => slot으로 <Hello /> //content 없음 </template> //Hello.vue <template> <slot>냉무</slot> //내용이 들어옴. 기본값: 냉무 <h1>{{ msg }}</h1> </template>
  • 컴포넌트의 자식을 template 태그로 분리하고, 해당 template에 v-slot으로 이름을 부여해서 slot을 나눠 쓸 수 있다
    • v-slot:이름 == #이름
    • 해당 컴포넌트의 slot에서 name 속성과 같은 v-slot이름을 매칭시킨다
    • 이름이 없는 자식은 기본 slot 태그로 받아올 수 있다
    • //App.vue <template> <Hello> <template v-slot:hi> //첫번째 자식 <h3>hihi</h3> </template> <template #bye> //약어, 두번째 자식 <h3>byebye</h3> </template> <h3>인사</h3> </Hello> //Hello.vue <template> <slot name="hi">냉무</slot> //첫번째 자식 <h1>{{ msg }}</h1> <slot name="bye" /> //두번째 자식 <slot></slot> </template>
  • 범위를 가지는 slot
    • slot에 값을 부여할 수 있고, 해당 값을 다시 가져올 수 있다
    • //App.vue <template> <Hello> <template #default="slotProps"> //name 속성없는 default slot //slotProps.noname으로 123을 받아올 수 있음 <h3>{{ slotProps.noname }}</h3> </template> </Hello> </template> //Hello.vue <template> <slot :noname="123"> //속성이름이 noname, 값은 123 냉무 </slot> <h1>{{ msg }}</h1> </template>
  • slot의 이름을 동적으로 제어할 수 있다
    • // App.vue <template> <Hello> <template #[slotName]> <h3>kkk</h3> </template> </Hello> </template> <script> ... data() { return { slotName: 'abc' } }, </scipt> //Hello.vue <template> <slot name="abc"> 냉무 </slot> </template>
 

동적 컴포넌트

<component :is=”데이터” /> : 컴포넌트 이름을 동적으로 할당
//App.vue <template> <component :is="componentName" /> </template> .. data() { return { componentName: 'Hello' } },
  • keep-alive로 component를 감싸주면, 컴포넌트를 캐싱해서 다른 이름으로 컴포넌트가 교체되어도 unmount되지 않는다
    • <keep-alive> <template> <component :is="componentName" /> </template> </keep-alive>
      ⇒ 자주 토글되는 경우에만 쓰는 것이 좋다.