3장 Data Binding
# 바인딩의 개념
단방향 :
양방향 :
v-bind는 사용해 보았다.
v-bind:to = " " --> v-bind 생략가능
v-if : 해당 요소를 포함을 시킬 것인지
v-show : 해당 요소를 보여줄 것인지 보여주지 않을 것인지
v-for는 반드시 v-bind:key와 같이 쓰인다.
실습해보자.
하기전에 라우터 파일 정리.
앞으로 챕터 별로 라우터 등록하는 방법을 알아보자.
1. 라우터에 새로운 파일 생성. (Ch02ComponentRouting.js)
기존 index.js에 있던 코드를 옮긴다. (2장내용 분리)
const routes = [
{
path: '/Ch02ComponentRouting/Exam01View',
name: 'Exam01View',
component: () => import(/* webpackChunkName: "Ch02ComponentRouting" */ '@/views/Ch02ComponentRouting/Exam01View')
},
{
path: '/Ch02ComponentRouting/Exam02View',
component: () => import(/* webpackChunkName: "Ch02ComponentRouting" */ '@/views/Ch02ComponentRouting/Exam01View')
},
{
path: '/Ch02ComponentRouting/Exam03View',
component: () => import(/* webpackChunkName: "Ch02ComponentRouting" */ '@/views/Ch02ComponentRouting/Exam03View')
},
{
path: '/Ch02ComponentRouting/Exam04View',
component: () => import(/* webpackChunkName: "Ch02ComponentRouting" */ '@/views/Ch02ComponentRouting/Exam04View')
},
{
path: '/Ch02ComponentRouting/Exam05View',
component: () => import(/* webpackChunkName: "Ch02ComponentRouting" */ '@/views/Ch02ComponentRouting/Exam04View'),
redirect: '/Ch02ComponentRouting/Exam05View/UIComponentA',
children: [
{
path: "UIComponentA", // "/Ch02ComponentRouting/Exam05View/UIComponentA"
component: () => import(/* webpackChunkName: "Ch02ComponentRouting" */ '@/components/Ch02ComponentRouting/UIComponentA.vue')
},
{
path: "UIComponentB", // "/Ch02ComponentRouting/Exam05View/UIComponentB"
component: () => import(/* webpackChunkName: "Ch02ComponentRouting" */ '@/components/Ch02ComponentRouting/UIComponentB.vue')
},
{
path: "UIComponentC", // "/Ch02ComponentRouting/Exam05View/UIComponentC"
component: () => import(/* webpackChunkName: "Ch02ComponentRouting" */ '@/components/Ch02ComponentRouting/UIComponentC.vue')
}
]
},
{
path: '/Ch02ComponentRouting/Exam06View',
component: () => import(/* webpackChunkName: "Ch02ComponentRouting" */ '@/views/Ch02ComponentRouting/Exam06View')
},
{
path: '/Ch02ComponentRouting/Exam07View/:kind?/:color?',
component: () => import(/* webpackChunkName: "Ch02ComponentRouting" */ '@/views/Ch02ComponentRouting/Exam07View')
}
];
export default routes;
2. 기존 index.js에 이 내용을 어떻게 추가할 것인지?
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import Ch02ComponentRouting from './Ch02ComponentRouting' // routes를 가져온다
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
...Ch02ComponentRouting // 구조분해할당 방식
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL), //히스토리 (뒤로가기 가능)
routes
})
export default router
앞으로 이런식으로 새로운 챕터를 추가하자.
--
1. views 폴더 밑 Ch03DataBinding 폴더 추가 - Exam01Expressions.vue 파일 생성
2. router에 Ch03DataBinding.js 추가
const routes = [
{
path: "/Ch03DataBinding/Exam01Expressions",
component: () => import(/* webpackChunkName: "Ch03DataBinding" */ '@/views/Ch03DataBinding/Exam01Expressions.vue')
}
];
export default routes;
3. router의 index.js에 구조분해할당 방식으로 코드 추가
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
...Ch02ComponentRouting, // 구조분해할당 방식
...Ch03DataBinding
]
4. component의 AppMenu.vue에 3장 리스트 코드 추가
<template>
<div class="accordion" id="accordionExample">
<!-- 1 --------------------------------------------------------->
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button fw-bold" type="button" data-bs-toggle="collapse"
data-bs-target="#collapse1" aria-expanded="true" aria-controls="collapse1">
Ch01. Vue 시작
</button>
</h2>
<div id="collapse1" class="accordion-collapse" data-bs-parent="#accordionExample">
<div class="accordion-body">
<ul class="nav flex-column">
<li class="nav-item">
<RouterLink to="/" class="nav-link">Home</RouterLink>
</li>
</ul>
</div>
</div>
</div>
<!-- 2 --------------------------------------------------------->
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button fw-bold" type="button" data-bs-toggle="collapse"
data-bs-target="#collapse2" aria-expanded="true" aria-controls="collapse2">
Ch02. Component & Routing
</button>
</h2>
<div id="collapse2" class="accordion-collapse" data-bs-parent="#accordionExample">
<div class="accordion-body">
<ul class="nav flex-column">
<li class="nav-item">
<RouterLink to="/Ch02ComponentRouting/Exam01View" class="nav-link">
Exam01View : 뷰 컴포넌트(싱글파일)</RouterLink>
</li>
<li class="nav-item">
<RouterLink to="/Ch02ComponentRouting/Exam02View" class="nav-link">
Exam02View : 뷰 컴포넌트(폴더)</RouterLink>
</li>
<li class="nav-item">
<RouterLink to="/Ch02ComponentRouting/Exam03View" class="nav-link">
Exam03View : UI 컴포넌트(공용 및 로컬)</RouterLink>
</li>
<li class="nav-item">
<RouterLink to="/Ch02ComponentRouting/Exam04View" class="nav-link">
Exam04View : 뷰 이동</RouterLink>
</li>
<li class="nav-item">
<RouterLink to="/Ch02ComponentRouting/Exam05View" class="nav-link">
Exam05View : 중첩된 라우트</RouterLink>
</li>
<li class="nav-item">
<RouterLink to="/Ch02ComponentRouting/Exam06View" class="nav-link">
Exam06View : URL 데이터 전달</RouterLink>
</li>
</ul>
</div>
</div>
</div>
<!-- 3 --------------------------------------------------------->
<div class="accordion-item">
<h2 class="accordion-header">
<button class="accordion-button fw-bold" type="button" data-bs-toggle="collapse"
data-bs-target="#collapse3" aria-expanded="true" aria-controls="collapse3">
Ch03. Data Binding
</button>
</h2>
<div id="collapse3" class="accordion-collapse" data-bs-parent="#accordionExample">
<div class="accordion-body">
<ul class="nav flex-column">
<li class="nav-item">
<RouterLink to="/Ch03DataBinding/Exam01Expressions" class="nav-link">
Exam01Expressions : 표현식</RouterLink>
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script setup>
</script>
<style scoped></style>
# 일반 데이터 : 일시적인 데이터
값이 변경되어도 컴포넌트가 리렌더링 X
# Exam01Expressions.vue
<template>
<div class="card">
<div class="card-header">Exam01Expressions</div>
<div class="card-body">
<p>번호: {{ no }}</p>
<p>이름: {{ name + "-" + company }}</p>
<p>설명: {{ detail.info }}</p>
<p>상태: {{ detail.sale ? "판매" : "품절" }}</p>
<p>가격(변수): {{ price }}</p>
<!-- 메소드를 호출하여 리턴값을 보이기 -->
<p>가격(함수): {{ getPrice() }}</p>
<button class="btn btn-outline-info btn-sm" @click="changeVarValue()">변수값 변경</button>
</div>
</div>
</template>
<script setup>
let no = 1;
let name = "미니백";
let company = "클레인";
let detail = {
info: "시그너츠 Ceycle Lock 마그네틱 클로저가 특징입니다.",
sale: false
};
let price = 300000;
function getPrice(){
return price;
}
function changeVarValue() {
no = 2;
name = "백팩";
}
</script>
<style scoped>
</style>
버튼을 눌러도 값이 변경되지 않는다.
# 상태 데이터 : 이전 데이터를 지속적으로 유지
상태가 바뀌면 자동적으로 재 바인딩이 됨
위의 코드를 상태 객체로 바꾸어 다시 작성
# Exam02NotState.vue
<template>
<div class="card">
<div class="card-header">Exam02NotState</div>
<div class="card-body">
<p>번호: {{ no }}</p>
<p>이름: {{ name + "-" + company }}</p>
<p>설명: {{ detail.info }}</p>
<p>상태: {{ detail.sale ? "판매" : "품절" }}</p>
<p>가격(변수): {{ price }}</p>
<!-- 메소드를 호출하여 리턴값을 보이기 -->
<p>가격(함수): {{ getPrice() }}</p>
<hr>
<button class="btn btn-info btn-sm"
@click="changeData">일반 변수 값 변경</button>
</div>
</div>
</template>
<script setup>
let no = 1;
let name = "미니백";
let company = "클레인";
let detail = {
info: "시그너츠 Ceycle Lock 마그네틱 클로저가 특징입니다.",
sale: false
};
let price = 300000;
function getPrice() {
return price;
}
function changeData() {
no = 2;
name = "백팩";
}
</script>
<style scoped>
</style>
--
# Exam03State.vue (상태 데이터) 생성하고 연결하여 화면에서 확인
<template>
<div class="card">
<div class="card-header">Exam03State</div>
<div class="card-body">
<p>번호: {{ no }}</p>
<p>이름: {{ name + "-" + company }}</p>
<p>설명: {{ detail.info }}</p>
<p>상태: {{ detail.sale ? "판매" : "품절" }}</p>
<p>가격(변수): {{ price }}</p>
<!-- 메소드를 호출하여 리턴값을 보이기 -->
<p>가격(함수): {{ getPrice() }}</p>
<hr>
<button class="btn btn-info btn-sm"
@click="changeData">상태 변수 값 변경</button>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
let no = ref(1);
let name = ref("미니백");
let company = ref("클레인");
let detail = ref({
info: "시그너츠 Ceycle Lock 마그네틱 클로저가 특징입니다.",
sale: false
});
let price = ref(300000);
function getPrice() {
return price.value; // price 변수의 상태 값을 변경해야 되기 때문에 .value를 붙여준다.
}
// function changeData() {
// no.value++;
// name.value = "파란 미니백";
// company.value = "구찌";
// detail.value.info = "시그너츠 Ceycle Lock 마그네틱 클로저가 별로였습니다."
// detail.value.sale = !detail.value.sale;
// price.value += 1000;
// }
// 이렇게도 표현 가능
function changeData() {
no.value++;
name.value = "백팩";
// (1) detail 상태 객체의 속성 값을 교체하고 싶은 경우 --------------
// detail.value.info = "시그너츠 Cecycle Lock 마그네틱 클로저와 빨간색의 조화가 좋습니다.";
// detail.value.sale = !detail.value.sale;
// (2) detail 상태 객체를 새로 교체하고 싶은 경우 --------------
detail.value = {
info: "시그너츠 Cecycle Lock 마그네틱 클로저와 빨간색의 조화가 좋습니다.",
sale: !detail.value.sale
};
price.value += 1000;
}
</script>
<style scoped>
</style>
상태 변경이 올바르게 되었는지 크롬 개발 툴 설치
개발 도중에만 사용할 수 있다.
앞으로 devtools를 열어놓고 실시간으로 확인해보자.
computed( 람다식 ); 으로 작성 // 람다식은 데이터 가공
리턴값이 있는 함수처럼 보이지만 상태 데이터처럼 사용하면 된다.
일반적인 함수를 이용하는 것보다 계산하는 것에 있어 computed함수를 사용하는 것이 더욱 실용적이다.
1. Ch03DataBinding 폴더 - Exam04ComputedFunBinding.vue 생성
2. router 폴더의 Ch03DataBinding.js routes코드 추가
3. components폴더의 AppMenu.vue에 리스트 추가
# Exam04ComputedFunBinding.vue
<template>
<div class="card">
<div class="card-header">Exam04ComputedFunBinding</div>
<div class="card-body">
<p>이름: {{ name }}</p>
<p>주민번호: {{ getSsn() }}</p>
<!-- computed를 사용한 경우 -->
<p>주민번호: {{ computedSsn }}</p>
<hr>
<button class="btn btn-info btn-sm me-3" @click="changeName">이름 수정</button>
<button class="btn btn-info btn-sm" @click="changeSsn">주민번호 수정</button>
</div>
</div>
</template>
<script setup>
import { ref, computed } from "vue";
// 반응형 속성 선언
const name = ref("홍길동");
const ssn1 = ref("880515");
const ssn2 = ref("1110345");
// 일반함수
//컴포넌트가 리렌더링될 때마다 호출된다.
function getSsn() {
console.log("getSsn() 실행");
const ssn = ssn1.value + "-" + ssn2.value.charAt(0) + "**************";
return ssn;
}
// function getSsn() {
// console.log("getSsn() 실행");
// const ssn = ssn1.value + "-" + ssn2.value.charAt(0) + "******";
// return ssn;
// }
// 계산된 함수
// 컴포넌트가 리렌더링이 되더라도 ssn1과 ssn2의 값이 변경될 때만 호출된다.
// ssn1과 ssn2 값의 변경이 없을 경우엔 호출되지 않는다! ==> getSsn()함수보다 성능면에서 더욱 좋다.
const computedSsn = computed(() => {
console.log("computedSsn() 실행");
const ssn = ssn1.value + "-" + ssn2.value;
return ssn;
});
// 상태 변경 함수
function changeName() {
name.value += "동";
}
// 상태 변경 함수
function changeSsn() {
ssn2.value = parseInt(Math.random() * 10 + 1) + "110345"; // ssn2의 맨 앞의 수만 바뀌게 된다. --> 7자리를 for를 돌려 모두 바꾸기 쉬울까?
//ssn2.value = "1234567"; // 클릭하게 되면 getSsn()함수가 처음만 실행되고 그다음부터는 실행되지 않는다. // 리렌더링이 일어나지 않기 때문
}
// 리렌더링이 될 때마다 실행
// function getSsn() {
// }
</script>
<style scoped></style>
# 확인해보자..
이름 수정을 누르게 되면 이름값에 "동"이 계속적으로 붙게 된다. (리렌더링이 된다는 의미)
리렌더링이 될 때(컴포넌트 화면의 변화가 일어날 때)만 computed함수가 호출된다.
getSsn()함수는 return값이 있을 때 호출된다.
'JAVA' 카테고리의 다른 글
63일차 2024-05-29 (Vue 7일차) (0) | 2024.05.29 |
---|---|
62일차 2024-05-28 (Vue 6일차) (0) | 2024.05.28 |
59일차 2024-05-23 (Vue 3일차) (0) | 2024.05.23 |
58일차 2024-05-22 (Vue 2일차) (0) | 2024.05.22 |
43일 2024-04-26 (0) | 2024.04.26 |