您正在阅读 Nuxt 内容 V1 文档。阅读最新版本

社区

代码片段

了解如何使用这些代码片段将 @nuxt/content 实现到您的应用中。

用法

asyncData

export default {
  async asyncData({ $content, params }) {
    const article = await $content('articles', params.slug).fetch()

    return {
      article
    }
  }
}

根据在 前置信息 中定义的标题和描述添加动态元数据

export default {
  async asyncData({ $content, params }) {
    const article = await $content('articles', params.slug).fetch()

    return {
      article
    }
  },
  head() {
    return {
      title: this.article.title,
      meta: [
        { hid: 'description', name: 'description', content: this.article.description },
        // Open Graph
        { hid: 'og:title', property: 'og:title', content: this.article.title },
        { hid: 'og:description', property: 'og:description', content: this.article.description },
        // Twitter Card
        { hid: 'twitter:title', name: 'twitter:title', content: this.article.title },
        { hid: 'twitter:description', name: 'twitter:description', content: this.article.description }
      ]
    }
  }
}

功能

通过使用 watch 添加搜索输入组件

<template>
  <div>
    <input v-model="query" type="search" autocomplete="off" />

    <ul v-if="articles.length">
      <li v-for="article of articles" :key="article.slug">
        <NuxtLink :to="{ name: 'blog-slug', params: { slug: article.slug } }">{{ article.title }}</NuxtLink>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data () {
    return {
      query: '',
      articles: []
    }
  },
  watch: {
    async query (query) {
      if (!query) {
        this.articles = []
        return
      }

      this.articles = await this.$content('articles')
        .only(['title', 'slug'])
        .sortBy('createdAt', 'asc')
        .limit(12)
        .search(query)
        .fetch()
    }
  }
}
</script>

查看 搜索文档

上一页和下一页

使用 surround 方法添加上一页和下一页链接

<template>
  <div>
    <NuxtLink v-if="prev" :to="{ name: 'blog-slug', params: { slug: prev.slug } }">
      {{ prev.title }}
    </NuxtLink>

    <NuxtLink v-if="next" :to="{ name: 'blog-slug', params: { slug: next.slug } }">
      {{ next.title }}
    </NuxtLink>
  </div>
</template>

<script>
export default {
  async asyncData({ $content, params }) {
    const [prev, next] = await $content('articles')
      .only(['title', 'slug'])
      .sortBy('createdAt', 'asc')
      .surround(params.slug)
      .fetch()

    return {
      prev,
      next
    }
  }
}
</script>

如果多个文档具有相同的 slug,则应将 path 作为 surround 方法的第一个参数,而不是 slug。 这是因为 Nuxt 内容根据第一个匹配的文档查找上一页和下一页文档。

例如,如果您按 position 对文档进行排序,即使当前页面显示的是较高位置的文档,也将始终使用位置较低的文档进行计算。

查看 surround 文档

不区分大小写的排序

需要解决 Nuxt 内容的不区分大小写排序问题,为文档添加额外的属性,其值是小写的。

nuxt.config.js
export default {
  hooks: {
    'content:file:beforeInsert': (document) => {
      if (document.extension === '.md') {
        Object.entries(document).forEach(([key, value]) => {
          const _key = `case_insensitive__${key}`; // prefix is arbitrary

          if (!document[_key] && typeof value === 'string') {
            document[_key] = value.toLocaleLowerCase();
          }
        });
      }
    }
  }
};

然后,使用要排序的额外属性的键调用 sortBy 方法。

export default {
  async asyncData({ $content, params }) {
    const articles = await $content('articles', params.slug)
      .sortBy('case_insensitive__title', 'asc') // Set prefixed prop
      .fetch()

    return {
      articles
    }
  }
}

查看 sortBy 文档

目录

通过循环遍历 toc 数组并使用 id 链接到它以及使用 text 显示标题来添加目录。 我们可以使用 depth 以不同的方式设置标题的样式

<template>
  <ul>
    <li
      v-for="link of article.toc"
      :key="link.id"
      :class="{ 'toc2': link.depth === 2, 'toc3': link.depth === 3 }"
    >
      <NuxtLink :to="`#${link.id}`">{{ link.text }}</NuxtLink>
    </li>
  </ul>
</template>

<script>
export default {
  async asyncData({ $content, params }) {
    const article = await $content('articles', params.slug)
      .fetch()

    return {
      article
    }
  }
}
</script>

查看 目录文档

动态路由

假设您要创建一个应用程序,其路由遵循 content/ 文件结构。 您可以通过创建一个 pages/_.vue 组件来做到这一点

pages/_.vue
<script>
export default {
  async asyncData ({ $content, app, params, error }) {
    const path = `/${params.pathMatch || 'index'}`
    const [article] = await $content({ deep: true }).where({ path }).fetch()

    if (!article) {
      return error({ statusCode: 404, message: 'Article not found' })
    }

    return {
      article
    }
  }
}
</script>

这样,如果您访问 /themes/docs 路由,它将显示 content/themes/docs.md 文件。 如果您需要为目录创建索引页面,则需要创建一个与目录同名的文件

content/
  themes/
    docs.md
  themes.md

如果您使用 nuxt-i18n,请不要忘记在调用之前加上当前语言环境前缀。

自定义高亮显示

Highlight.js

nuxt.config.js
import highlightjs from 'highlight.js'

const wrap = (code, lang) => `<pre><code class="hljs ${lang}">${code}</code></pre>`

export default {
  // Complete themes: https://github.com/highlightjs/highlight.js/tree/main/src/styles
  css: ['highlight.js/styles/nord.css'],

  modules: ['@nuxt/content'],

  content: {
    markdown: {
      highlighter(rawCode, lang) {
        if (!lang) {
          return wrap(highlightjs.highlightAuto(rawCode).value, lang)
        }
        return wrap(highlightjs.highlight(rawCode, { language: lang }).value, lang)
      }
    }
  }
}

Shiki

Shiki 是一个语法高亮器,它使用 TexMate 语法,并使用 VS Code 主题对标记进行着色。 它将生成与 VS Code 中的代码完全一致的 HTML。

您无需添加自定义样式,因为 Shiki 会将其内联到 HTML 中。

nuxt.config.js
import shiki from 'shiki'

export default {
  modules: ['@nuxt/content'],

  content: {
    markdown: {
      async highlighter() {
        const highlighter = await shiki.getHighlighter({
          // Complete themes: https://github.com/shikijs/shiki/tree/main/packages/shiki/themes
          theme: 'nord'
        })
        return (rawCode, lang) => {
          return highlighter.codeToHtml(rawCode, lang)
        }
      }
    }
  }
}

Shiki Twoslash

Twoslash 是一种用于 TypeScript 代码的标记格式。 在内部,Twoslash 使用 TypeScript 编译器生成丰富的高亮信息。

要更好地了解 Twoslash 的工作原理,您可以访问 官方 TypeScript 文档 并将鼠标悬停在其中的一些代码示例上。

您可以使用 Shiki Twoslash 达到相同的结果。 此包也是为官方 TypeScript 文档提供支持的包。

nuxt.config.js
import {
  createShikiHighlighter,
  runTwoSlash,
  renderCodeToHTML
} from 'shiki-twoslash'

export default {
  modules: ['@nuxt/content'],

  content: {
    markdown: {
      async highlighter() {
        const highlighter = await createShikiHighlighter({
          // Complete themes: https://github.com/shikijs/shiki/tree/main/packages/shiki/themes
          theme: 'nord'
        })
        return (rawCode, lang) => {
          const twoslashResults = runTwoSlash(rawCode, lang)
          return renderCodeToHTML(
            twoslashResults.code,
            lang,
            ['twoslash'],
            {},
            highlighter,
            twoslashResults
          )
        }
      }
    }
  }
}

Remark 插件

Nuxt 内容在幕后使用 remark 来处理 markdown 文档。 创建 remark 插件是操作文档并添加新功能的一种方式。

列出所有贡献者

假设您要在一个文档中列出项目的贡献者。 您可以创建一个插件,该插件获取所有贡献者并将它们注入到文档数据中。

  • 创建插件。 如果 fetchContributors 设置为 true,则此插件将获取贡献者
~~/plugins/contributors.js
const fetch = require('node-fetch')

module.exports = function () {
  return async (tree, { data }) => {
    if (data.fetchContributors) {
      const contributors = await fetch(
        'https://api.github.com/repos/nuxt/content/contributors'
      ).then(res => res.json())
      .then(res => res.map(({ login }) => login))

      data.$contributors = [...new Set(contributors)]
    }
    return tree
  }
}
  • 在 Nuxt 配置中注册插件
nuxt.config.js
export default {
  contents: {
    markdown: {
      remarkPlugins: [
        '~~/plugins/contributors.js'
      ]
    }
  }
}
  • 创建一个简单的组件来显示贡献者
~~/components/List.vue
<template>
  <ul>
    <li v-for="(item, i) in items" :key="i">
      {{ item }}
    </li>
  </ul>
</template>

<script>
export default {
  props: {
    items: {
      type: Array,
      default: () => []
    }
  }
}
  • 最后,使用这些组件并标记文档以获取贡献者
document.md
---
title: Nuxt Content
fetchContributors: true
---

## Contributors

<list :items="$contributors"></list>