vue.js/vue.js 2

61. <vue-news> 프로젝트 | 1차 완성

DEV-Front 2022. 8. 6. 00:30
반응형


<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>
반응형