[Vue]4. Component / Props / custom event

Ming·2023년 10월 17일

Vue

목록 보기
4/10

업데이트

컴포넌트.vue 이름을 2단어 이상으로 작명하지 않으면 에러가 남
(DiscountBanner.vue 2단어 식으로 이름지어야 한다!)
👀싫으면 package.json파일 -> rules"vue/multi-word-component-names": "off" 코드 추가할것
(미리보기 껐다가 다시 띄우면 됨)

"rules": {
   "vue/multi-word-component-names": "off"
} 

Component

HTMl이 너무 길때 2 단어로 축약할 수 있는 문법.

🤫복잡해 보이는데 굳이 왜 쓸까?
✔️ 코드 정리가 편하다.
✔️ HTMl 재사용이 쉬워진다.
✔️ 라우터로 페이지 구분하고 싶으면 하나의 페이지는 하나의 컴포넌트로 만드는게 좋다.

만드는 법

vue 파일을 만든 후 축약할 HTML을 넣는다.
❗️형식대로 만들어야 한다.

<template>
  // 축약할 HTML
</template>

<script>
export default {
  name : '작명', // 디버깅할때 쓰는 이름
  data() {
  	return { // 넣을 data }
  },
}
</script>
<style>
  // 넣을 style
</style>

사용하는 법

  1. component 파일을 App.vue파일에서 import 해서 불러온다.
  2. <script> - components에 저장해 사용한다.
// [ ModalRoom.vue (컴포넌트 파일) ]

<template>
  <div class="black-bg" v-if="모달창 == true">
    <div class="white-bg">
      <h4>{{원룸들[누른거].title}}</h4>
      <p>{{원룸들[누른거].content}}</p>
      <img :src= "원룸들[누른거].image" class="roomImg">
      <p>{{ 원룸들[누른거].price }}만원</p>
      <button v-on:click="모달창=false">닫기</button>
    </div>
  </div>
</template>

<script>
export default {
  name:'ModalRoom'
}
</script>

<style>
</style>
// [ App.vue ]

<template>
	<Modol/> // 3. 사용하기
</template>

<script>
import Modol from './Modal.vue'; // 1. 불러오기

export default {
  name: "App",
  data() {},
  methods: {},
  components: {
    Modol : Modol // 2. 저장하기
  },
};
</script>

해서 사용하면 된다!
🤫 근데 잘 될거같은데 되지 않는다...
✔️ 데이터바인딩할 때 문제가 생겨서!

<h4>{{원룸들[누른거].title}}</h4>
<p>{{원룸들[누른거].content}}</p>
<img :src= "원룸들[누른거].image" class="roomImg">
<p>{{ 원룸들[누른거].price }}만원</p>

{{원룸들}} 을 데이터바인딩 했는데 Model.vue 파일에는 해당하는 데이터가 없기 때문이다.
(데이터바인딩하려면 데이터가 밑에 있어야 한다.)
🤫 그럼 데이터를 넣어주면 될까?
✔️ 만약 데이터를 수정해야하면 복사본들 다 찾아서 이케저케...... 안된다!!
👉 부모가 가진 데이터를 props로 전달해서 써야한다!


Props

하위 컴포넌트로 데이터를 전송하는 문법

👀부모 컴포넌트 / 자식 컴포넌트란
App.vue안에 Abc.vue를 집어 넣어 쓰고 있다고 가정할때
App.vue = 상위|부모 컴포넌트 / Abc.vue = 하위/자식 컴포넌트 라고 비유해 부른다.

쓰는법

  1. 보내고 - 2. 등록하고- 3. 쓰면 된다(^_^){헤헤ㅋ)

App.vue에 있는 데이터를 Abc.vue / Def.vue 에 보낸다고 가정해보자

1. 보내기

부모 컴포넌트에서 데이터바인딩 문법(:)을 쓰면 데이터를 보낼 수 있다.
<자식컴포넌트 v-bind:작명="데이터명"> / <자식컴포넌트 :작명="데이터명">
:은 데이터바인딩 또는 props 전송이다.

Props 보내는 여러가지 방법

Obj = {name : 'kim', age : 20}

<A :데이터이름="[1,2,3]" /> // 배열을 한번에 보내기
<A :데이터이름="{ name:kim, age:20 }" /> // 오브젝트를 보내기
<A :데이터이름="obj.name" :데이터이름="obj.age"/> // 오브젝트를 하나씩 보내기
<A :데이터이름="obj"/> // 오브젝트를 한번에 보내기 <-(:데이터이름=:"오브젝트명")
<A :데이터이름="100" /> // 숫자 보내기
<A 데이터이름="안녕" /> // :을 붙이지 않으면 문자 보내기  
//[ App.vue(부모컴포넌트) ]

<template>
  <div>
    <Abc v-bind:원룸="원룸들" :num="num"/>
    // Abc 컴포넌트에 "원룸들"이라는 데이터를 "원룸"이라는 이름으로 전달!
    // 작명은 데이터명과 달라도, 같아도 상관없다
  </div>
</template>

2. 등록하기

자식 컴포넌트는 데이터를 받으면 <script>- props로 등록한다.
props:{데이터이름:자료형}
자료형은 Arraym, Object, String, Number, Boolean 등

//[ Abc.vue(자식컴포넌트) ]

<script>
  export default {
    name : 'Abc',
    props : {
      원룸 : Array,
      num: Number,
    }
  }
</script>

3. 사용하기

props 등록한 것들은 HTML안에서 데이터바인딩으로 자유롭게 사용가능하다.
단, props는 그냥 받아서 사용만 하는 read-only 데이터처럼 취급하셔야지 수정하면 에러난다.

🤫 그냥 자식컴포넌트에 쓰는 데이터는 자식컴포넌트 데이터보관함에 저장하면 안되나?
✔️ 데이터를 만들 때 원칙이 있다.
"데이터를 사용하는 컴포넌트들 중 최상위 컴포넌트에다가 데이터를 만들어놔야함"
데이터는 위로 전송도 가능한데 복잡하고 추적이 어렵다ㅠㅡ)

🤫 그럼 부모 데이터를 바꾸고 싶을때는 어떡해...?
✔️ custom event 문법을 사용해 부모에게 데이터를 바꿔주라고 전달하자!


custom event

부모 컴포넌트에 있는 데이터를 변경하고 싶을때 요청할 수 있는 방법
자식 컴포넌트가 요청하면 부모가 받아 수정할 수 있다.
$emit('작명', 전달할자료)

부모 컴포넌트에게 자료 보내기

$emit('작명', 전달할자료) 로 요청할 수 있다.
= 작명한 이름으로 커스텀 이벤트 전송!

요청한 커스텀 이벤트 저장하기

@작명="바꿔야할 데이터= 내용"; 데이터 = $event
수정해야할 부분에 커스텀 이벤트명, 바꿔야 할 데이터를 저장한다.
전달할자료는 $event라는 변수 안에 담겨서 온다.

모달창 열기 기능 만들기

//[ Card.vue(자식컴포넌트) ]

<template>
  <div>
    <img :src= "원룸들.image" class="roomImg">
    <h4 v-on:click="$emit('openModal',원룸들.id)">{{ 원룸들.title }}</h4>
	// click할 때마다 openModal 이라는 이벤트명, 데이터 전송
    <p>{{ 원룸들.price }}만원</p>
  </div>
</template>
//[ App.vue(부모컴포넌트) ]

<template>
    <CardRoom @openModal="모달창=true; 누른거=$event" v-bind:원룸들="원룸들[idx]" v-for="(ele,idx) in 원룸들" :key="idx"/>
 // openModal 이벤트명이 실행되면 모달창 데이터는 true값으로 바꾸고,
 // 누른거 라는 이벤트의 값은 보낸 원룸들.id 값으로 바꿔줘!
</template>

🤫 근데 쭉 쓰니까 너무 길어졌어...
✔️ 함수에 담아서 전달해도 된다! 대신 this.$emit()이라고 작성해야 한다!

//[ Card.vue(자식컴포넌트) ]

<template>
  <div>
     <h4 v-on:click="send">{{ 원룸들.title }}</h4>
  </div>
</template>

<script>
export default {
  name:'CardRoom',
  props:{
    원룸들:Object,
  },
  methods:{
    send(){
      this.$emit('openModal', this.원룸들.id )
    }
  }
}
</script>

0개의 댓글