주소에 따라 특정 컴포넌트로 변경하게 했지만, 아직 Notion API에 적용까지 하지 못하여 내용이 나오지 않고 있습니다. 이를 위해서 글의 id와 카테고리 값이 필요한데, 이를 URL에서 가져오는 방법에 대해 알아보겠습니다.
URL
url이란? Uniform Resource Locator의 약자로, 인터넷에서 특정 리소스(Resource)의 위치를 가리키는 문자열입니다. 리소스란, 웹 상에서 클라이언트가 요청한 정보를 의미합니다. 대표적으로 HTML, CSS, JavaScript, 이미지 등이 있습니다. 즉 URL은 웹 상에서 존재하는 정보들의 경로(위치)를 말합니다.
URL 구조
URL 구조는 크게 다음과 같이 구성되어있습니다.

- 프로토콜 (Protocol): 리소스에 접근하기 위한 규칙이라고 할 수 있습니다. URL에 사용되는 가장 일반적인 프로토콜은 HTTP와 HTTPS입니다. HTTP는 보안성이 낮은 반면, HTTPS는 보안성이 높습니다.
- 호스트 주소 (Host Address): 리소스가 위치한 서버의 주소를 의미합니다. 일반적으로 도메인 이름으로 사용됩니다. 도메인 이름은 IP 주소와 매핑되어 있으며, IP 주소를 입력해도 도메인 이름으로 리소스에 접근할 수 있습니다.
- 파일 경로 (File Path): 서버 내에서 리소스가 위치한 경로를 의미합니다. 파일 경로는 디렉토리와 파일 이름으로 구성되어 있으며, 슬래시 (/)로 구분됩니다.
- 쿼리스트링(Query String): URL에서 사용되는 파라미터(Parameter)의 일종입니다. 쿼리스트링은 URL의 끝에
?
기호와 함께 전달되며, 여러 개의 파라미터들은&
기호로 구분됩니다. 쿼리스트링을 사용하면 클라이언트가 서버에게 정보를 전달할 수 있습니다. 예를 들어, 검색 엔진에서 검색 결과 페이지를 보여줄 때, 검색어를 쿼리스트링으로 전달하여 검색 결과를 필터링할 수 있습니다.
만약 https://realmyspace.com/category/html 이라는 URL에 접속한다면, 해당 서버가 가진 서버의 /category/html
폴더에 위치한 index.html
파일을 요청하여 페이지를 보여주게됩니다.

Q] html까지만 적었는데 왜 index.html을 가져오나요? A] 서버는 폴더까지 적을 경우 특정 파일을 읽도록 설정되어있습니다. 보통은 index.html을 가져오며 default.html나 그 외에 다른 파일을 보도록 설정할 수 있습니다.
이번 시간에는 파일 경로 값을 읽어와서 글 목록과 내용을 가져와
useRoute
URL에 대한 정보는 VueRouter의 useRoute
함수를 통해 가져올 수 있습니다.
import { useRoute } from "vue-router"
const route = useRoute();
PostList에 적용하기
이 내용을 PostList.vue
에 추가해보겠습니다.
<script setup>
import { useRoute } from "vue-router";
import { ref, computed, onMounted } from "vue";
import { getPageTable } from "vue-notion";
const search = ref("");
const route = useRoute();
console.log(route);
// ...
</script>
그러면 route안에 다양한 반응형 객체들이 들어간 것을 볼 수 있는데요.

우리는 이 중 path
라는 값을 사용해보겠습니다. path는 /category/html
이란 값을 가지고 있습니다. 그럼 html
이란 값도 가져올 수 있겠죠!

path의 값에서 /category/
뒤의 값을 가져오는 방법은 다음과 같이 가능합니다.
<script setup>
// ...
const route = useRoute();
// route.path ==> /category/html
// route.path.split('/') ==> ['', 'category', 'html']
// route.path.split('/').pop() ==> 'html'
const selectedCategory = route.path.split("/").pop();
// 기존의 props는 제거합니다.
// const props = defineProps(["selectedCategory"]);
// ...
// props.selectedCategory -> selectedCategory로 변경
const filteredList = computed(() => {
if (search.value == "") {
return postList.value[selectedCategory];
} else {
// ...
});
</script>
하지만 이럼에도 불구하고 글 목록이 나타나지 않을 것입니다. 왜냐하면 postList
값에는 대문자로 저장되어 있고, 우리의 selectedCategory
값은 소문자이기 때문입니다.
postList = {
HTML: [ ... ]
CSS: [ ... ]
Javascript: [ ... ]
}
selectedCategory = "html"
그래서 filteredList
에서 값을 가져올 때 약간의 수정이 필요합니다.
const filteredList = computed(() => {
if (search.value == "") {
// category: "HTML" -> "CSS" -> "Javascript 순회
for (const category in postList.value) {
// category.toLowerCase() = "HTML" -> "html"
// selectedCategory = "html"
// 같은 경우 해당 리스트 반환
if (category.toLowerCase() == selectedCategory) {
return postList.value[category];
}
}
// return postList.value[selectedCategory];
} else {
// ...
글 목록이 나타납니다!

하지만 CSS와 Javascript를 클릭해도 아무런 변화가 없습니다.

기억하시나요 props.selectedCategory
는 반응형이였다는 것을! 주소가 바뀜에 따라 selectedCategory
값도 반응해서 바뀌어야합니다. route
값이 반응형 상태이기 때문에, computed를 사용할 수 있습니다.
<script setup>
// ...
// const selectedCategory = route.path.split("/").pop();
const selectedCategory = computed(() => route.path.split("/").pop());
// ...
const filteredList = computed(() => {
// ...
if (category.toLowerCase() == selectedCategory.value) {
return postList.value[category];
}
// ...
});
</script>
이제야 제대로 바뀌네요! 하지만 아직 글을 클릭해도 주소가 바뀌지 않습니다. 이 것도 마저 바꿔볼게요!

이전에 MenuBar에서 사용했던 RouterLink
를 적용하면 됩니다.
<template>
<!-- ... -->
<ul>
<li v-for="item in filteredList" :key="item.id">
<!-- <button class="post" @click="$emit('click-post', item.id)">
{{ item.title }}
</button> -->
<RouterLink class="post" :to="'/post/' + item.id">
{{ item.title }}
</RouterLink>
</li>
</ul>
</template>
이제 주소도 바뀝니다!!

다만 아무런 페이지가 나타나지 않는데요. 이는 우리가 router에서 이런 주소에 어떤 컴포넌트를 보여야할지 정하지 않았기 때문입니다. 개발자 도구에서 이런 경고문이 보일겁니다.

router/index.js
의 routes
값에는 이런 경로들이 없었습니다.
// ...
routes: [
{
path: "/category/html",
component: PostList,
},
{
path: "/category/css",
component: PostList,
},
{
path: "/category/javascript",
component: PostList,
},
{
path: "/post/1",
component: PostContent,
},
{
path: "/post/2",
component: PostContent,
},
{
path: "/post/3",
component: PostContent,
},
],
// ...
하지만 만약 이 주소에 대한 매칭을 따로 넣는다면 해당 글에 대한 페이지를 볼 수 있을겁니다.
{
path: "/post/8bc11312-00d8-4f68-b3b4-baa0c1c98e26",
component: PostContent,
},
하지만 모든 페이지마다 이런 route
설정을 하는 것은 너무 번거롭습니다. 그래서 다음 글에서는 routes
설정을 좀 더 유연하게 할 수 있는 방법에 대해 다뤄보겠습니다.