[프론트엔드_개발] props와 event

혯승·2023년 5월 11일
0

프론트엔드_개발

목록 보기
3/9
post-thumbnail

props와 event

💻vue_app21 프로젝트

Single Page App

Vue 앱 프로젝트는 index.html 페이지 하나를 생성하는 프로젝트

  • Single Page App : html 페이지 하나에 앱의 기능을 전부 구현한 프론트엔드 앱

javascript로 구현한 기능은 다른 페이지로 넘어갈 때, 전 페이지에서 실행 중이던 javascript 코드를 모두 종료하고 새로운 페이지의 javascript 코드가 새로 시작
➡️ 새로고침하면, 실행 중이던 javascript 코드는 모두 초기화(종료 후 재시작)

🧐Virtual DOM

  • DOM : Documnet Object Model, html 태그 객체(c++)
  • Virtual DOM : javascript 라이브러리에 구현된 태그 객체(javascript)

<template> 부분은 표준 html 태그가 아니라 Virtual DOM 객체

  • Virtual DOM 태그 사이 여백
    표준 html 태그에서는, 태그와 태그 사이의 공백 문자들이 공백 하나로 웹브라우저에 출력 ▶︎ 태그들 사이의 작은 여백 역할

<template> 부분에서는, 태그와 태그 사이의 공백문자들이 전부 제거
작은 여백이 전혀 없으므로 margin 값이 필요

  • 랜더링 과정
    (1) 변경된 데이터를 반영해서 Virtual DOM 웹페이지를 새로 만듦
    (2) 직전 화면을 그릴 때 만든 Virtual DOM 웹페이지와 새로 만든 Virtual DOM 웹페이지와 비교
    (3) 그 차이를 웹브라우저 DOM에 반영

1) MyCounter1 컴포넌트

MyCounter1.vue 생성

src/MyCounter1.vue

<template>
  <div>
    <h2>{{ title }} - <small>{{ description }}</small></h2>
    <input type="number" v-model="counter" />
    <button type="button" @click="counter++"> ++ </button>
    <button type="button" @click="counter--"> -- </button>
  </div>
</template>

<script>
export default {
  name: "MyCounter1",
  props: [ "title", "description" ],
  data() {
    return { counter: 0 };
  }
}
</script>

<style scoped>
  div { border: 1px solid gray; padding: 0 20px 20px 20px; margin-top: 10px; }
  input { padding: 5px; margin-right: 5px; }
  button { padding: 0.4em 1em; margin-right: 5px; }
</style>

v-on: == @

props: [ "title", "description" ]

부모 컴포넌트로부터 자식 컴포넌트로 전달되는 값

<h2>{{ title }} - <small>{{ description }}</small></h2>

이 부분에 부모 컴포넌트로부터 전달 받은 값이 출력된다.(title props, description props)

App.vue 수정

src/App.vue

<template>
  <div id="app">
    <h1>MyCounter1</h1>
    <MyCounter1 title="카운터" description="첫째 컴포넌트" />
    <MyCounter1 title="카운터" description="둘째 컴포넌트" />
  </div>
</template>

<script>
import MyCounter1 from './MyCounter1.vue'

export default {
  name: "App",
  components: { MyCounter1  }
}
</script>

<style scoped>
div#app { padding: 0 30px 30px 30px; margin: 30px auto; max-width: 400px;
      border: 1px solid #ccc; box-shadow: 3px 3px 3px #aaa; }
</style>
<MyCounter1 title="카운터" description="첫째 컴포넌트" />
<MyCounter1 title="카운터" description="둘째 컴포넌트" />

MyCounter1 컴포넌트의 title props, description props으로 전달


## props ### props 선언 방법 - 배열 - props : 부모 컴포넌트로부터 자식 컴포넌트로 전달되는 값
  • 문자열 배열 형태
    export default {
      name: "Counter1",
      props: [ "title", "description" ],
    }
  • props 값 전달 : 부모 컴포넌트에서 전달
    <MyCounter1  title="카운터1" description="첫째 컴포넌트" />

➡️ props 값은 전달하지 않아도 에러X, props값은 undefined가 됨

props 선언 방법 - 객체 형태

  • 객체 형태
props: {
  title: String, 
  description: String
}

➡️ props 타입은 String, Number, Boolean, Array, Object, Function 등이 가능

  • props 값 전달 v-bind
    아래와 같은 방법으로 props 값을 전달하면 오류 ▶︎ 태그의 애트리뷰트 값은 전부 string으로 해석되기 때문
    	```vue
    ``` 따라서 v-bind: 접두어를 붙여야함 ```vue ```

➡️ props 값이 문자열이 아니라면 v-bind: 접두어 필수

  • required : true
    가 선언된 props는 값 전달이 필수, 전달하지 않을 경우 에러 발생

    props: {
      title: { type: String, required: true },
      description: { type: String, default: "안녕하세요" }
    }

2) MyCounter2 컴포넌트

MyCounter2.vue 생성

src/MyCounter2.vue

<template>
  <div :style="{ backgroundColor: color }">
    <h2>{{ title }} - <small>{{ description }}</small></h2>
    <input type="number" v-model="counter" />
    <button type="button" @click="counter++"> ++ </button>
    <button type="button" @click="counter--"> -- </button>
    <button type="button" @click="$emit('send', counter)"> 전달 </button>
  </div>
</template>

<script>
export default {
  name: "MyCounter1",
  props: {
    title: { type: String, required: true },
    description: { type: String, default: "안녕하세요" },
    color: { type: String, default: "#fff" }
  },
  data: function() {
    return { counter: 0 };
  }
}
</script>

<style scoped>
  div { border: 1px solid gray; padding: 0 20px 20px 20px; margin-top: 10px; }
  input { padding: 5px; margin-right: 5px; }
  button { padding: 0.4em 1em; margin-right: 5px; }
</style>
<button type="button" @click="$emit('send', counter)"> 전달 </button>

이 버튼이 클릭되면 부모에개 'send' 이벤트를 전달, 이벤트의 파라미터로 counter 값 전달

v-bind:style

<template> 영역의 태그에 css 서식을 적용하려면 v-bind:style 애트리뷰트를 사용해야함

⭐️ v-bind: == : , v-on: == @

$emit 메소드

: 자식 컴포넌트로부터 부모 컴포넌트에게 이벤트 전달
이밴트 이름은 'send'이고, 이벤트 파라미터 값으로 counter 값 전달
이벤트 파라미터의 수는 0개 이상

➡️ 이벤트를 전달하는 이유는, 자식 컴포넌트로부터 부모 컴포넌트에게 어떤 시점(event)을 알리거나, 어떤 값을 전달하기 위해

만일 $emit() 메소드를 method 본문에서 호출한다면, this.$emit() 형식이어야 함(태그 부분은 this 생략)

  • 이벤트 전달 받기
<MyCounter2 title="카운터2"  v-on:send="showValue" />

v-on:이벤트명="메소드"
MyCounter2 컴포넌트에서 send 이벤트를 전달하면, 부모 컴포넌트의 showValue 메소드가 호출
MyCoutner2 컴포넌트가 전달한 이벤트 파라미터 값은, showValue 메소드의 파라미터로 전달

App.vue 수정

src/App.vue

<template>
  <div id="app">
    <h1>MyCounter2</h1>
    <MyCounter2 title="카운터2" description="첫째 컴포넌트" color="#ffb"  v-on:send="showValue" />
    <MyCounter2 title="카운터2" color="#afa"  v-on:send="showValue" />
  </div>
</template>

<script>
import MyCounter2 from './MyCounter2.vue'

export default {
  name: "App",
  methods: {
    showValue(value) {
      alert(value);
    }
  },
  components: { MyCounter2 }
}
</script>

<style scoped>
div#app { padding: 0 30px 30px 30px; margin: 30px auto; max-width: 400px;
      border: 1px solid #ccc; box-shadow: 3px 3px 3px #aaa; }
</style>

0개의 댓글

관련 채용 정보