第三方评论系统
存在许多第三方评论系统,下面简要介绍下各评论系统集成方式。
Waline
Waline 是一个依赖服务端实现的评论系统,它可以托管在 Vercel 等平台上。
使用 valaxy-addon-waline 集成。
valaxy-addon-waline 是基于 Waline 的一个 Valaxy 插件。 除此之外,我们推荐您可以使用 kotodama 进行评论管理,它是一个基于 Waline 服务端实现的评论管理系统。
安装
bash
npm i valaxy-addon-waline
# pnpm add valaxy-addon-walinets
import { defineValaxyConfig } from 'valaxy'
import { addonWaline } from 'valaxy-addon-waline'
export default defineValaxyConfig({
// or write it in site.config.ts
siteConfig: {
// 启用评论
comment: {
enable: true
},
},
// 设置 valaxy-addon-waline 配置项
addons: [
addonWaline({
// Waline 配置项,参考 https://waline.js.org/reference/client/props.html
serverURL: 'https://your-waline-url',
}),
],
})Utterances
Utterances 是一个基于 GitHub Issues 实现的评论系统。
它可以直接通过挂载 JS 脚本集成。
在博客根目录下新建 App.vue,添加挂载脚本:
vue
<!-- You can mount anything here -->
<script lang="ts" setup>
import { useUtterances } from './composables/use-utterances'
useUtterances({
/**
* use your repo
*/
repo: 'YunYouJun/valaxy',
issueTerm: 'pathname',
label: 'utterances',
})
</script>
<template>
<!-- try it -->
<div />
</template>ts
import { isClient } from '@vueuse/core'
import { onContentUpdated, useAppStore } from 'valaxy'
import { nextTick, onBeforeUnmount, watch } from 'vue'
import { useRoute } from 'vue-router'
const utterancesClientSrc = 'https://utteranc.es/client.js'
/**
* @see https://utteranc.es/
*/
export function useUtterances(options: {
repo: string
issueTerm: 'pathname' | 'title'
label: string
}) {
// Guard: only run on client side
if (!isClient) {
return
}
const app = useAppStore()
const route = useRoute()
let script: HTMLScriptElement | undefined
let mountedContainer: Element | null = null
let mountedKey = ''
let contentPath: string | undefined
let disposed = false
function cleanup() {
script?.remove()
mountedContainer?.querySelector('.utterances')?.remove()
script = undefined
mountedContainer = null
mountedKey = ''
}
/**
* mount utterances
* @see https://utteranc.es/
*/
function createUtterancesScript() {
if (disposed || contentPath !== route.path)
return
const commentContainer = document.querySelector('.comment')
const key = `${route.path}:${app.isDark}`
// Content updates (for example a language change) must not reload the same iframe.
if (commentContainer === mountedContainer && key === mountedKey)
return
cleanup()
if (!commentContainer)
return
script = document.createElement('script')
script.src = utterancesClientSrc
script.async = true
script.crossOrigin = 'anonymous'
script.setAttribute('repo', options.repo)
script.setAttribute('issue-term', options.issueTerm)
script.setAttribute('label', options.label)
script.setAttribute('theme', app.isDark ? 'github-dark' : 'github-light')
commentContainer.appendChild(script)
mountedContainer = commentContainer
mountedKey = key
}
function scheduleMount() {
nextTick(createUtterancesScript)
}
// UserApp can mount before the async route hydrates. Wait for its Markdown
// content, then finish that render before inserting third-party DOM.
onContentUpdated(() => {
contentPath = route.path
scheduleMount()
})
watch(() => app.isDark, scheduleMount, { flush: 'post' })
watch(() => route.path, () => {
contentPath = undefined
cleanup()
})
onBeforeUnmount(() => {
disposed = true
cleanup()
})
}