ArticleView route코드 -> App에 ArticleView 컴포넌트로 이동하는 RouterLink 작성 -> ArticleView 컴포넌트에 ArticleList 컴포넌트 등록 -> store에 임시 데이터 articles 배열 작성하기 -> ArticleList 컴포넌트에서 게시글 목록 출력 -> ArticleListItem 컴포넌트는 내려받은 props를 정의 후 출력 -> 메인 페이지 게시글 목록 출력 확인
// router/index.js
import ArticleView from '@/views/ArticleView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'ArticleView',
component: AritcleView,
}
]
})
<!--App.vue-->
<template>
<header>
<nav>
<RouterLink :to='{name: 'ArticleView'}">Articles</RouterLink>
</nav>
</header>
<RouterView />
</template>
<script setup>
import { RouterView, RouterLink } from 'vue-router'
</script>
<!--views/ArticleView.vue-->
<template>
<div>
<h1>Article Page</h1>
<ArticleList />
</div>
</template>
<script setup>
import ArticleList from '@/components/ArticleList.vue'
</script>
//store/counter.js
export const useCouterStore = defineStore('counter', () => {
const articles = ref ([
{id: 1, title : 'Article 1', content: 'Content of article 1' },
{id: 2, title : 'Article 2', content: 'Content of article 2' },
])
return { articles }
}, { persist : true })
<!-- components/ArticleList.vue -->
<template>
<div>
<h3>Article List</h3>
<ArticleListItem
v-for="article in store.articles"
:key='article.id'
:article='article'
/>
</div>
</template>
<scipt setup>
import { useCounterStore } from '@/stores/counter'
import ArticleListItem from '@/components/ArticleListItem.vue'
const store = useCounterStore()
</script>
<!--components/ArticleListItem.vue-->
<template>
<div>
<h5>{{ article.id }}</h5>
<p>{{ article.title }}</p>
<p>{{ article.content }}</p>
<hr>
</div>
</template>
<script setup>
defineprops({
article: Object
})
</script>
- DRF 서버로의 AJAX 요청을 위한 axios 설치 및 관련 코드 작성 -> 2. DRF 서버로 요청을 보내고 응답 데이터를 처리하는 getArticles 함수 작성 ->
npm install axios
// store/counter.js
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
import axios from 'axios'
export const useCounterStore = defineStore('counter',() => {
const articles = ref([])
const API_URL = 'http://127.0.0.0.1:8000'
}, { persist: true })
// store/counter.js
export const useCounterStore = defineStore('counter', () => {
const getArticles() = function () {
axios({
method: 'get',
url: `${API_URL}/api/v1/articles/`
})
.then(res => {
console.log(res)
console.log(res.data)
})
.catch(err => console.log(err))
}
return { articles, API_URL, getArticles }
}, { persist: true })
<!-- views/ArticleView.vue -->
<script setup>
import { onMounted } from 'vue'
import { useCounterStore } from '@/stores/counter'
import ArticleList from '@/components/ArticleList.vue'
const store = useCounterStore()
onMounter(()=> {
store.getArticles()
})
</script>
SOP (Same-origin policy)
웹 애플리케이션의 도메인이 다른 도메인의 리소스에 접근하는 것을 제어하여 사용자의 개인정보와 데이터의 보안을 보호하고, 잠재적인 보안 위협을 방지
잠재적으로 해로울 수 있는 문서를 분리함으로써 공격받을 수 있는 경로를 줄인다.
pip install django-cors-headers
#settings.py
CORS_ALLOWED_ORIGINS = [
'http://127.0.0.1:5173',
'http://localhost:5173',
]
// store/counter.js
export const useCounterStore = defineStore('counter', () => {
...
const getArticles= function () {
axios({
method: 'get',
url: `${API_URL}/api/v1/articles/`
})
.then(res => {
articles.value = res.data
})
.catch(err => console.log(err))
}
return { articles, getArticles }
}, { persist: true })
DetailVue route 작성 -> ArticleListItem에 DetailView 컴포넌트로 가기 위한 RouterLink 작성 -> DetailView가 마운트 될때 특정 게시글을 조회하는 AJAX 요청 진행
// router/index.js
import DetailView from '@/views/DetailView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes : [
{
path: '/',
name: 'ArticleView',
component: ArticleView
},
{
path: '/articles/:id',
name: 'DetailView',
component: DetailView
}...
<!-- components/ArticleListItem.vue-->
<template>
<div>
<h5>{{ article.id }}</h5>
<p>{{ article.title }}</p>
<p>{{ article.content }}</p>
<RouterLink :to="{name: 'DetailView', params: {id: article.id} ">
[DETAIL][
</RouterLink>
<hr>
</div>
</template>
<script setup>
import { RouterLink } from 'vue-router'
...
</script>
// views/DetailView.vue
import axios from 'axios'
import { onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { useCounterStore } from '@/stores/counter'
const store = useCounterStore()
const route = useRoute()
onMounted(() => {
axios({
method: 'get',
url: `${store.API_URL}/api/v1/articles/${route.params.id}/`,
})
.then((res) => {
console.log(res.data)
})
.catch(err => console.log(err))
})
// router/index.js
import CreateView from '@/views/CreateView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
...
{
path:'/create',
name: 'CreateView',
component: CreateView
}
<!-- views/ArticleView.vue -->
<script setup>
import { onMounted } from 'vue'
import { useCounterStore } from ..
import { RouterLink } from 'vue-router'
import ArticleList from '@/components/ArticleList.vue'
</script>
<!--views/ArticleView.vue-->
<template>
<div>
<h1>Article Page</h1>
<RouterLink :to="{ name: 'CreateView' }">
[CREATE]
</RouterLink>
<hr>
<ArticleList />
</div>
</template>
<!-- views/CreateView.vue -->
<template>
<div>
<h1>게시글 작성</h1>
<form>
<label for='title'>제목: </label>
<input type='text' id='title' v-model.trim='title'><br>
<label for='content'>내용: </label>
<textarea id='content' v-model.trim='content'></textarea><br>
<input type='submit'>
</form>
</div>
</template>
// views/CreateView.vue
const createArticle = function () {
axios({
method: 'post',
url: `${store.API_URL}/api/v1/articles/`,
data: {
title: title.value,
content: content.value
},
}).then(() => {
router.push({name: 'ArticleView' })
}).catch(err => console.log(err))
}