Vue.js 3 & NodeJS/사내교육 - 점심 메뉴

[7] Frontend 개발 - 읽기 뷰 (ReadView), 수정, 삭제 생성

carrotweb 2026. 8. 3. 16:29
728x90
반응형

읽기 뷰 (ReadView) 생성

1. src\views\LunchMenu에서 LunchMenuReadView.vue 파일을 생성합니다.

<template>
    <div>점심 메뉴 보기</div>
</template>

<script>
export default {
    setup() {
    }
}
</script>

 

2. src\router\index.js에서 LunchMenuReadView.vue를 import하고 children(칠드런)에 추가합니다.

:
import LunchMenuReadView from '@/views/LunchMenu/LunchMenuReadView.vue'

const routes = [
  :
  {
    path: '/lunchmenu',
    component: LunchMenuView,
    children : [
      :
      {
        path: ':seq',
        name: 'lunchmenuread',
        component: LunchMenuReadView
      }
    ]
  }
]
:

:seq는 웹 경로에 있는 파라미터입니다.

파라미터는 콜론 :으로 표시됩니다.

/lunchmenu/1

웹 경로에 있는 파라미터(동적 세그먼트)를 사용한 동적으로 라우팅하게 합니다. → 파라미터를 사용한 동적 라우트 매칭 (https://router.vuejs.kr/guide/essentials/dynamic-matching.html)

 

2. src\views\LunchMenu\LunchMenuListView.vue 파일에서 <li>가 클릭되면 함수(핸들러)가 호출되도록 @click(v-on:click)를 사용합니다.

<template>
    <div>점심 메뉴 리스트</div>
    <div class="buttons">
        <div class="right">
            <router-link :to="{ name: 'lunchmenuadd' }" class="button blue">
                <span>등록</span>
            </router-link>
        </div>
    </div>
    <div v-if="lunchMenuList.length == 0">
        점심 메뉴가 없습니다.
    </div>
    <div v-else>
        점심 메뉴가 {{ lunchMenuList.length }} 개 있습니다.
        <ul class="menu-list">
            <li class="menu-item" v-for="(lunchMenuItem, index) in lunchMenuList" :key="index"
                @click="gotoLunchMenuRead(lunchMenuItem)">{{ lunchMenuItem.menu_name }}
            </li>
        </ul>
    </div>
</template>

 

3. setup()에 <li>가 클릭되면 읽기 뷰 컴포넌트로 이동하기 위해서 라우터 인스턴스를 받고 router.push() 함수를 사용합니다. → Router 프로그램 방식

<script>
:
import { useRouter } from 'vue-router';

export default {
    name : 'LunchMenuListView',
    setup() {
        const router = useRouter();
        :
        function gotoLunchMenuRead(lunchMenuItem) {
            router.push({name : 'lunchmenuread', params : {seq : lunchMenuItem.seq}});
        }

        return {
            :
            gotoLunchMenuRead
        }
    },
}
</script>

name에는 route(라우트)를 생성할 때 부여한 이름을 사용합니다.

params에는 웹 경로에 있는 파라미터(콜론(:)으로 표시)인 :seq에 전달할 lunchMenuItem의 seq입니다.

 

router.push() 함수를 사용하면 routers에 등록되어 있는 router를 찾아 이동하게 됩니다.
(https://router.vuejs.kr/guide/essentials/navigation.html#Navigate-to-a-different-location)

 

4. 웹 브라우저에서 확인하기 (http://127.0.0.1:8080/lunchmenu/1)

 

5. src\views\LunchMenu\LunchMenuListView.vue 파일에서 <li>에 있는 점심 메뉴 명을 클릭되면 이동하도록 router-link를 추가합니다. → Router 선언적 방식

<template>
    <div>점심 메뉴 리스트</div>
    <div class="buttons">
        <div class="right">
            <router-link :to="{ name: 'lunchmenuadd' }" class="button blue">
                <span>등록</span>
            </router-link>
        </div>
    </div>
    <div v-if="lunchMenuList.length == 0">
        점심 메뉴가 없습니다.
    </div>
    <div v-else>
        점심 메뉴가 {{ lunchMenuList.length }} 개 있습니다.
        <ul class="menu-list">
            <li class="menu-item" v-for="(lunchMenuItem, index) in lunchMenuList" :key="index">
                <router-link :to="{name : 'lunchmenuread', params : {seq: lunchMenuItem.seq}}">
                    {{ lunchMenuItem.menu_name }}
                </router-link>
            </li>
        </ul>
    </div>
</template>

name에는 route(라우트)를 생성할 때 부여한 이름을 사용합니다.

params에는 웹 경로에 있는 파라미터(콜론(:)으로 표시)인 :seq에 전달할 lunchMenuItem의 seq입니다.

 

6. 웹 브라우저에서 확인하기 (http://127.0.0.1:8080/lunchmenu/)

 

LunchMenuListView.vue 파일에 있는 <style>에 menu-item를 추가했습니다.

<style>
.menu-item a {
    color: white;
}
</style>

 

7. src\views\LunchMenu\LunchMenuReadView.vue 파일을 수정합니다.

<template>
    <div>점심 메뉴 보기 {{ $route.params.seq }}</div>
    {{ lunchMenuItem.menu_name }}
</template>

<script>
import { ref } from 'vue';
import { useRoute } from 'vue-router'
import axios from 'axios';

export default {
    setup() {
        const route = useRoute();

        const lunchMenuItem = ref({});

        function getLunchMenuItem() {
            axios.get("http://127.0.0.1:9000/api/v1/lunchmenus/" + route.params.seq).then((res) => {
                console.log(res);
                lunchMenuItem.value = res.data.data;
            }).catch((err) => {
                console.log(err);
            });
        }

        return {
            lunchMenuItem,
            getLunchMenuItem
        }
    },
    mounted() {
        this.getLunchMenuItem();
    }
}
</script>

현재 라우트는 템플릿에서 $route로 접근할 수 있습니다.

라우트가 매칭되면 파라미터의 값은 컴포넌트에서 route.params로 노출됩니다

/lunchmenu/:seq → /lunchmenu/1

 

useRoute() 함수는 현재 라우트를 반환 합니다.

 

8. 웹 브라우저에서 확인하기 (http://127.0.0.1:8080/lunchmenu/1)

 

9. 목록 버튼을 추가하고 버튼이 클릭되면 점심 메뉴 리스트로 이동하도록 함수를 생성하고 리턴합니다.

<template>
    :
    <div class="buttons">
        <div class="right">
            <button class="button" @click="listClick">목록</button>
        </div>
    </div>
</template>

<script>
import { useRoute, useRouter } from 'vue-router'

export default {
    setup() {
        :
        const router = useRouter();
        :
        function listClick() {
            router.back();
        }

        return {
            :
            listClick
        }
    },
    :
}
</script>

 

10. 웹 브라우저에서 확인하기 (http://127.0.0.1:8080/lunchmenu/1)

 

 

수정 생성 – 등록 뷰 (AddView) 재사용

1. src\router\index.js에서 수정 라우트를 children(칠드런)에 추가합니다.

:
const routes = [
  :
  {
    path: '/lunchmenu',
    component: LunchMenuView,
    children : [
      :
      {
        path: ':seq/edit',
        name: 'lunchmenuedit',
        component: LunchMenuAddView
       }
    ]
  }
]
:

/lunchmenu/1/edit

컴포넌트는 등록 컴포넌트를 사용합니다.

 

2. 수정 버튼을 추가하고 버튼이 클릭되면 점심 메뉴 수정으로 이동하도록 함수를 생성하고 리턴합니다.

<template>
    :
    <div class="buttons">
        <div class="left">
            <button class="button" @click="editClick">수정</button>
        </div>
        :
    </div>
</template>

<script>
:
export default {
    setup() {
        :
        function editClick() {
            var result = confirm("수정하시겠습니까?");
            if (result) {
                router.push({name : 'lunchmenuedit', params : {seq : route.params.seq}});
            }
        }
    return {
            :
            editClick
        }
    },
    :
    
    }
</script>

<style>
.buttons > div.left {
    position:absolute;
    height:32px;
    left:0;
}
</style>

 

3. 웹 브라우저에서 확인하기 (http://127.0.0.1:8080/lunchmenu/1)

 

4. src\views\LunchMenu\LunchMenuAddView.vue 파일에서 $route.name으로 등록인지 수정인지 확인하여 메지지를 변경하고 버튼을 교체합니다.

<template>
    <div>점심 메뉴 {{ $route.name == 'lunchmenuedit' ? '수정' : '등록' }}</div>
    <form class="lunchMenuForm">
        <div>
            <label for="lunchMenuName">점심 메뉴 명 :</label>
            <input type="text" id="lunchMenuName" 
                placeholder="점심 메뉴 명을 입력하세요."
                v-model="lunchMenuName"/>
        </div>
    </form>
    <div class="buttons">
        <div class="right">
            <button v-if="$route.name == 'lunchmenuedit'" class="button blue" @click="editClick">수정</button>
            <button v-else class="button blue" @click="addClick">등록</button>
            <button class="button" @click="cancelClick">취소</button>
        </div>
    </div>
</template>

 

수정 버튼이 클릭되면 axios의 put() 함수를 사용하여 APIServer에 점심 메뉴가 수정되도록 합니다.

<script>
import { reactive, toRefs, onMounted } from 'vue';
import { useRouter, useRoute } from 'vue-router';
:

export default {
    setup() {
        :
        const route = useRoute();
        :
        function editClick() {
            if (state.lunchMenuName == "") {
                alert("점심 메뉴 명을 입력하세요.");
                lunchMenuNameInput.value.focus();
                return;
            }
            var result = confirm("수정하시겠습니까?");
            if (result) {
                const lunchMenuItem = { menuName : state.lunchMenuName };
                axios.put("http://127.0.0.1:9000/api/v1/lunchmenus/"+ route.params.seq, lunchMenuItem).then(() => {
                    router.replace({name : 'lunchmenuread', params : {seq: route.params.seq}};
                }).catch((err) => {
                    console.log(err);
                });
            }
        }

 

onMounted()에 콜백으로 getLunchMenuItem() 함수를 등록하여 APIServer에서 점심 메뉴를 가져오도록 합니다.

        function getLunchMenuItem() {
            axios.get("http://127.0.0.1:9000/api/v1/lunchmenus/" + route.params.seq).then((res) => {
                state.lunchMenuName = res.data.data.menu_name;
            }).catch((err) => {
                console.log(err);
            });
        }
        :
        onMounted(()=>{
            if (route.name == "lunchmenuedit") {
                getLunchMenuItem();
            }
        });
        return {
            :
            editClick
        }
    }
}

 

5. 웹 브라우저에서 확인하기 (http://127.0.0.1:8080/lunchmenu/1/edit)

 

6. 마운트 된 후 점심 메뉴 명 입력란으로 포커스가 가기 위해서 <template>를 참조하여 처리해야 합니다.

<template>
    :
            <input type="text" id="lunchMenuName" placeholder="점심 메뉴 명을 입력하세요."
                v-model="lunchMenuName"
                ref="lunchMenuNameInput"/>
    :
</template>

<script>
import { …, ref } from 'vue';

export default {
    setup() {
        :
        const lunchMenuNameInput = ref(null);
        :
        onMounted(()=>{
            :
            lunchMenuNameInput.value.focus();
        });
        
        return {
            :
            lunchMenuNameInput
        }
    }
}
</script>

DOM에 접근하기 위해서 ref란 특수 속성을 사용합니다.

ref 속성 값과 일치하는 이름으로 ref를 선언해야 합니다.

초기값은 null 이어야 합니다. 마운트 된 후 DOM객체로 변경됩니다.

focus() 함수로 input에 포커스가 이동됩니다.

 

템플릿 참조에 대한 설명을 참고하세요. (https://ko.vuejs.org/guide/essentials/template-refs.html)

 

 

삭제 – 읽기 뷰 (ReadView) 사용

1. 삭제 버튼을 추가하고 버튼이 클릭되면 점심 메뉴가 삭제되도록 함수를 생성하고 리턴합니다.

<template>
    :
    <div class="buttons">
        <div class="left">
            <button class="button" @click="editClick">수정</button>
            <button class="button" @click="deleteClick">삭제</button>
        </div>
        :
    </div>
</template>

<script>
:

export default {
    setup() {
        :
        async function deleteClick() {
            var result = confirm("삭제하시겠습니까?");
            if (result) {
                try {
                    const res = await axios.delete("http://127.0.0.1:9000/api/v1/lunchmenus/" + route.params.seq);
                    if (res.data.code == 200) {
                        alert("삭제되었습니다.");
                        router.push({name : 'lunchmenulist’});
                    } else {
                        alert("삭제되지 않았습니다.");
                    }
                } catch(err) {
                    console.log(err);
                }
            }
        }

        return {
            :
            deleteClick
        }
    },
    :
}
</script>

 

2. 웹 브라우저에서 확인하기 (http://127.0.0.1:8080/lunchmenu/4)

 

 

라우터와 현재 라우트에 접근하기

라우터와 현재 라우트에 대한 접근 방법을 참고하세요.
(https://router.vuejs.kr/guide/#Accessing-the-router-and-current-route)

 

변수와 함수 사용

 

 

 

 

728x90
반응형