목표 : vue.js로 로그인 기능 만들기

사용 기술: vue.js, vuex, vue-router,axios, vee-validate

 

1. visual studio code로 화면단을 만든다. 

2. api를 연동하여 화면에 표시한다.

3. 주소 api를 사용한다.

4. 카트페이지 30일간 아이템이 들어있게 만든다.

--끝--

순서도

1. 스프링에서 api-swagger를 만든다.

2. api link를 이용하여 데이터를 화면에 보여준다. 

3. 뷰에 api를 이용하여 데이터를 가져온다.

 

스프링에서 api-swagger를 만들어보자!

포트는 (localhost:8088/swagger-ui.html#/)이니 기억하자!

 

 

-- 아이템리스트 가져오기

-- 회원정보 가져오기

-- 마이페이지 정보 가져오기

-- 카트 정보 가져오기

일단 결과물!

 

api 연동해서 데이터 상태 200으로 데이터가 아주 잘 보이죠?

 

소스는 다운 받아서 보세요 :)

api-swagger.zip
0.08MB

 1. 요구분석

  • 먼저 실제 세계에서 어떤 시스템을 구축할 것인지 요구사항 수집
  • 요구사항에 대해 어떤 데이터들이 필요한지 분석

   순서

 -  Mysql ERD 프로그램 만들기 (olidang.tistory.com/95)

 

 

   2. 개념적 설계

  • ER 다이어그램을 통해 요구사항을 개념적으로 표현

  3. 논리적 설계

  • 관계 모델(Relation model)을 통해 개념적 설계를 논리적으로 표현

  4. 물리적 설계

  • 실제 디스크와 같은 물리 저장장치에 데이터를 저장할 수 있도록 표현

  5. 구현

  • 데이터베이스 스키마를 실제 파일로 생성하는 단계

 

1. 배너테이블

2. 카테고리테이블

3. 아이템테이블

4. 마이페이지테이블

5. 회원가입/로그인 테이블

6.카트 테이블

순서도 > 메인페이지 >> 상세페이지 >> 카테고리페이지 >> 회원가입페이지 >> 로그인페이지 >> 마이페이지 >> 카트페이지

참고자료(clicknfunny.com/index.html#none)

 

1. 메인페이지

2. 상세페이지

3. 카테고리페이지

4. 회원가입페이지

5. 로그인페이지

6.마이페이지

7.카트페이지

일반적으로 웹 페이지에서 페이지 이동을 할 때는 사용자가 url을 다 쳐서 이동하지 않습니다.

이 때 화면에서 특정 링크를 클릭해서 페이지를 이동할 수 있게 해줘야 하는데

그게 바로 <router-link> 입니다.

<router-link to="이동할 URL"></router-link>

실제 코드 예시는 다음과 같습니다.

<div> <router-link to="/login"></router-link> </div>

위 코드를 실행하면 화면에서는 <a> 태그로 변형되서 나옵니다.

따라서 <a> 태그를 클릭하면 /login URL로 이동합니다.

<template>
  <div>
    <p v-for="ask in this.$store.state.ask" :key="ask.id">
      <router-link :to="`item/${ask.id}`">{{ ask.title }}</router-link><br>
      <small>
        {{ ask.time_ago }} 
        by 
        <router-link :to="'/user/' + ask.user">{{ ask.user }}</router-link>
      </small>
    </p>
  </div>
</template>

<script>
export default {
  created() {
    this.$store.dispatch('FETCH_ASK')
      .then(() => console.log('success'))
      .catch(() => console.log('fail'));
  }
}
</script>

<style>

</style>

뷰 스토어를 하나 생성하고 나서 ES6 import/export 문법으로 main.js 파일의 인스턴스에 주입합니다.

데이터의 흐름은 Actions -> Mutations -> State 순서임을 알 수 있습니다.

import Vue from 'vue'
import App from './App.vue'
import router from './routes/index.js';
import store from './store/index.js';

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

router-view

브라우저의 주소 창에서 URL이 변경되면, 앞에서 정의한 routes 속성에 따라

해당 컴포넌트가 화면에 뿌려집니다. 이 때 뿌려지는 지점이 템플릿의 <router-view>입니다.

앞에서 정의한 라우팅 옵션 기준으로 /login은 로그인 컴포넌트를 /home은 홈 컴포넌트를 화면에 표시합니다.

<template>
  <div id="app">
    <tool-bar></tool-bar>
    <router-view></router-view>
  </div>
</template>

<script>
import ToolBar from './components/ToolBar.vue';

export default {
  components: {
    ToolBar
  }
}
</script>

<style>
body {
  margin: 0;
}

a {
  color: #34495e;
  text-decoration: none;
}
a:hover {
  color: #42b883;
  text-decoration: underline;
}
a.router-link-active {
  text-decoration: underline;
}
</style>
<template>
  <div id="app">
    <modals-container></modals-container>
    <button @click="open_modal()" type="button">
      팝업창 오픈
    </button>

    <!-- 
    <div v-show="is_show">
      <popup-view></popup-view>
    </div>
    -->
  </div>
</template>

<script>
import PopupView from './popup/Popup';

export default {
  name: "App",
  data: () => {
    return {
      is_show: false
    }
  },
  // mounted() {
  //   this.open_modal();
  // },
  methods: {
    open_popup: function() {
      this.is_show = !this.is_show;
    },
    open_modal() {
      this.$modal.show(PopupView, {
        modal : this.$modal },
        {
          name: 'dynamic-modal',
          width: '754px',
          height: '404px',
          draggable: false,
          resizable: true,
      })
    }
  }
}
</script>

<style>

</style>
<template>
  <div>
      slide-view
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>
<template>
  <div>
    scroll-view
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>

퍼온글(joshua1988.github.io/vue-camp/vue/props.html#props-%EC%86%8D%EC%84%B1-%EC%BD%94%EB%93%9C-%ED%98%95%EC%8B%9D)

 

퍼온글(kr.vuejs.org/v2/api/#created)

Created VS Mounted

많은 경우 중 하나의 예로 들었지만, created와 mounted는 확실히 인지해야한다.

사용에 있어, 하나의 예로 created는 데이터 초기화에 대한 목적, mounted는 DOM 조작에 대한 목적으로 사용할 수 있다.

created: data에 직접 접근이 가능하기 때문에, 컴포넌트 초기에 외부에서 받아온 값들로 data를 세팅해야 하거나 이벤트 리스너를 선언해야 한다면 이 단계에서 하는 것이 가장 적절합니다.

mounted:일반적으로 가장 많이 사용하는 mounted훅입니다. 가상 DOM의 내용이 실제 DOM에 부착되고 난 이후에 실행되므로, this.$el을 비롯한 data, computed, methods, watch 등 모든 요소에 접근이 가능합니다.

 

출처: https://mygumi.tistory.com/201 [마이구미의 HelloWorld]

props 속성

프롭스 속성은 컴포넌트 간에 데이터를 전달할 수 있는 컴포넌트 통신 방법입니다. 프롭스 속성을 기억할 때는 상위 컴포넌트에서 하위 컴포넌트로 내려보내는 데이터 속성으로 기억하면 쉽습니다.

사용해야될때 : 컴포넌트가 같은 내용이 아닐경우, 큰 틀은 중복되지만, 다른 부분이 있을경우

props속성을 이용하여 각각 다른 내용을 전달 해줄수 있다.

쉽게 부모에서 자식으로 데이터를 전달한다. 

여기서 저는 props로 받는 board와 categories데이터를 초깃값으로 받은 후, 사용자 입력에 따라 로컬 데이터로써 활용하기 위해 props의 데이터와 data의 데이터를 분리하고자 합니다.


Data() 속성

함수 내에서 data를 매번 새로운 객체로 반환.컴포넌트는 data가 각각 컴포넌트마다 달라야하기 때문에 return을 이용하여 컴포넌트의 data를 관리한다.return값을 통해 객체 리터럴을 반환한다.

<template>
  <div>
    [{{ $props.pdata }}] 쿠키런 공지 info
    <div>{{ noticeInfo.title }}</div>
    <div>{{ noticeInfo.regdate }}</div>
    <div>{{ noticeInfo.contents }}</div>
  </div>
</template>

<script>
import { getNoticeContents } from '../../api/api.js';
//props: ['프롭스 속성 명'] : 하위 컴포넌트
// 여기서 idx 데이터를 서버로부터 받아옵니다.
// 컴포넌트에서의 Data (return 객체 리터럴)
//JS에서 Props를 가져올때는 보통 camel-case로 가져온다.
export default {
  props: ['pData'],         
  mounted() {
    console.log(this.$props.send);
  },
  data() {
    return {
      idx: this.$props.send,
      noticeInfo: {}
    }
  },
  created() {
    getNoticeContents(this.idx)
      .then(response =>
        this.noticeInfo = response.data);
  }
}
</script>

<style>

</style>
<template>
  <div id="notice_wrap">
    <div class="notice" v-if="show_title">
      <ul class="notice list">
        <li :key='notice' v-for="notice in notices">
          <div @click="show_contents(`${notice.idx}`)">
            <p class="title">{{ notice.title }}</p>
            <p class="regdate">{{ notice.regdate.split(' ')[0] }}</p>
          </div>
        </li>
      </ul>
    </div>
    <div class="info" v-else>
      <button @click="back_notice()">뒤로가기</button>
      <info-view v-bind:pdata="notice_idx"></info-view>
    </div>
  </div>
</template>

<script>
import { getNotice } from '../../api/api.js';
import InfoView from './InfoView.vue';

export default {
  data() {
    return {
      notices: [],
      show_title: true,
      notice_idx: '',
    }
  },
  created() {
    getNotice()
      .then(response =>
        this.notices = response.data);
  },
  methods: {
    show_contents(idx) {
      this.notice_idx = idx;
      this.show_title = false;
    },
    back_notice() {
      this.show_title = true;
    }
  },
  components: {
    InfoView
  }
}
</script>

<style>
#notice_wrap {
  margin: 15px 0 0 15px;
}

.tag {
  width: 50px;
  height: 20px;
}

.notice.list li {
  list-style: none;
}

.notice.list li div {
  width: 640px;
  height: 60px;
  background-color: white;
  color: black;
  margin-bottom: 8px;
}

.notice.list li div .title {
  padding-top: 3px;
  padding-left: 25px;
  display: inline-block;
}

.notice.list li div .regdate {
  padding-top: 3px;
  padding-right: 25px;
  float: right;
  display: inline;
}


router-link {
  text-decoration: none;
}

ul {
  margin: 0 auto;
  padding: 0;
}
</style>

뷰엑스 등록

뷰엑스를 등록하기 위해서는 뷰 라우터와 마찬가지로 뷰 스토어를 하나 생성해야 합니다.

routes > popup.js

import Vue from 'vue';
import VueRouter from 'vue-router';
import HomeView from '../page/Home.vue';
import InfoView from '../page/popup/Popup.vue';
//라우터 인스턴스 사용
Vue.use(VueRouter);
//path는 url이름, routes:라우팅할 url과 컴포넌트 값 지정, mode:url해쉬 값 제거 속성
export const router = new VueRouter({
    mode: 'history',
    routes: [
        {
            path: '/',
            redirect: '/home',
        },
        {
            path: '/home',
            name: 'home',
            component: HomeView,
        },
        {
            path: '/notice',
            name: 'notice',
            component: InfoView,
        }
    ]
});

데이터의 흐름은 Actions -> Mutations -> State 순서임을 알 수 있습니다.

actions --(commit)-->  mutations --(mutate변화)--> state --(render)--> vue components

--(dispatch)--> actions 

 

actions: Backend API를 받는다. 

vuex 구조도 : actions, mutations, state를 의미한다. 


('index'.js)생성  --파일이름 자유

import Vue from 'vue';

import Vuex from 'vuex';

import { 

getNotice, getNoticeContents 

} from '../api/api.js';     //action역할



Vue.use(Vuex);      //필수

 

export const store = new Vuex.Store({          //const 대신 default 사용 가능

    state: {

        notice: [],

        noticeInfo: {},

    },

    mutations: {

        SET_NOTICE(state, notice) {

            state.notice = notice;

        },

        SET_NOTICE_INFO(state, noticeInfo) {

            state.noticeInfo = noticeInfo;

        }

    },

    actions: {

        GET_NOTICE() {

            getNotice()

                .then(response => {

                    console.log("response");

                    console.log(response.data);

                })

                .catch();

        },

        GET_NOTICE_INFO(idx) {

            getNoticeContents(idx)

                .then(response => {

                    console.log(response.data);

                });

        }

    }

})



Popup.vue

<template>
  <div id="popup">
    <div id="toolbar">
      <ul>
        <li @click="show_contents(main)"
          v-bind:class="{ 'clicked':main_show, 'notclicked':!main_show }">
          <img src="../../assets/main_clicked.png">
        </li>
        <li @click="show_contents(notice)"
          v-bind:class="{ 'clicked':notice_show, 'notclicked':!notice_show }">
          <img src="../../assets/notice.png">
        </li>
      </ul>
    </div>
    <div id="contents">
      <div id="main" v-if="main_show">
        <div class="slide"><slide-view></slide-view></div>
        <div class="scroll"><scroll-view></scroll-view></div>
      </div>
      <div id="notice" v-else>
        <div class="title">
          <notice-view></notice-view>
        </div>

      </div>
    </div>
  </div>
</template>

<script>
import ScrollView from './ScrollView.vue';
import SlideView from './SlideView.vue';
import NoticeView from './NoticeView.vue';

export default {
  name: "popup",
  data: () => {
    return {
      main : 'main',
      notice : 'notice',
      main_show: true,
      notice_show: false,
      clicked: true,
    }
  },
  components: {
    ScrollView,
    SlideView,
    NoticeView,
  },
  methods: {
    show_contents: function(name) {
      console.log(name);

      if(name == 'main') {
        this.notice_show = false;
        this.main_show = true;

      } else if(name == 'notice') {
        this.notice_show = true;
        this.main_show = false;
      }
    }
  }
}
</script>

<style>

@font-face {
  font-family: 'CookieRunOTF';
  src: url('../../assets/CookieRun Bold.otf');
}

#popup {
  font-family: CookieRunOTF;
  margin: 0 auto;
  width: 750px;
  height: 400px;
  border: 2px solid black;
  background-color: #C3CAD7;
}

#contents .scroll {
  padding: 23px;
}

#toolbar li {
  list-style: none;
  width: 80px;
  height: 80px;
}

#toolbar li img {
  width: 80px;
}

#toolbar ul {
  background-color: #383F55;
  float: left;
  margin: 0;
  padding: 0;
  width: 80px;
  height: 400px;
}

.slide {
  float: left;
  width: 370px;
  height: 400px;
  border: 1px solid black;
}

.scroll {
  float: left;
  width: 200px;
  height: 310px;
  border: 1px solid black;
  margin: 20px 0px 0px 23px;
}

#notice {
  float: left;
}

.clicked {
  background-color: #8D97BA;
}

.notclicked {
  background-color: #383F55;
}

</style>

 

2. api 작성
- ('api'.js)생성 --파일이름 자유

import axios from 'axios';

const api = { 
    title: 'http://localhost:8088/popup/notice/title',
    contentens: 'http://localhost:8088/popup/notice/contents?idx=',
};

function getNotice() {

 return axios.get(api.title);

}

function getNoticeContents(idx) {

 return axios.get(api.contents + idx);

}

export {

  getNotice,

  getNoticeContents

}




1. 프로젝트 폴더 추가

├─ README.md

├─ index.html

├─ webpack.config.js

├─ package.json

└─ src

├─ main.js

├─ App.vue

└─ assets

└─ logo.png

 


기본 폴더
src
3>assets (이미지 png파일 가져오는 역할)
7>components (기본 toolbar툴바 역할, 필요에 따라 제거 가능) 생략.

-- 새롭게 추가할 폴더
src
2>api   (axios를 통해 api 링크 가져오는 역할)
3>views (화면단이다. .vue를 보여주는 역할)\
4>store
5>routes (controller 같은 역할) 

 

 

[vue 들어가기전 알아야할 개념들]

 

[클래스 vs 메소드 vs 인스턴스 이게 뭐야??]

post.naver.com/viewer/postView.nhn?volumeNo=6350086&memberNo=30800755&vType=VERTICAL

 

JAVA, 잡아버려 | 13강, 눈을 부릅! 클래스, 객체, 인스턴스와 static지정

[BY PLAY with EXEM] 벌써 잡은 자바물고기가 12개나 됩니다. 모두들 잡은 물고기 핵심을 모두 쏙!!쏙!!!...

m.post.naver.com

[v-bind 생략 가능한가?? Yes!! ]

velog.io/@shkim313/v-bind-%EC%97%98%EB%A6%AC%EB%A8%BC%ED%8A%B8-%EC%86%8D%EC%84%B1-%EC%84%A4%EC%A0%95

 

v-bind 엘리먼트 속성 설정

v-bind 디렉티브

velog.io

[VUE-공식문서]

kr.vuejs.org/v2/guide/components-props.html

 

Props — Vue.js

Vue.js - 프로그레시브 자바스크립트 프레임워크

kr.vuejs.org

[VUE-기초문법]

live-jh.github.io/posts/dev/vue_info/

 

vue template 기초 정리

 

live-jh.github.io

[CRUD가 개념은??]

GET 방식: 데이터 조회

POST 방식: 새로운 데이터의 삽입 및 수정

PUT 방식: 기존 데이터의 수정

DELETE 방식: 기존 데이터의 삭제

 

[스웨거api 환경구성은??]

pom.xml에 swagger의 dependency 추가

Slf4j dependency 추가

Swagger Config설정   java에 추가

[RequestHandlerSelectors.basePackage("api.controller") 이 부분은

api.controller 경로 아래에 API 컨트롤러를 읽겠다는 설정이다.

프로젝트 콘트롤러 경로 써주면 될것같다. ]

sample Controller 생성

[VUE가 뭔가요?]

[Swagger 정의]

-  스웨거는 개발자가 REST 웹 서비스를 설계, 빌드, 문서화, 소비하는 일을 하는 오픈 소스 소프트웨어 프레임워크이다. [위키백과]

[vue개념 정의]

-  MVVM : 모델 - 뷰 - 뷰 모델 (wikidocs.net/17701)

   모델(자바스크립트 사용)-뷰(화면HTML,CSS,JAVASCRIPT)-뷰모델(VUE.JS: 데이터 동기화, 돔 변경내역 반응하는 역할)

[vue 장점]

-  양방향 데이터 바인딩 (화면에 데이터와 프레임워크 데이터 값이 동기화 되어 자동 변경된다.

-  가상 돔 (화면 전체를 다시 그리지않고 변경가능하다)

 

 

[vue 설치순서: 명령어 사용] 1번~5번

1. 환경변수 설정 (blog.nachal.com/1498)(window +r) 환경 > 환경변수 > path 

C:\Users\[해당폴더]\AppData\Roaming\npm
C:\Program Files\nodejs

 

2. node.js 설치(nm817.tistory.com/34?category=816335)

 

3. vue 설치 명령어 사용

$npm i 

$npm i -g @vue/cli ($vue --version 으로 버전 확인)

 

4. 프로젝트 생성 명령어 사용(blog.naver.com/PostView.nhn?blogId=dktmrorl&logNo=222069826131&categoryNo=108&parentCategoryNo=0&viewDate=&currentPage=1&postListTopCurrentPage=1&from=postView)

$vue create '프로젝트명'    (3x vue-cli)

$vue init webpack '프로젝트명' (2x vue-cli)

-  (엔터키)를 누르면 default(babel, eslint)선택

-  확인방법 $npm run serve  (vue-cli 3.x)

-  확인방법 $npm run dev  (vue-cli 2.x)

 

5. 프로젝트 생성후 dependency 다운로드

$npm i axios

$npm i core-js

$npm i cors

$npm i vue

$npm i vue-js-modal --force

$npm i vue-router

$npm i vuex --force (설치 안 되면 --force로 진행)

 

 

 

+ Recent posts