重构 ReadingTime.vue 和 config.ts 以获取更准确的文档字数 (#414)
parent
fba943a25f
commit
54adc5e64c
|
@ -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 }} 预计阅读时间: {{ readingTime }} 分钟</p>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue