Vue.js_4일차(완벽가이드)

써니·2022년 12월 27일
0

vue.js

목록 보기
4/15

Vue.js

VSCode 플러그인

TSLint 추가


제작할 사이트 & API 소개

해커 뉴스

show / ask / jobs를 사용하여 제작
hacker news
api 깃허브


애플리케이션 라우터 설계

  • show / ask / jobs 페이지 리스트 출력
  • ask에서 상세페이지 이동
  • 상세페이지에서 유저클릭시 유저 정보 출력
    (5개의 라우터)



Vue-Cli 버전

vue-news 폴더 만들기(버전2.x)

vue-cli3 만들기(버전3.x)

버전2와 버전3의 차이점

  • webpack.config의 노출 여부
  • 버전 3 -> ES6의 이해 필요



Vue-Cli 프로젝트 만들기

vue create vue-news
cd vue-news
npm run serve



ESLint

  1. 에러에 대한 대처 안내
  2. 세미콜론, 콤마를 찍게 유도




라우터 설치 및 라우터 구현

라우터 설치

npm i vue-router@3.5.3 --save

📂 router

  • index.js

    export를 하면 다른 곳에서 import 할 수 있다

import Vue from 'vue'
import VueRouter from 'vue-router';
import NewsView from '../views/NewsView.vue';
import AskView from '../views/AskView.vue';
import JobsView from '../views/JobsView.vue';

Vue.use(VueRouter);

export const router = new VueRouter({
  routes: [
    {   
        // path: url 주소
        path: '/news',
        // component: url 주소로 갔을 때 표시될 컴포넌트
        component: NewsView,
    },
    {
        path: '/ask',
        component: AskView,
    },
    {
        path: '/jobs',
        component: JobsView,
    }
  ]
});

📂 views

  • AskView.vue, JobsView.vue, NewsView.vue

    각각의 형태가 같지만 이름은 다른 View 세개 생성

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

<script>
export default {

}
</script>

<style>

</style>

📂 src

  • main.js

    router를 import

import Vue from 'vue'
import App from './App.vue'
import { router } from './router/index.js';

Vue.config.productionTip = false

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

router-view

  • App.vue
<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>


redirect

첫번째 페이지를 news 페이지로 띄우기

import Vue from 'vue'
import VueRouter from 'vue-router';
import NewsView from '../views/NewsView.vue';
import AskView from '../views/AskView.vue';
import JobsView from '../views/JobsView.vue';

Vue.use(VueRouter);

export const router = new VueRouter({
  routes: [
    {
        path: '/',
        redirect: '/news',
    },
    {   
        // path: url 주소
        path: '/news',
        // component: url 주소로 갔을 때 표시될 컴포넌트
        component: NewsView,
    },
    {
        path: '/ask',
        component: AskView,
    },
    {
        path: '/jobs',
        component: JobsView,
    }
  ]
});


페이지 네비게이션

  • App.vue
<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>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
  • ToolBar.vue
<template>
  <div>
    <router-link to="/news">News</router-link>
    <router-link to="/ask">Ask</router-link>
    <router-link to="/jobs">Jobs</router-link>
  </div>
</template>

<script>
export default {

}
</script>

<style>

</style>


라우터 링크 스타일링

scoped 해당 컴포넌트에만 적용됨

  • ToolBar.vue
<template>
  <div class="header">
    <router-link to="/news">News</router-link> |
    <router-link to="/ask">Ask</router-link> |
    <router-link to="/jobs">Jobs</router-link>
  </div>
</template>

<script>
export default {

}
</script>

<style scoped>
.header {
    color: white;
    background-color: #42b883;
    display: flex;
    padding: 8px;
}

.header .router-link-exact-active {
    color: #35495e;
}

.header a {
    color: white;
}
</style>
  • App.vue
<style>
#app {
  padding: 0;
  margin: 0;
}
</style>




(실습) 라우터 구현

ItemView.vue / UserView.vue를 만든 후 router 연결

import Vue from 'vue'
import VueRouter from 'vue-router';
import NewsView from '../views/NewsView.vue';
import AskView from '../views/AskView.vue';
import JobsView from '../views/JobsView.vue';
import ItemView from '../views/ItemView.vue';
import UserView from '../views/UserView.vue';

Vue.use(VueRouter);

export const router = new VueRouter({
  routes: [
    {
        path: '/',
        redirect: '/news',
    },
    {   
        // path: url 주소
        path: '/news',
        // component: url 주소로 갔을 때 표시될 컴포넌트
        component: NewsView,
    },
    {
        path: '/ask',
        component: AskView,
    },
    {
        path: '/jobs',
        component: JobsView,
    },
    {
        path: '/user',
        component: UserView,
    },
    {
        path: '/item',
        component: ItemView,
    }
  ]
});

url 해시태그 # 제거하기

mode: 'history'

import Vue from 'vue'
import VueRouter from 'vue-router';
import NewsView from '../views/NewsView.vue';
import AskView from '../views/AskView.vue';
import JobsView from '../views/JobsView.vue';
import ItemView from '../views/ItemView.vue';
import UserView from '../views/UserView.vue';

Vue.use(VueRouter);

export const router = new VueRouter({
  mode: 'history',
  routes: [
    {
        path: '/',
        redirect: '/news',
    },
    {   
        // path: url 주소
        path: '/news',
        // component: url 주소로 갔을 때 표시될 컴포넌트
        component: NewsView,
    },
    {
        path: '/ask',
        component: AskView,
    },
    {
        path: '/jobs',
        component: JobsView,
    },
    {
        path: '/user',
        component: UserView,
    },
    {
        path: '/item',
        component: ItemView,
    }
  ]
});



axios를 이용한 API

api 주소

<template>
  <div>
    <div v-for="(user, index) in users" :key="index">{{ user.title }}</div>
  </div>
</template>

<script>
import axios from 'axios';
export default {
  data() {
    return {
      users: []
    }
  },
  created() {
    var vm = this;
    axios.get('https://api.hnpwa.com/v0/news/1.json')
    .then(function(response){
      console.log(response);
      vm.users = response.data;
    })
    .catch(function(error){
      console.log(error);
    });
  },
}
</script>

<style>

</style>

API 관리

📂src -> 📂api -> index.js

  1. HTTP Request & Response와 관련된 기본 설정
  2. API 함수들을 정리
import axios from 'axios';

const config = {
    baseUrl: 'https://api.hnpwa.com/v0/'
}

function fetchNewsList() {
    // return axios.get(config.baseUrl + 'news/1.json');
    return axios.get(`${config.baseUrl}news/1.json`);
}

export {
    fetchNewsList
}

👉두가지 방법 다 사용 가능

  • return axios.get(config.baseUrl + 'news/1.json');
  • return axios.get(${config.baseUrl}news/1.json); (백틱)
    중복되는 url을 따로 관리

  • NewsView.vue
<template>
  <div>
    <div v-for="(user, index) in users" :key="index">{{ user.title }}</div>
  </div>
</template>

<script>
import { fetchNewsList } from '../api/index.js';

export default {
  data() {
    return {
      users: []
    }
  },
  created() {
    var vm = this;
    fetchNewsList()
    .then(function(response){
      console.log(response);
      vm.users = response.data;
    })
    .catch(function(error){
      console.log(error);
    });
  },
}
</script>

<style>

</style>

장점

  • 라이브러리, url의 공통 코드들의 중복을 방지한다.

(실습) API

AskView, JobsView 똑같이 구현해보기

📂api

  • index.js
import axios from 'axios';

const config = {
    baseUrl: 'https://api.hnpwa.com/v0/'
}

function fetchNewsList() {
    // return axios.get(config.baseUrl + 'news/1.json');
    return axios.get(`${config.baseUrl}news/1.json`);
}

function fetchAskList() {
    return axios.get(`${config.baseUrl}ask/1.json`);
}

function fetchJobsList() {
    return axios.get(`${config.baseUrl}jobs/1.json`);
}

export {
    fetchNewsList,
    fetchAskList,
    fetchJobsList,
}

📂views

  • AskView.vue
<template>
  <div>
    <div v-for="(user, index) in users" :key="index">{{ user.title }}</div>
  </div>
</template>

<script>
import { fetchAskList } from '../api/index.js';

export default {
  data() {
    return {
      users: []
    }
  },
  created() {
    var vm = this;
    fetchAskList()
    .then(function(response){
      vm.users = response.data;
    })
    .catch(function(error){
      console.log(error);
    });
  }
}
</script>

<style>

</style>
  • JobsView.vue
<template>
  <div>
    <div v-for="(user, index) in users" :key="index">{{ user.title }}</div>
  </div>
</template>

<script>
import { fetchJobsList } from '../api/index.js';

export default {
  data() {
    return {
      users: []
    }
  },
  created() {
    var vm = this;
    fetchJobsList()
    .then(function(response){
      vm.users = response.data;
    })
    .catch(function(error){
      console.log(error);
    });
  }
}
</script>

<style>

</style>


(실습) 정답

created: function () -> created() 생략가능
reactivity in depth

  • JobsView.vue
    화살표로 한줄 표기 가능
<template>
  <div>
    <div v-for="(user, index) in users" :key="index">{{ user.title }}</div>
  </div>
</template>

<script>
import { fetchJobsList } from '../api/index.js';

export default {
  data() {
    return {
      users: []
    }
  },
  created() {
    fetchJobsList()
    .then(response => this.users = response.data)
    .catch(error => console.log(error));
  }
}
</script>

<style>

</style>

this 화살표 함수

자바스크립트에서는 this는 전역 함수

  1. this

  2. this(함수)

  3. this(비동기처리)


  • NewsView.vue
<template>
  <div>
    <div v-for="(user, index) in users" :key="index">{{ user.title }}</div>
  </div>
</template>

<script>
import { fetchNewsList } from '../api/index.js';

export default {
  data() {
    return {
      users: []
    }
  },
  created() {
    console.log('호출 전->',this);
    var vm = this;
    fetchNewsList()
    .then(function(response){
      console.log('호출 후->',this);
      vm.users = response.data;
    })
    .catch(function(error){
      console.log(error);
    });
  },
}
</script>

<style>

</style>

데이터를 요청하고 받아올 때까지 기다려주지 않고 다음 코드인 return response를 실행했기 때문에 초기값을 설정해주지 않은 response 값은 undefined로 출력한다.
이렇게 특정 로직의 실행이 끝날 때까지 기다려주지 않고 나머지 코드를 먼저 실행하는 것이 비동기 처리이다. 동기, 비동기 참고 자료


비동기와 동기 사진


화살표 함수 사용 후

컴포넌트를 가리키는 this을 바로 호출 가능하다

<template>
  <div>
    <div v-for="(user, index) in users" :key="index">{{ user.title }}</div>
  </div>
</template>

<script>
import { fetchNewsList } from '../api/index.js';

export default {
  data() {
    return {
      users: []
    }
  },
  created() {
    console.log('호출 전->',this);
    var vm = this;
    fetchNewsList()
    .then(response => {
      console.log('호출 후->',this);
      vm.users = response.data;
    })
    .catch(function(error){
      console.log(error);
    });
  },
}
</script>

<style>

</style>




비동기 처리(1) - Callback

  • callback.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Callback</title>
</head>
<body>
    <div>jquery ajax</div>
    <script src="https://code.jquery.com/jquery-3.6.3.js" integrity="sha256-nQLuAZGRRcILA+6dMBOvcRh5Pe310sBpanc6+QBmyVM="
        crossorigin="anonymous"></script>
    <script>
        function fetchData() {
            // 1
            var result = [];
            // 2
            $.ajax({
                url: 'https://api.hnpwa.com/v0/news/1.json',
                success: function(data) {
                    console.log('데이터 호출 결과', data);
                    result = data;
                    console.log('ajax 함수 결과', result);
                }
            });

            // 3
            console.log('함수 결과', result);
        }
        fetchData();
    </script>
</body>
</html>


비동기 처리(2) - Promise

mdn promise
Promise 객체는 비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과 값을 나타냅니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Promise</title>
</head>
<body>
    <div>jquery ajax</div>
    <script src="https://code.jquery.com/jquery-3.6.3.js" integrity="sha256-nQLuAZGRRcILA+6dMBOvcRh5Pe310sBpanc6+QBmyVM="
    crossorigin="anonymous"></script>
    <script>
        function callAjax() {
            return new Promise(function(resolve, reject) {
                $.ajax({
                     url: 'https://api.hnpwa.com/v0/news/1.json',
                     success: function(data) {
                        // console.log(data);
                        resolve(data);
                     }
                });
            });
        }

        function fetchData() {
            // 1
            var result = [];
            
            callAjax()
            .then(function(data) {
                console.log('데이터 호출 결과', data);
                result = data;
                console.log('ajax 함수 결과', result);
            });
        }
        fetchData();
    </script>
</body>
</html>

0개의 댓글