Lzh on GitHub

Markdown

在你的 Nuxt 应用程序中创建和查询 Markdown 文件并使用 MDC 语法来集成 Vue 组件。

用法

定义一个集合

content.config.ts
import { defineCollection, defineContentConfig, z } from '@nuxt/content'

export default defineContentConfig({
  collections: {
    blog: defineCollection({
      type: 'page',
      source: 'blog/*.md',
      schema: z.object({
        date: z.string()
      })
    })
  }
})
了解更多关于 page 集合类型的信息。

创建 .md 文件

content/blog/ 目录下创建博客文章。

---
date: 2020-11-11
---

# Foo

This is Foo blog post.

查询 Markdown 文件

现在我们可以查询博客文章了:

// Get the foo post
const fooPost = await queryCollection('blog').path('/foo').first()

// Find all posts
const allPosts = await queryCollection('blog').order('date', 'DESC').all()

显示 Markdown

要显示 Markdown 文件的内容,你可以使用 <ContentRenderer> 组件。

blog/[slug].vue
<script setup>
const slug = useRoute().params.slug
const { data: post } = await useAsyncData(`blog-${slug}`, () => {
  return queryCollection('blog').path(`/blog/${slug}`).first()
})
</script>

<template>
  <!-- Render the blog post as Prose & Vue components -->
  <ContentRenderer :value="post" />
</template>
阅读更多关于 <ContentRenderer> 组件和 Prose Components 的信息。

Frontmatter

Frontmatter 是基于 Markdown 的 CMS 的一种约定,用于为页面提供元数据,如描述或标题。在 Nuxt Content 中,frontmatter 使用 YAML 语法,采用 key: value 键值对的形式。

这些数据在渲染内容时可用,并且可以存储你需要的任何信息。

语法

你可以在 content/ 目录下的 Markdown 文件顶部使用 --- 标识符声明一个 frontmatter 块。

content/index.md
---
title: 'Title of the page'
description: 'meta description of the page'
---

<!-- Content of the page -->
example.ts
const home = await queryCollection('content').path('/').first()

console.log(home.title)
// => 'Title of the page'
console.log(home.description)
// => 'meta description of the page'
console.log(home.body)
// => AST object of the page content

原生参数

类型默认值描述
titlestring页面的第一个 <h1>页面标题,也会被注入到 meta 标签中。
descriptionstring页面的第一个 <p>页面描述,将显示在标题下方并注入到 meta 标签中。
navigationbooleantrue定义该页面是否包含在 queryCollectionNavigation 的返回值中。
你在 frontmatter 块中定义的其他参数需要在你的 schema 中定义(参见此页面顶部的示例中的 date 参数),以便能够使用它们进行查询。

MDC 语法

我们创建了 MDC 语法来增强 Markdown,并使你能够在 Markdown 中集成带有插槽和 props 的 Vue 组件。

安装 MDC VS Code 扩展 以获得 MDC 语法的正确语法高亮。

Vue 组件

你可以在你的 Markdown 文件中使用任何 Vue 组件。

我们提供了一种特殊的语法,使在 Markdown 文件中使用组件更加容易。

content/index.md
::component-name
Default slot content
::
自动注册:将组件放置在 components/content/ 目录下,MDC 会自动识别。
全局注册:如果你不使用 components/content/ 目录,则在 Markdown 中使用的组件必须在你的 Nuxt 应用程序中标记为 global,请访问 Nuxt 3 文档 了解更多信息。

块级组件

块级组件是接受 Markdown 内容或其他组件作为插槽的组件。

该组件必须包含至少一个 <slot /> 组件才能接受格式化文本。

在 Markdown 文件中,使用 :: 标识符来使用该组件。

::card
The content of the card
::

插槽

组件的插槽可以接受内容或其他组件。

  • 默认插槽 渲染块级组件内部的顶层内容或使用 #default
  • 具名插槽 使用 # 标识符渲染相应的内容。
::hero
My Page Title

#description
This will be rendered inside the `description` slot.
::
阅读更多关于 <slot /> 组件的信息。
你可以在你的组件插槽中使用 Markdown:
::my-title
A [rich text](/) will be **rendered** by the component.
::

Props

有两种方法可以使用 MDC 将 props 传递给组件。

内联方法

{} 标识符通过使用 key=value 语法以简洁的方式将 props 传递给组件。

::alert{type="warning"}
The **alert** component.
::
:class="type":class="[type]" 的区别:
  • :class="type"
    • 当 type 是字符串时,直接应用对应的类名
    • 当 type 是数组时,Vue 会将数组直接转换为字符串(可能导致意外的 class1,class2 结果)
    • 当 type 是对象时,Vue 会将其视为类名映射对象
  • :class="[type]"
    • 明确指示 Vue 使用数组语法
    • 正确处理数组中的类名(自动展开)
    • 可以与其他类名组合::class="['static-class', type]"
    • 提供更好的类型提示
[type] 是动态 class 绑定的数组语法。

多个 props 可以用空格分隔:

::alert{type="warning" icon="exclamation-circle"}
Oops! An error occurred
::

v-bind 简写 : 也可以用于将 prop 绑定到 frontmatter 中的一个值。

---
type: "warning"
---

::alert{:type="type"}
Your warning
::

如果你想将数组或对象作为 props 传递给组件,你可以将它们作为 JSON 字符串传递,并在 prop 键前加上冒号以自动解码 JSON 字符串。请注意,在这种情况下,你应该为值字符串使用单引号,以便可以使用双引号传递有效的 JSON 字符串:

::dropdown{:items='["Nuxt", "Vue", "React"]'}
::
YAML 方法

YAML 方法使用 --- 标识符每行声明一个 prop,这对于提高可读性很有用。

::icon-card
---
icon: IconNuxt
description: Harness the full power of Nuxt and the Nuxt ecosystem.
title: Nuxt Architecture.
---
::

属性

属性对于高亮和修改段落的一部分很有用。其语法几乎与内联组件和 Markdown 链接语法类似。

可能的值是所有具名属性、带有 .class-name 标记的类以及带有 #id-name 的 ID。

Hello [World]{style="color: green;" .custom-class #custom-id}!

除了 mdc 组件和 span 之外,属性语法还适用于图像、链接、内联 code、*粗体* 和 _斜体_ 文本。

Attributes work on:

- [link](#attributes){style="background-color: pink;"}, `code`{style="color: cyan;"},
- _italic_{style="background-color: yellow; color:black;"} and **bold**{style="background-color: lightgreen;"} texts.

在 Markdown 中绑定数据

你可以使用 {{ $doc.variable || 'defaultValue' }} 语法在你的 Markdown 文档中绑定数据。这些值可以在文档顶部的 YAML frontmatter 中定义,也可以在每个 MDC 组件中定义,或者使用 <ContentRenderer> 组件的 data prop 注入。

在 YAML 中定义

---
title: 'Title of the page'
description: 'meta description of the page'
customVariable: 'Custom Value'
---

# The Title is {{ $doc.title }} and customVariable is {{ $doc.customVariable || 'defaultValue' }}

使用 <ContentRenderer> 从外部定义

test.vue
<template>
  <div>
    <ContentRenderer :value="data" :data="mdcVars"/>
    <button type="button" v-on:click="mdcVars.name = 'Hugo'">Change name</button>
  </div>
</template>

<script setup lang="ts">
const { data } = await useAsyncData(() => queryCollection('content').path('/test').first());
const mdcVars = ref({ name: 'Maxime'});
</script>
test.md
# Hello {{ $doc.name || 'World' }}

Prose 组件

在 Nuxt Content 中,prose 表示由 Markdown 语法生成的 HTML 标签,例如标题级别和链接。

对于每个 HTML 标签,都会使用一个 Vue 组件,如果需要,你可以覆盖它们,例如 <p> 变为 <ProseP>

如果你想自定义一个 Prose 组件,以下是推荐步骤:

  • 查看原始 组件源码
  • 使用完全相同的 props。
  • 在你的 components/content/ 目录中,给它相同的名称。
  • 尽情发挥你的创意 🚀。
在 Prose 组件部分阅读完整的 Prose 参考。

代码高亮

Nuxt Content 使用 Shiki,它使用 VSCode 主题为 tokens 着色。

代码高亮适用于 ProsePreProseCode

代码块的每一行都在 line 属性中获取其行号,因此可以标记或单独设置行的样式。

图片

你可以将图片添加到你的 public 目录:

Directory structure
content/
  01.backface-visibility.md.filter.md
public/
  image.png
nuxt.config.ts
package.json

然后像这样在 content 目录下的 Markdown 文件中使用它们:

content/index.md
![my image](/image.png)

摘要

可以使用 <!--more--> 作为分隔符从内容中提取内容摘要或总结。

content/index.md
---
title: Introduction
---

Learn how to use `@nuxt/content`.

<!--more-->

Full amount of content beyond the more divider.

除非在 frontmatter props 中定义,否则 description 属性将包含摘要内容。

如果文本中没有 <!--more--> 分隔符,则摘要未定义。

如果你想使用摘要功能,你应该在集合 schema 中定义 excerpt 字段。
content.config.ts
const content = defineCollection({
  type: 'page',
  source: '**',
  schema: z.object({
    excerpt: z.object({
      type: z.string(),
      children: z.any(),
    }),
  }),
})
阅读更多关于 集合 schema 的信息。

示例,变量将被注入到文档中:

{
  "excerpt": Object
  "body": Object
  // ... other keys
}