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

+ Recent posts