반응형
<main.js>
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({
render: h => h(App),
router,
store
}).$mount('#app')
Router <index.js>
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', // url #값 제거
routes: [ //routes도 커졌을때 모듈화 가능
{
path: '/',
redirect: '/news',
},
{
path: '/news', // url에 대한 정보가 담기는곳, url주소
component: NewsView, // url 주소로 갔을때 표시될 컴포넌트
},
{
path: '/ask',
component: AskView,
},
{
path: '/jobs',
component: JobsView,
},
{
path: '/item/:id',
component: ItemView,
},
{
path: '/user/:id',
component: UserView,
},
]
});
Store <index.js>
import Vue from 'vue'
import Vuex from 'vuex'
import mutations from './mutation.js';
import actions from './action.js'
Vue.use(Vuex);
// vuex는 상태관리 도구
// 상태는 여러 컴포넌트 간에 공유되는 데이터 속성
export const store = new Vuex.Store({
state : { // 3. state에 저장한다.
news : [],
asks : [],
jobs : [],
user : {},
items: [],
},
getters:{
fetchedNews(state) {
return state.news
},
fetchedAsk(state){
return state.asks
},
fetchedJobs(state){
return state.jobs
},
fetchedItem(state){
return state.items
}
},
mutations, // 2. mutations으로 데이터 받아
actions // 1. 백엔드 API를 actions으로 받고
})
api <index.js>
import axios from 'axios';
// 1. HTTP Requset & Response 와 관련된 기본 설정
const config = {
baseUrl: 'https://api.hnpwa.com/v0/'
};
// 2. 공통 API 함수들 정리
function fetchNewsList(){
// return 바로 해준게 핵심
// return axios.get(config.baseUrl+'/news/1.json');
return axios.get(`${config.baseUrl}news/1.json`);
}
function fetchJobsList(){
return axios.get(`${config.baseUrl}jobs/1.json`)
}
function fetchAskList() {
return axios.get(`${config.baseUrl}ask/1.json`)
}
function fetchUserInfo(username){
// https://api.hnpwa.com/v0/user/lnyan.json
return axios.get(`${config.baseUrl}user/${username}.json`)
}
function fetchCommentItem(id){
// https://api.hnpwa.com/v0/item/32340433.json
return axios.get(`${config.baseUrl}item/${id}.json`)
}
// 3. 마지막 내보내기
export { fetchNewsList, fetchJobsList, fetchAskList, fetchUserInfo, fetchCommentItem }
<actions.js>
import { fetchNewsList, fetchAskList, fetchJobsList, fetchUserInfo, fetchCommentItem } from '../api/index.js'
export default { // 1. 백엔드 API를 actions으로 받고
FETCH_NEWS(context) {
fetchNewsList()
.then(res => {
context.commit('SET_NEWS', res.data);
})
.catch(error => console.log(error));
},
FETCH_ASKS({ commit }) {
fetchAskList()
.then(({ data }) => {
commit('SET_ASKS', data);
})
.catch(error => console.log(error))
},
FETCH_JOBS({ commit }) {
fetchJobsList()
.then(({ data }) => {
commit('SET_JBOS', data);
})
.catch(error => console.log(error))
},
FETCH_USER({ commit }, name){
fetchUserInfo(name)
.then(({ data }) => {
commit('SET_USER', data);
})
.catch(error => console.log(error))
},
FETCH_ITEM({ commit }, id) {
fetchCommentItem(id)
.then(({ data }) => {
commit('SET_ITEM', data);
})
.catch(error => console.log(error))
}
}
<mutation.js>
export default{ // 2. mutations으로 데이터 받아서
SET_NEWS(state, data) {
state.news = data;
},
SET_ASKS(state, data) {
state.asks = data;
},
SET_JBOS(state, data) {
state.jobs = data;
},
SET_USER(state, data){
state.user = data;
},
SET_ITEM(state, data){
state.items = data;
}
}
<App.vue>
<template>
<div id="app">
<tool-bar></tool-bar>
<transition name="page">
<router-view />
</transition>
</div>
</template>
<script>
import ToolBar from './components/ToolBar.vue';
export default {
components:{
ToolBar,
}
}
</script>
<style>
body{
padding: 0;
margin: 0;
}
/* Router 트렌지션 */
.page-enter-active,
.page-leave-active {
transition: opacity .5s;
}
.page-enter,
.page-leave-to
/* .fade-leave-active below version 2.1.8 */
{
opacity: 0;
}
</style>
<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: #fff;
background-color: #42b883;
display: flex;
padding: 8px;
}
.header .router-link-exact-active{
color: #354952;
}
.header a {
color: #fff;
}
</style>
<NewsView.vue>
<template>
<div>
<!-- v-bind:key 에는 객체 넣을수없고 숫자, 문자만 넣을수 있다 -->
<!-- <div v-for="(user, i) in fetchedNews" v-bind:key="i">{{ user.title }}</div> -->
<p v-for="(item, i) in fetchedNews" v-bind:key="i">
<a v-bind:href="item.url">
{{ item.title }}
</a>
<small>{{ item.time_ago }} by
<!-- <router-link v-bind:to="'/user' + item.user">
{{ item.user }}
</router-link> -->
<router-link v-bind:to="`/user/${item.user}`">
{{ item.user }}
</router-link>
</small>
</p>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
computed: {
...mapGetters(['fetchedNews'])
},
created(){
this.$store.dispatch('FETCH_NEWS');
}
};
</script>
<style lang="scss" scoped>
</style>
<AskView.vue>
<template>
<div>
<!-- <div v-for="(ask, i) in fetchedAsk" v-bind:key="i"> {{ ask.title}} </div> -->
<p v-for="(item, i) in fetchedAsk" v-bind:key="i">
<!-- v-bind:href 축약-->
<router-link v-bind:to="`item/${item.id}`">
{{ item.title }}
</router-link>
<small>{{ item.time_ago }}, {{ item.user }}</small>
</p>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
computed:{
// 3.
...mapGetters(['fetchedAsk'])
// 2.
// ...mapGetters({ //객체, 배열 풀어서 넣는 역할
// askItems: 'fetchedAsk'
// })
// 1.
// ...mapState({
// asks: state => state.asks
// })
},
created(){
this.$store.dispatch('FETCH_ASKS');
}
};
</script>
<style lang="scss" scoped>
</style>
<JobsView.vue>
<template>
<div>
<!-- <div v-for="(job, i) in fetchedJobs" v-bind:key="i">{{ job.title }}</div> -->
<p v-for="(item, i) in fetchedJobs" v-bind:key="i">
<a :href="item.url">
{{ item.title }}
</a>
<small>{{ item.time_ago }}, {{ item.domain }}</small>
</p>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
computed:{
...mapGetters(['fetchedJobs'])
},
created(){
this.$store.dispatch('FETCH_JOBS');
}
};
</script>
<style lang="scss" scoped>
</style>
<UserView.vue>
<template>
<div>
<p>name : {{ userInfo.id }}</p>
<p>karma : {{ userInfo.karma }}</p>
<p>created : {{ userInfo.created }}</p>
</div>
</template>
<script>
export default {
computed: {
userInfo() {
return this.$store.state.user;
}
},
created(){
const userName = this.$route.params.id;
// axios.get(`https://api.hnpwa.com/v0/user/${userName}.json`)
this.$store.dispatch('FETCH_USER', userName);
},
};
</script>
<style lang="scss" scoped>
</style>
<UserView.vue>
<template>
<div>
<section>
<!--질문 상세정보-->
<div class="user-container">
<div>
<i class="fa-solid fa-user"></i>
</div>
<div class="user-description">
<router-link :to="`/user/${fetchedItem.user}`">{{ fetchedItem.user }}</router-link>
<div class="time">
{{ fetchedItem.time_ago }}
</div>
</div>
</div>
<h2>{{ fetchedItem.title }}</h2>
</section>
<section>
<!--질문 댓글-->
<div v-html="fetchedItem.content"></div>
</section>
</div>
</template>
<script>
import { mapGetters } from 'vuex';
export default {
computed:{
...mapGetters(['fetchedItem'])
},
created(){
const itemId = this.$route.params.id; // router-link로 넘긴 데이터 받을때
this.$store.dispatch('FETCH_ITEM', itemId); // actions에 보내는 dispatch
}
};
</script>
<style scoped>
.user-container{
display: flex;
align-items: center;
padding: 0.5rem;
}
.fa-user{
font-size: 2.5rem;
}
.user-description{
padding-left: 8px;
}
.time{
font-size: 0.7rem;
}
</style>
반응형
'vue.js > vue.js 2' 카테고리의 다른 글
63. <vue-news> 프로젝트 | 컴포넌트의 코드마저 재사용하는 하이 오더 컴포넌트 (0) | 2022.08.07 |
---|---|
62. <vue-news> 프로젝트 | list 공통 컴포넌트화 (0) | 2022.08.06 |
60. <vue-news> 프로젝트 | Router 트렌지션 (0) | 2022.08.06 |
59. <vue-news> 프로젝트 | API 데이터 출력하는 순서 | axios 순서 (0) | 2022.08.05 |
58. <vue-news> 프로젝트 | Dynamic Route Matching | 동적 라우트 매칭 (0) | 2022.08.05 |