Skip to content

如何在 VitePress 中整合 Giscus 评论系统

1. 在 Github 上配置 Giscus

首先,按照 giscus.app 上的说明安装与配置 Giscus 并获取关键参数,如:data-repo、data-repo-id、data-category、data-category-id 等...

2. 代码实现

接下来,创建一个新的 components/Comments.vue 组件并配置你的 Layout.vue。以下是代码:

components/Comments.vue

vue
<template>
<div :key="title" class="giscus">
    <component
        :is="'script'"
        src="https://giscus.app/client.js"
        data-repo="..."
        data-repo-id="..."
        data-category="..."
        data-category-id=""
        data-mapping="pathname"
        data-strict="0"
        data-reactions-enabled="1"
        data-emit-metadata="0"
        data-input-position="top"
        data-theme="light_high_contrast"
        data-lang="zh-CN"
        data-loading="lazy"
        crossorigin="anonymous"
        async
    />
</div>
</template>

<script setup>
import { useData } from 'vitepress'

const { frontmatter, title } = useData()
</script>

<style scoped>
.giscus {
    margin-top: 2rem;
}
</style>

Layout.vue

vue
<template>
  <div class="theme-container">
    <Layout>
      <template #doc-after>
        <Comments />
      </template>
    </Layout>
  </div>
</template>

<script setup>
import DefaultTheme from 'vitepress/theme'
import Comments from './components/Comments.vue'

const { Layout } = DefaultTheme
</script>

使用 VitePress 内置的 Layout 插槽在所有文档布局页面下方注入 Giscus 评论区,这是一个不错的选择。需要注意以下几点:

  • Vue 不能在模板中直接使用 <script /> 标签,所以我们使用 <component /> 来模拟实现 <script /> 标签。
  • :key 属性是必需的;否则,由于 "Vue 组件复用策略",在页面路由变化时可能会遇到评论区不重新加载的问题。
  • <div class="giscus" /> 用于让 Giscus 正确放置评论区。这确保了当 :key 发生变化时,DOM 中的 Giscus 评论区能够正确更新。
  • :key 属性不应该放在 <component /> 上,因为 <script /> 标签并不代表 Giscus 评论区对应的实际 DOM。将 :key 放在 <script /> 标签上是没有意义的。

你可能会在浏览器控制台看到一个警告和一个错误,提示"未找到相关讨论内容"。这是 Giscus 的预期行为,当你添加第一条评论或反应后创建讨论主题,这个提示就会自动消失。

3. 在特定页面移除 Giscus 评论区

虽然你可以通过锁定讨论功能来禁用评论,但为了更好的页面设计,你可能想要在某些页面完全隐藏 Giscus 评论区。

要实现这一点,在特定页面中添加 frontmatter

---
comments: false
---

然后,按如下方式修改现有代码:

vue
<template>
<div v-if="frontmatter.comments !== false" :key="title" class="giscus">
    <component ...... ...... />
</div>
</template>

<script setup>
import { useData } from 'vitepress'

const { frontmatter, title } = useData()
</script>

<style scoped>
.giscus {
    margin-top: 2rem;
}
</style>

基于之前讨论过的原因,不要将 v-if 放在 <component /> 上,这样做不会生效。