這兩天建立了文章列表與搜尋功能後,發現現在若是點擊文章列表上的標籤(tag)後,會顯示:
Document not found, overwrite this content with #not-found slot in <ContentDoc>.
但我們預期是點擊特定標籤後,應該顯示的是有該標籤的文章列表,而不是這樣的內容。這其實是因為我們還沒有實作標籤的頁面,所以他是直接套用我們頁面最底層的頁面元件 @/pages/[...slug].vue
,而該頁面元件是會渲染 content 目錄下對應路徑的 Markdwon,沒有特別去新增的話,理所當然會因為找不到而跳出該訊息。
所以今天就來為標籤新增其對應的頁面吧!首先建立 @/pages/tags/[...slug].vue
,並填寫以下內容:
<template>
<section>
<div class="divide-y divide-gray-200">
<header class="pt-6 pb-8 space-y-2 md:space-y-5">
<div>
<h1 class="tracking-tight font-extrabold text-gray-900 text-2xl leading-6 mb-1">
Tag: {{ tag }}
</h1>
</div>
</header>
<main>
<ul>
<li v-for="item in tagPosts" :key="item._path" class="py-4">
<ListItem :item="item" />
</li>
</ul>
</main>
</div>
</section>
</template>
<script setup lang="ts">
const route = useRoute()
const tag = route.params.slug.toString().toUpperCase()
const { data: tagPosts } = await useAsyncData(() => {
return queryContent()
.where({ _dir: { $in: ['articles'] } })
.where({ tags: { $icontains: tag } })
.find()
})
</script>
這段時程式碼其實很簡單,<template />
裡的結構和過去兩天的文章列表的 @/pages/articles/index.vue
很相似。與其不同的部分主要落在 <script />
中。
這裡使用了 useRoute()
這個 API,並透過其屬性協助頁面取得相關參數。而這裡取得的 slug
,其實就是 @/pages/tags/[...slug].vue
檔案路徑所揭示的位置,也就是實際網頁中 localhost:3000/tags/[slug]
中的 [slug]
:
const route = useRoute()
const tag = route.params.slug.toString().toUpperCase()
接著再透過前天用到的查詢方法,檢索在 articles
目錄下,有沒有 tags 屬性中,含有與 tag 相符且大小寫不一定要一致的項目。這邊疑應試 MongoDB 的檢索方法,其中檢視陣列中有沒有某元素是用 {array: { $contains: KEYWORD } }
,而如果希望判斷時不用大小寫一致,則改使用 $icontains
,i
即為 insensitive
之意。
const tag = route.params.slug.toString().toUpperCase()
const { data: tagPosts } = await useAsyncData(() => {
return queryContent()
.where({ _dir: { $in: ['articles'] } })
.where({ tags: { $icontains: tag } })
.find()
})
完成後就會發現當我點擊 Nuxt 標籤後,就只會顯示有該標籤的文章:
緊接著我會三篇不同文章新增大小寫不同的 ASD-FGH-QWE
標籤,來測試一下是否大小寫不敏感: