vitepress静态网站添加访问量统计

一、网站访问统计插件

目前我使用到的访问统计插件有两个,一个是 不蒜子 busuanzi ,另一个是我目前使用的 Vercount

二、两个插件使用感受

  • 不蒜子大部分人都很推荐使用,但是它有些缺点:

    1. 使用的人太多的时候,会出现502错误。
    2. 不蒜子的代码已经过时,使用的是 Referrer 方法进行统计,这种方法在移动端 / Firefox / Safari 上统计不准确。
    3. 不蒜子的代码使用的是 JSONP 回调,这种方法容易受到 CSRF 攻击威胁网站安全,详情请看:JSONP
  • Vercount 优化了不蒜子的缺点,并且支持自托管。但它也有一些小缺点:

    1. 刷新页面后,会先显示之前的缓存数据,再从接口拉取新数据更新到界面上,观感上会有点怪。
    2. 统计单文章页面访问量,切换页面后,会在 span 中先显示上一个页面的访问数据,再刷新到本页面的访问数据。

这个小缺点 Vercount 提供了解决方法了,可以往下看 六、Vercount优化

三、插件说明

对于静态网页来说,两款插件调用的方法都特别的简单,只需要两步:

  1. 在每一个页面引入一个 script 标签;
  2. 在页面中的某个 span 绑定id标签显示。

script 标签需要在网站的每个页面都添加 (无需都显示),否则计数器可能会丢失这些未添加页面的访问计数。

busuanzi id 标签说明:

  • busuanzi_container_site_uv 的作用是为防止计数服务访问出错或超时(3秒)的情况下,使整个标签自动隐藏显示,带来更好的体验。这个id可以省略。
  • busuanzi_value_site_pv 的作用是异步回填访问数,这个id一定要正确。
  • busuanzi_container_site_pv:_site_pv 包裹容器
  • busuanzi_container_site_uv:_site_uv 包裹容器
  • busuanzi_container_page_pv: _page_pv 包裹容器

包裹容器可以添加样式 style='display:none' 不蒜子执行完毕会自动修改样式将标签显示出来。

  • busuanzi_value_site_pv:本站总访问量
  • busuanzi_value_site_uv:本站总访客数
  • busuanzi_value_page_pv: 本文总阅读量

Vercount 兼容 busuanzi 的 id 标签写法,也可以把前缀 'busuanzi_' 替换成 'vercount_'

html 复制代码
<!-- busuanzi:busuanzi_container_site_pv 可省略 -->
<span id="busuanzi_container_site_pv">
  本站总访问量<span id="busuanzi_value_site_pv"></span>次
</span>
<!-- Vercount -->
<span>
  本站总访问量<span id="vercount_value_site_pv">Loading</span>次
</span>

四、在 vitepress 项目中使用插件

一般静态网站项目只需要在 html 的 head 中引入 script 标签即可,但是 vitepress 项目实际是比较特殊的 单页应用程序,切换页面并不会触发整个页面的刷新,不会再次触发 script 重载。

ts 复制代码
// 错误例子
export default defineConfig({
  lang: 'zh-Hans',
  title: 'My Awesome Project',
  description: 'A VitePress Site',
  lastUpdated: true,
  // 这里配置只会首次触发span能看到数据,切换路由后,数据便丢失了,除非重新刷新整个页面。
  head: [
    ['script',{defer: '',async: '',src: 'https://cn.vercount.one/js'}]
  ],
})

以上这个做法是不可行的,所以需要在路由中做手脚。为了简化代码操作,利用 hooks 是很方便的方式。

1. 编写一个调用访问量接口的hooks

编写这个 hooks 的作用是,利用 document 创建一个 script 标签,并利用 script 标签调用 url 。

创建一个 useVisitData.ts 文件,复制下面的代码:

ts 复制代码
// useVisitData.ts
/**
 * 网站访问量统计 hooks
 */
function useVisitData() {
  const script = document.createElement('script')
  script.defer = true
  script.async = true
  // 调用 Vercount 接口
  script.src = 'https://cn.vercount.one/js'
  // 调用 不蒜子 接口
  // script.src = '//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js'
  document.head.appendChild(script)
}

export default useVisitData

其实也不算hooks,不要介意这个写法

2. 在路由中调用hooks

场景一:如果希望做一个全站的访问统计,每个页面跳转都要计算到总访问量中去

javascript需要在网站的每个页面都添加 (无需都显示),否则计数器可能会丢失这些未添加页面的访问计数。

在 viepress 路由守卫中调用 hooks,在.vitepress/theme/index.ts 中添加如下代码:

ts 复制代码
// .vitepress/theme/index.ts
import type { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'

import { inBrowser } from 'vitepress'
// 导入hooks
import useVisitData from '../../hooks/useVisitData'

export default {
  extends: DefaultTheme,
  enhanceApp({ app, router, siteData }) {
    if (inBrowser) {
      // 路由加载完成,在加载页面组件后(在更新页面组件之前)调用。
      router.onAfterPageLoad = (to: string) => {
        // 调用统计访问接口hooks
        useVisitData()
      }
    }
  }
} satisfies Theme
场景二:如果希望某些子路由不想统计到总访问量中,或只想个别些页面统计到总访问量中

直接在上面代码添加一个 ignoreList 或者 whiteList ,利用参数 to 判断路由路径即可:

ts 复制代码
// .vitepress/theme/index.ts
import type { Theme } from 'vitepress'
import DefaultTheme from 'vitepress/theme'

import { inBrowser } from 'vitepress'
// 导入hooks
import useVisitData from '../../hooks/useVisitData'
// 忽略名单
let ignoreList = ['/a', '/b']

export default {
  extends: DefaultTheme,
  enhanceApp({ app, router, siteData }) {
    if (inBrowser) {
      router.onAfterPageLoad = (to: string) => {
        // 某些页面不计入总访问量中
        if (!ignoreList.includes(to)) {
          useVisitData()
        }
      }
    }
  }
} satisfies Theme

至此,你可以在任何页面(除了忽略名单页面),插入最简单的 span,就可以显示统计数字了:

vue 复制代码
<!-- 使用 vercount 就将 busuanzi_value_page_pv 替换成 vercount_value_page_pv -->
<span>
  本文总阅读量 <span id="busuanzi_value_page_pv">Loading</span> 次
</span>

3. 编写一个漂亮的统计访问数据的组件

Vercount 是兼容 busuanzi 的 span 的 id 标签的,也可以将前缀替换成 vercount_

但是为了统一和后续功能扩展需要,各自用自己的 id 标签比较好。组件例子如下:

vue 复制代码
// DataPanel.vue
<template>
  <!-- busuanzi用法 -->
  <div class="text" id="busuanzi_container_site_pv">
    <div>本站总访问量</div>
    <span id="busuanzi_value_site_pv" class="font-bold">--</span>次
  </div>
  <div class="text" id="busuanzi_container_site_uv">
    <div>本站访客数</div>
    <span id="busuanzi_value_site_uv" class="font-bold">--</span>人次
  </div>

  <!-- Vercount用法 -->
  <div class="text">
    <div>本站总访问量</div>
    <span id="vercount_value_site_pv" class="font-bold">--</span>次
  </div>
  <div class="text">
    <div>本站访客数</div>
    <span id="vercount_value_site_uv" class="font-bold">--</span>人次
  </div>
</template>

4. 导入组件

在你想要展示的界面中导入组件,例如在首页 index.md 中导入组件,添加根级 <script> 标签

md 复制代码
# index.md
---
layout: home

hero:
  name: 'Demo'
features:
  - title: Feature A
    details: Lorem ipsum dolor sit amet, consectetur adipiscing elit
---
# 访问数据组件
<DataPanel />

<script setup lang="ts">
// 导入访问数据组件
import DataPanel from '../components/home/DataPanel.vue'
</script>

现在,刷新界面就可以看到统计数字的变化了。

如果没有部署项目,看到的数字会很大,只需要部署项目后,统计数据就变正常了。

五、 不蒜子 busuanzi.pure.js 插件问题

使用这个插件,如果按照以下配置,会导致刷新页面后统计两次访问量的问题。这个方式可以弃用了。

安装 busuanzi.pure.js 插件:

npm 复制代码
npm install busuanzi.pure.js

.vitepress/theme/index.ts 中调用插件:

ts 复制代码
// .vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme'
// 导入 busuanzi
import { inBrowser } from 'vitepress'
import busuanzi from 'busuanzi.pure.js'

export default {
  extends: DefaultTheme,

  enhanceApp({ app , router }) {
    // 调用接口
    if (inBrowser) {
      router.onAfterRouteChanged = () => {
        busuanzi.fetch()
      }
    }
  },
}

这个方式弃用吧。

六、Vercount优化

看到这的时候,还记得最开始我说的 Vercount 的小缺点吗?

  1. 刷新页面后,会先显示之前的缓存数据,再从接口拉取新数据更新到界面上,观感上会有点怪。
  2. 统计单文章页面访问量,切换页面后,会在 span 中先显示上一个页面的访问数据,再更新到本页面的访问数据。

解决办法:

在含有 id 标签 id="vercount_container_site_pv" 的容器添加 style 属性:style="display: none",直到正确获取数据后会自动显示出来。例子如下:

vue 复制代码
<span id="vercount_container_site_pv" style="display: none">
  本站总访问量<span id="vercount_value_site_pv"></span>次
</span>

修改 DataPanel.vue 组件里的代码:

vue 复制代码
// DataPanel.vue
<template>
  <!-- busuanzi用法 -->
  <div class="text" id="busuanzi_container_site_pv" style="display: none">
    <div>本站总访问量</div>
    <span id="busuanzi_value_site_pv" class="font-bold">--</span>次
  </div>
  <div class="text" id="busuanzi_container_site_uv" style="display: none">
    <div>本站访客数</div>
    <span id="busuanzi_value_site_uv" class="font-bold">--</span>人次
  </div>

  <!-- Vercount用法 -->
  <div class="text" id="vercount_container_site_pv" style="display: none">
    <div>本站总访问量</div>
    <span id="vercount_value_site_pv" class="font-bold">--</span>次
  </div>
  <div class="text" id="vercount_container_site_pv" style="display: none">
    <div>本站访客数</div>
    <span id="vercount_value_site_uv" class="font-bold">--</span>人次
  </div>
</template>

不蒜子也有这个优化功能哦!不蒜子本身数字观感优化还是可以的,加不加看自己的需求吧。

相关推荐
码界领航5 分钟前
【2025最新版】Chrome谷歌浏览器如何能恢复到之前的旧版本
前端·chrome
乐多_L1 小时前
使用vue3框架vue-next-admin导出表格excel(带图片)
前端·javascript·vue.js
南望无一1 小时前
React Native 0.70.x如何从本地安卓源码(ReactAndroid)构建
前端·react native
Mike_188702783511 小时前
1688代采下单API接口使用指南:实现商品采集与自动化下单
前端·python·自动化
鲨鱼辣椒️面1 小时前
HTML视口动画
前端·html
一小路一1 小时前
Go Web 开发基础:从入门到实战
服务器·前端·后端·面试·golang
堇舟1 小时前
HTML第一节
前端·html
纯粹要努力1 小时前
前端跨域问题及解决方案
前端·javascript·面试
小刘不知道叫啥1 小时前
React源码揭秘 | 启动入口
前端·react.js·前端框架
kidding7232 小时前
uniapp引入uview组件库(可以引用多个组件)
前端·前端框架·uni-app·uview