VuePress 生态系统VuePress 生态系统
  • 主题指南
  • 默认主题
  • Hope 主题
  • Plume 主题
  • Reco 主题
  • 功能插件
  • Markdown 插件
  • 搜索插件
  • 博客插件
  • 渐进式应用插件
  • 统计分析插件
  • 搜索引擎优化插件
  • 开发插件
  • 工具插件
  • AI 插件
  • @vuepress/helper
  • English
  • 简体中文
GitHub
  • 主题指南
  • 默认主题
  • Hope 主题
  • Plume 主题
  • Reco 主题
  • 功能插件
  • Markdown 插件
  • 搜索插件
  • 博客插件
  • 渐进式应用插件
  • 统计分析插件
  • 搜索引擎优化插件
  • 开发插件
  • 工具插件
  • AI 插件
  • @vuepress/helper
  • English
  • 简体中文
GitHub
  • 博客
    • 指南
    • 配置
  • 评论
    • 指南
    • Giscus
    • Waline
    • Artalk
    • Twikoo
  • Feed
    • 指南
    • 插件配置
    • Frontmatter 配置
    • 频道配置
    • Feed 获取器

指南

为 VuePress 主题赋予博客功能,包含文章收集、分类和摘要生成。

文章收集

插件使用 filter 选项来决定哪些页面应被视为文章。

提示

默认情况下,除主页外,所有从 Markdown 文件生成的页面都被视为文章。

收集信息

使用 getInfo 选项定义一个函数,用于从页面中提取文章元数据。

插件会将收集到的信息注入 routeMeta 字段,使其可以通过组合式 API (Composition API) 访问。

示例
主题入口
import { blogPlugin } from '@vuepress/plugin-blog'

export default {
  name: 'vuepress-theme-xxx',
  plugins: [
    blogPlugin({
      filter: ({ filePathRelative, frontmatter }) => {
        // 排除非文件生成的页面
        if (!filePathRelative) return false

        // 排除 `archives` 目录下的页面
        if (filePathRelative.startsWith('archives/')) return false

        // 排除未使用默认布局的页面
        if (frontmatter.home || frontmatter.layout) return false

        return true
      },

      getInfo: ({ frontmatter, title, git = {}, data = {} }) => {
        // 提取页面信息
        const info: Record<string, unknown> = {
          title,
          author: frontmatter.author || '',
          categories: frontmatter.categories || [],
          date: frontmatter.date || git.createdTime || null,
          tags: frontmatter.tags || [],
          excerpt: data.excerpt || '',
        }

        return info
      },
    }),
    // 其他插件 ...
  ],
}

自定义分类与类型 (Customizing Categories and Types)

本插件允许你将文章组织成两种主要的集合类型:

  • Category (分类):基于标签(如“标签”、“分类”)对文章进行分组。
  • Type (类型):基于特定条件筛选文章(如“日记”条目、“星标”文章)。

你可以使用 category 和 type 数组选项进行配置。

Category 配置

使用 category 选项创建基于标签的分组。

例如,如果你想根据 Frontmatter 中定义的 tags 对文章进行分组,在 /tag/ 生成一个映射页面(使用 TagMap 布局),并在 /tag/:tagName 列出特定标签的文章(使用 TagList 布局),你可以使用以下配置:

主题入口
import { blogPlugin } from '@vuepress/plugin-blog'

export default {
  name: 'vuepress-theme-xxx',
  plugins: [
    blogPlugin({
      // 其他选项 ...
      category: [
        {
          key: 'tag',
          getter: ({ frontmatter }) => frontmatter.tag || [],
          path: '/tag/',
          layout: 'TagMap',
          frontmatter: () => ({ title: '标签页' }),
          itemPath: '/tag/:name/',
          itemLayout: 'TagList',
          itemFrontmatter: (name) => ({ title: `标签 ${name}` }),
        },
      ],
    }),
    // 其他插件 ...
  ],
}

Type 配置

使用 type 选项创建特定的集合列表。

例如,要在 /star/ 路径下使用 StarList 布局显示“星标”文章列表(在 Frontmatter 中标记为 star: true):

主题入口
import { blogPlugin } from '@vuepress/plugin-blog'

export default {
  name: 'vuepress-theme-xxx',
  plugins: [
    blogPlugin({
      // 其他选项 ...
      type: [
        {
          key: 'star',
          filter: ({ frontmatter }) => frontmatter.star,
          path: '/star/',
          layout: 'StarList',
          frontmatter: () => ({ title: '星标页面' }),
        },
      ],
    }),
    // 其他插件 ...
  ],
}

如需完整的选项列表,请参阅 Category 配置 和 Type 配置。

在客户端使用组合式 API

在页面生成过程中,插件会将以下信息注入到 frontmatter.blog 中:

interface BlogFrontmatterOptions {
  /** 当前页面的类型 */
  type: 'category' | 'type'
  /** 当前分类或标签下的唯一 key */
  key: string
  /**
   * 当前分类名称
   *
   * @description 仅在分类子项页面可用
   */
  name?: string
}

你可以使用 useBlogCategory() 和 useBlogType() 钩子来获取绑定到当前路由的数据。或者,你可以传递一个特定的 key 作为参数来检索与该 key 相关的数据。

基于上面的配置示例,以下是如何在客户端获取标签和星标信息的方法:

TagMap 布局:

<script setup lang="ts">
import { useBlogCategory } from '@vuepress/plugin-blog/client'
import { RouteLink } from 'vuepress/client'

const categoryMap = useBlogCategory('tag')
</script>

<template>
  <div>
    <h1>标签页</h1>
    <ul>
      <li v-for="({ items, path }, name) in categoryMap.map" :key="path">
        <RouteLink :key="name" :to="path" class="category">
          {{ name }}
          <span class="category-num">
            {{ items.length }}
          </span>
        </RouteLink>
      </li>
    </ul>
  </div>
</template>

TagList 布局:

<script setup lang="ts">
import { useBlogCategory } from '@vuepress/plugin-blog/client'
import { RouteLink } from 'vuepress/client'

const categoryMap = useBlogCategory('tag')
</script>

<template>
  <div>
    <h1>标签页</h1>
    <div class="category-wrapper">
      <RouteLink
        v-for="({ items, path }, name) in categoryMap.map"
        :key="name"
        :to="path"
        class="category"
      >
        {{ name }}
        <span class="category-num">
          {{ items.length }}
        </span>
      </RouteLink>
    </div>
    <div v-if="categoryMap.currentItems" class="article-wrapper">
      <div v-if="!categoryMap.currentItems.length">这里没有文章。</div>
      <article
        v-for="{ info, path } in categoryMap.currentItems"
        :key="path"
        class="article"
        @click="$router.push(path)"
      >
        <header class="title">
          {{ info.title }}
        </header>
        <hr />
        <div class="article-info">
          <span v-if="info.author" class="author">作者: {{ info.author }}</span>
          <span v-if="info.date" class="date"
            >日期: {{ new Date(info.date).toLocaleDateString() }}</span
          >
          <span v-if="info.category" class="category"
            >分类: {{ info.category.join(', ') }}</span
          >
          <span v-if="info.tag" class="tag"
            >标签: {{ info.tag.join(', ') }}</span
          >
        </div>
        <div v-if="info.excerpt" class="excerpt" v-html="info.excerpt" />
      </article>
    </div>
  </div>
</template>

StarList 布局:

<script setup lang="ts">
import { useBlogType } from '@vuepress/plugin-blog/client'
import ParentLayout from '@vuepress/theme-default/layouts/Layout.vue'

import ArticleList from '../components/ArticleList.vue'

const stars = useBlogType('star')
</script>

<template>
  <div v-if="stars.items?.length" class="article-wrapper">
    <article
      v-for="{ info, path } in stars.items"
      :key="path"
      class="article"
      @click="$router.push(path)"
    >
      <header class="title">
        {{ info.title }}
      </header>
      <hr />
      <div class="article-info">
        <span v-if="info.author" class="author">作者: {{ info.author }}</span>
        <span v-if="info.date" class="date"
          >日期: {{ new Date(info.date).toLocaleDateString() }}</span
        >
        <span v-if="info.category" class="category"
          >分类: {{ info.category.join(', ') }}</span
        >
        <span v-if="info.tag" class="tag">标签: {{ info.tag.join(', ') }}</span>
      </div>
      <div v-if="info.excerpt" class="excerpt" v-html="info.excerpt" />
    </article>
  </div>
  <div v-else>这里没有文章。</div>
</template>

关于返回类型详情,请参阅 组合式 API 返回类型。

国际化支持

本插件支持原生国际化。你的配置会自动应用于每个语言环境。

例如,如果你在配置中定义了以下语言环境:

.vuepress/config.ts
export default {
  locales: {
    '/': {
      lang: 'en-US',
    },
    '/zh/': {
      lang: 'zh-CN',
    },
  },
}

插件将自动生成 /zh/star/ 和 /star/。每个路径下只会显示属于对应语言环境的文章。

生成摘要

本插件包含一个内置的摘要生成器,通过设置 excerpt: true 启用。

摘要的限制

摘要是一个用于展示文章简短预览的 HTML 片段。请注意以下限制:

  • 语法支持:未知标签(包括 Vue 组件)和 Vue 特有的语法将在生成过程中被移除。若要保留自定义非 Vue 元素,请使用 isCustomElement 选项。
  • 资源引用:由于摘要是 HTML 片段,图片相对路径和别名将被移除。为确保图片在摘要中正确显示,请使用绝对路径(基于 .vuepress/public)或完整的 URL。

生成器优先使用分隔符来确定摘要。默认分隔符为 <!-- more -->,可以通过 excerptSeparator 选项进行自定义。

如果未找到有效的分隔符,生成器将提取文件开头的内容,直到达到指定长度(默认:300 个字符)。该长度可以通过 excerptLength 选项调整。

若要控制哪些页面需要生成摘要,请使用 excerptFilter 选项。

示例

你可能更倾向于在 frontmatter.description 存在时直接使用它作为摘要,你可以配置过滤函数,当 frontmatter.description 存在时返回 false,从而跳过这些页面的自动生成。

在 GitHub 上编辑此页
上次更新: 2025/11/29 04:46
贡献者: Mister-Hope, meteorlxy, pengzhanbo, Piotr Przetacznik
下一页
配置