重构 ReadingTime.vue 和 config.ts 以获取更准确的文档字数 (#414)

pull/419/head^2
Lee 2024-09-17 01:23:57 +08:00 committed by GitHub
parent fba943a25f
commit 54adc5e64c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 58 additions and 52 deletions

View File

@ -1,62 +1,22 @@
<script setup lang="ts">
import { useRoute } from 'vitepress'
import { nextTick, ref, watch } from 'vue'
import { useData } from 'vitepress'
//
const route = useRoute()
//
const { frontmatter } = useData()
//
const wordCount = ref(0)
const readingTime = ref(0)
const componentKey = ref(0) // key
const isLoaded = ref(false) //
//
function calculateReadingTime(content: string) {
//
function calculateReadingTime(wordCount: number) {
const wordsPerMinute = 500 // 500
// 77
const wordCountOffset = 77
const chineseText = content.replace(/<[^>]*>|[^\u4E00-\u9FA5]/g, '') // HTML
const wordCount = chineseText.length - wordCountOffset //
const readingTime = Math.ceil(wordCount / wordsPerMinute) //
return { wordCount, readingTime }
return Math.ceil(wordCount / wordsPerMinute) //
}
//
function updateReadingTime() {
const contentElement = document.querySelector('.VPContent') // DOM
if (contentElement) {
const content = contentElement.textContent || '' //
const { wordCount: wc, readingTime: rt } = calculateReadingTime(content)
wordCount.value = wc
readingTime.value = rt
}
}
//
function initialize() {
isLoaded.value = false //
componentKey.value += 1
nextTick().then(() => {
updateReadingTime()
isLoaded.value = true //
})
}
//
watch(
route,
() => {
initialize()
},
{ immediate: true },
)
// frontmatter
const wordCount = frontmatter.value.wordCount || 0
const readingTime = calculateReadingTime(wordCount)
</script>
<template>
<div v-if="isLoaded" :key="componentKey">
<div>
<p>字数: {{ wordCount }} &nbsp; 预计阅读时间: {{ readingTime }} 分钟</p>
</div>
</template>

View File

@ -17,6 +17,34 @@ import { defineConfig } from 'vitepress'
import { generateSidebar } from './sidebar'
import { useThemeContext } from './utils/themeContext'
import fs from 'fs';
import path from 'path';
// 从文件系统读取 Markdown 文件内容
function readMarkdownFileContent(filePath: string): string {
if (fs.existsSync(filePath)) {
return fs.readFileSync(filePath, 'utf-8');
}
return '';
}
// 统计文档的字数函数
function countWords(content: string): number {
const cleanedContent = content
.replace(/```[\s\S]*?```/g, '') // 移除代码块
.replace(/!\[.*?\]\(.*?\)/g, '') // 移除图片链接
.replace(/\[.*?\]\(.*?\)/g, '') // 移除普通链接
.replace(/<\/?[^>]+(>|$)/g, '') // 移除 HTML 标签
.replace(/[.,\/#!$%\^&\*;:{}=\-_`~()]/g, '') // 移除标点符号
.replace(/\s+/g, ' ') // 将多余的空格归为一个空格
.trim(); // 去除首尾空格
const chineseCharacters = cleanedContent.match(/[\u4e00-\u9fff\uff01-\uffe5]/g) || [];
const words = cleanedContent.split(/\s+/).filter(Boolean);
return chineseCharacters.length + words.length;
}
// https://vitepress.dev/reference/site-config
function genConfig() {
const themeConfig = useThemeContext()
@ -196,7 +224,25 @@ function genConfig() {
],
},
},
})
transformPageData(pageData) {
// 构建 Markdown 文件路径
const markdownFile = `${pageData.relativePath}`;
const filePath = path.join(process.cwd(), 'docs', markdownFile);
// 从文件系统读取文件内容
const content = readMarkdownFileContent(filePath);
// 统计字数并插入到 Frontmatter
const wordCount = countWords(content);
return {
frontmatter: {
...pageData.frontmatter,
wordCount, // 将字数写入 Frontmatter
},
};
},
});
}
export default genConfig
export default genConfig;