Đăng nhập

BÀI 17: XỬ LÝ DỮ LIỆU MARKDOWN NÂNG CAO VỚI @nuxt/content

Cùng tiếp tục với Bài 17 – Xử lý dữ liệu Markdown nâng cao với @nuxt/content. Sau khi bạn đã biết cách hiển thị một bài blog, giờ là lúc làm cho blog chuyên nghiệp hơn, giống như Medium, Dev.to, hay các blog kỹ thuật lớn.


BÀI 17: XỬ LÝ DỮ LIỆU MARKDOWN NÂNG CAO VỚI @nuxt/content


1. Hiển thị thông tin tác giả, ngày đăng, thời gian đọc

Trong mỗi bài viết Markdown, thêm phần frontmatter:

---
title: Bắt đầu với Nuxt Content
description: Tìm hiểu cách dùng Markdown trong Nuxt
author: Johnny
date: 2025-07-07
---

# Nội dung bài viết

Trong component pages/blog/[slug].vue:

<template>
  <article v-if="post">
    <h1>{{ post.title }}</h1>
    <p>
      {{ post.date }} – {{ post.author }} – 
      {{ post.readingTime?.text || '...' }}
    </p>

    <ContentRenderer :value="post" />
  </article>
</template>

readingTime được tự động tính từ số chữ


2. Tạo Table of Contents (TOC)

Để tạo mục lục tự động, bạn cần cài plugin @nuxt/content đã có sẵn tính năng này.

Trong pages/blog/[slug].vue:

<script setup>
const { params } = useRoute()
const { data: post } = await useAsyncData(() =>
  queryContent('/blog').where({ _path: `/blog/${params.slug}` }).findOne()
)
</script>

<template>
  <div v-if="post">
    <aside class="toc">
      <ContentNavigation :toc="post.body.toc" />
    </aside>
    <article>
      <h1>{{ post.title }}</h1>
      <ContentRenderer :value="post" />
    </article>
  </div>
</template>

<style scoped>
.toc {
  float: right;
  width: 250px;
  font-size: 14px;
  margin-left: 20px;
}
</style>

3. Gắn tag cho bài viết

Trong frontmatter:

---
title: Tìm hiểu Nuxt
tags: ['nuxt', 'vue', 'markdown']
---

Hiển thị:

<ul class="tags">
  <li v-for="tag in post.tags" :key="tag">#{{ tag }}</li>
</ul>

Sau đó bạn có thể tạo trang /tag/[tag].vue để lọc bài viết theo tag.


4. Hiển thị bài viết liên quan (Related Posts)

Trong pages/blog/[slug].vue, sau phần content:

<script setup>
const related = await queryContent('/blog')
  .where({ tags: { $in: post.value?.tags || [] } })
  .limit(4)
  .find()
</script>

<template>
  <section>
    <h2>Bài viết liên quan</h2>
    <ul>
      <li v-for="item in related" :key="item._path">
        <NuxtLink :to="item._path">{{ item.title }}</NuxtLink>
      </li>
    </ul>
  </section>
</template>

→ Bài viết liên quan dựa trên tag giống nhau


5. Hiển thị code có highlight + copy

Trong nuxt.config.ts:

export default defineNuxtConfig({
  content: {
    highlight: {
      theme: 'github-dark', // hoặc 'dracula', 'one-dark',...
      preload: ['ts', 'js', 'vue', 'html', 'bash']
    }
  }
})

Bạn viết code trong markdown như sau:

```js
console.log('Hello Nuxt!')
```

→ Nuxt sẽ render với highlight tự động


6. Tính năng nâng cao khác

Bạn có thể mở rộng:

  • Hiển thị số lượt đọc bằng API
  • Hiển thị tác giả với avatar, bio
  • Lọc theo năm, theo danh mục
  • Thêm search bằng Algolia hoặc Fuse.js

Bạn đã học được

  • Thêm author, date, readingTime vào bài viết
  • Hiển thị Table of Contents từ post.body.toc
  • Gắn tag, tạo bài viết liên quan tự động
  • Highlight code trong Markdown
  • Chuẩn hóa blog kỹ thuật đẹp và chuyên nghiệp hơn

Bài tập mở rộng

  1. Tạo ít nhất 5 bài viết, mỗi bài có title, tags, author, date
  2. Hiển thị TOC, thời gian đọc, bài viết liên quan
  3. Tạo component PostMeta.vue hiển thị toàn bộ meta
  4. Dùng layout blog.vue để giữ UI đồng nhất

Thảo luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *

Đăng ký nhận tin mới

Nhận bài học, tài nguyên và cơ hội việc làm qua email hàng tuần.

Chúng tôi cam kết không spam. Bạn có thể hủy bất cứ lúc nào.