feat:增加博客统计组件

This commit is contained in:
2025-12-15 19:53:21 +08:00
parent cbcc48d457
commit 7dfd151119
32 changed files with 1418 additions and 18 deletions

View File

@@ -0,0 +1,66 @@
<script lang="ts" setup>
import { computed, ref, onMounted } from 'vue'
import { countWord } from '../utils/functions'
const wordCount = ref(0)
const imageCount = ref(0)
const wordTime = computed(() => {
return ((wordCount.value / 275) * 60)
})
const imageTime = computed(() => {
const n = imageCount.value
if (imageCount.value <= 10) {
// 等差数列求和
return n * 13 + (n * (n - 1)) / 2
}
return 175 + (n - 10) * 3
})
// 阅读时间
const readTime = computed(() => {
return Math.ceil((wordTime.value + imageTime.value) / 60)
})
function analyze() {
document.querySelectorAll('.meta-des').forEach(v => v.remove())
const docDomContainer = window.document.querySelector('#VPContent')
const imgs = docDomContainer?.querySelectorAll<HTMLImageElement>(
'.content-container .main img'
)
imageCount.value = imgs?.length || 0
const words = docDomContainer?.querySelector('.content-container .main')?.textContent || ''
wordCount.value = countWord(words)
}
onMounted(() => {
// 初始化时执行一次
analyze()
})
</script>
<template>
<div class="word">
<p>
<svg t="1724571760788" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6125" width="16" height="16"><path d="M204.8 0h477.866667l273.066666 273.066667v614.4c0 75.093333-61.44 136.533333-136.533333 136.533333H204.8c-75.093333 0-136.533333-61.44-136.533333-136.533333V136.533333C68.266667 61.44 129.706667 0 204.8 0z m307.2 607.573333l68.266667 191.146667c13.653333 27.306667 54.613333 27.306667 61.44 0l102.4-273.066667c6.826667-20.48 0-34.133333-20.48-40.96s-34.133333 0-40.96 13.653334l-68.266667 191.146666-68.266667-191.146666c-13.653333-27.306667-54.613333-27.306667-68.266666 0l-68.266667 191.146666-68.266667-191.146666c-6.826667-13.653333-27.306667-27.306667-47.786666-20.48s-27.306667 27.306667-20.48 47.786666l102.4 273.066667c13.653333 27.306667 54.613333 27.306667 61.44 0l75.093333-191.146667z" fill="#1890FF" p-id="6126"></path><path d="M682.666667 0l273.066666 273.066667h-204.8c-40.96 0-68.266667-27.306667-68.266666-68.266667V0z" fill="#52C41A" p-id="6127"></path></svg>
字数: {{ wordCount }}
<svg t="1724572797268" class="icon" viewBox="0 0 1060 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15031" width="16" height="16"><path d="M556.726857 0.256A493.933714 493.933714 0 0 0 121.929143 258.998857L0 135.021714v350.390857h344.649143L196.205714 334.482286a406.820571 406.820571 0 1 1-15.908571 312.649143H68.937143A505.819429 505.819429 0 1 0 556.726857 0.256z m-79.542857 269.531429v274.907428l249.197714 150.966857 42.422857-70.070857-212.114285-129.389714V269.787429h-79.542857z" fill="#FA8C16" p-id="15032"></path></svg>
时长: {{ readTime }} 分钟
</p>
</div>
</template>
<style>
.word {
color: var(--vp-c-text-2);
font-size: 15px;
}
.icon {
display: inline-block;
transform: translate(0px , 2px);
}
</style>

View File

@@ -1,5 +1,6 @@
import DefaultTheme from 'vitepress/theme'
import Confetti from "./components/Confetti.vue";
import ArticleMetadata from "./components/ArticleMetadata.vue"
import type { EnhanceAppContext } from 'vitepress'
import { onMounted, watch, nextTick } from 'vue'
import { useRoute } from 'vitepress'
@@ -27,5 +28,6 @@ export default {
},
enhanceApp({ app }: EnhanceAppContext) {
app.component("Confetti", Confetti);
app.component("ArticleMetadata", ArticleMetadata);
},
};

View File

@@ -0,0 +1,19 @@
const pattern
= /[a-zA-Z0-9_\u0392-\u03C9\u00C0-\u00FF\u0600-\u06FF\u0400-\u04FF]+|[\u4E00-\u9FFF\u3400-\u4DBF\uF900-\uFAFF\u3040-\u309F\uAC00-\uD7AF]+/g
export function countWord(data: string) {
const m = data.match(pattern)
let count = 0
if (!m) {
return 0
}
for (let i = 0; i < m.length; i += 1) {
if (m[i].charCodeAt(0) >= 0x4E00) {
count += m[i].length
}
else {
count += 1
}
}
return count
}