vuepress+百度统计显示博客浏览量

开通百度统计

我是使用百度统计来统计浏览量的,首先要注册账号,如果有了也可以直接登陆。我用的账号的普通的百度账号,而不是营销账号。

登陆之后就能看到如下界面,并且点击使用设置:
请添加图片描述

点击之后进入设置页面,可以新建网站:
请添加图片描述

然后填入信息:
请添加图片描述

确定之后就能看到百度给的脚本了:
请添加图片描述

配置代码

按照他的教程,把脚本添加到我们的所有页面里面。由于使用vuepress构建后的是静态页面,切换页面也不会触发请求,所以我们需要在进去网站的时候就把这段脚本加上,而且在切换页面的时候也需要触发统计。

现在先把代码加到我们的页面中:
请添加图片描述

接下来添加 config 同级文件 enhanceApp.js,添加如下代码:

export default ({
     
      router }) => {
    
    
  // 路由切换事件处理
  router.beforeEach((to, from, next) => {
    
    
    //触发百度的pv统计
    if (typeof _hmt != "undefined") {
    
    
      if (to.path) {
    
    
        _hmt.push(["_trackPageview", to.fullPath]);
      }
    }
    next();
  });
};

然后等一段时间,大概20分钟,如果配置正确的话就能看到数据了!
请添加图片描述

那么接下来就是把数据引入到我们的网站里面了。我们可以阅读百度统计的文档来开通数据api,但是开通需要前一天网站的阅读量超过100才可以,所以目前我还开通不了,自己随便点点几下就好了,只能明天再继续了。

数据导出

– one day later –
今天可以开通数据导出服务了,开通后我们会获取到API Key与Secret Key,如下图:
请添加图片描述

注意图中的统计工具和文档,后面调试的时候需要用到。

然后我们点击 此文档 继续后面的操作。

首先利用 api key 去获取 code:

 http://openapi.baidu.com/oauth/2.0/authorize?response_type=code&client_id={CLIENT_ID}&redirect_uri=oob&scope=basic&display=popup

其中的CLIENT_ID就是api key。

获取到code之后,通过code、CLIENT_ID和Secret Key去获取 ACCESS_TOKEN,这个就是我们要调用接口的凭证了:

http://openapi.baidu.com/oauth/2.0/token?grant_type=authorization_code&code={CODE}&client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&redirect_uri=oob

返回结果如下:

{
    
    
    "expires_in": 2592000,
    "refresh_token":"2.385d55f8615fdfd9edb7c4b5ebdc3e39.604800.1293440400-2346678-124328",
    "access_token":"1.a6b7dbd428f731035f771b8d15063f61.86400.1292922000-2346678-124328",
    "session_secret":"ANXxSNjwQDugf8615OnqeikRMu2bKaXCdlLxn",
    "session_key":" 248APxvxjCZ0VEC43EYrvxqaK4oZExMB",
    "scope":"basic"
}

此外还有一个参数需要获取,那就是site_id,也就是我们网站的id,需要调用查询自己的网站列表api去获取:

https://openapi.baidu.com/rest/2.0/tongji/config/getSiteList?access_token=1.a6b7dbd428f731035f771b8d15063f61.86400.1292922000-2346678-124328

把其中的 access_token 换成你自己的。

返回的结果如下:

{
    
    
    "list": [
        {
    
    
            "site_id": 18957957,
            "domain": "xxx",
            "status": 0,
            "create_time": "2023-04-04 17:58:49",
            "sub_dir_list": []
        }
    ]
}

记住这个site_id。

然后我们回到刚开通数据导出服务的那个页面,点击api调试工具,来到调试界面,选择百度账号之后,填入自己的 access_token,选择获取报告数据,网站概况(趋势数据),最后再填入参数就OK啦。

这里我们简单试一下,查询一下浏览量:
请添加图片描述
点击提交之后,就会自动帮我们生成请求链接和响应结果:
请添加图片描述

我们就可以拿着这个链接放到我们的博客里啦。

然后我只能查出总的访问量,不能看到每个子页面的访问量,可能是我设置站点的时候有些地方出错了。但经过查阅用户手册,发现可以通过调用 受访页面 的接口来获取每个页面的访问量。

https://openapi.baidu.com/rest/2.0/tongji/report/getData?access_token=xxxxxxxx&site_id=xxxx&method=visit/toppage/a&start_date=20190101&end_date=20190105&metrics=pv_count,visitor_count

其实就是 method 不一样。

那么我们可以在之前的 enhanceApp.js 中请求访问量,代码如下:

import {
    
     getPV } from "../util/api";
export default ({
     
      router }) => {
    
    
  // 路由切换事件处理
  router.beforeEach((to, from, next) => {
    
    
    //触发百度的pv统计
    if (typeof _hmt != "undefined") {
    
    
      if (to.path) {
    
    
        _hmt.push(["_trackPageview", to.fullPath]);
        getPV().then(res => {
    
    
          if (res.error_code) {
    
    
            // Access token 过期了
          } else {
    
    
            const items = res.data.result.items || []
            const page = items[0] || [], vis = items[1] || []
            let pv = 0
            // 主页统计全部
            if(to.path == '/') {
    
    
              page.forEach((value, index) => {
    
    
                // 只统计该域名下的,因为开发的时候访问也会被计算这里分开统计
                if(value[0].name.indexOf(window.location.origin) > -1) {
    
    
                  pv += vis[index][0]
                }
              })
            } else {
    
    
              const pathUrl = window.location.origin + to.path
              for(let i = 0, n = page.length; i < n; i++) {
    
    
                if(page[i][0].name == pathUrl) {
    
    
                  pv = vis[i][0]
                  break
                }
              }
            }
            console.log(pv)
          }
        })
      }
    }
    next();
  });
};

展示浏览量

到这里已经只差最后一步了,那就是把浏览量展示到我们的主页还有每篇博客上面。因为我使用的主题是vuepress-theme-reco,所以需要在node_modules中找到主题的源代码,自己修改想要显示浏览量的位置。

例如在首页中,我希望把浏览量设置在底部备案的位置:
请添加图片描述

所以我们需要找到Footer组件,经过我的一番寻找,发现他在node_modules/vuepress-theme-reco/components下,我们直接把备案的那串代码注释掉,添加如下代码:

<!-- template -->
<span>
  <reco-icon icon="reco-eye" />
  <a>
    <span>{
   
   { pv }}</span>
  </a>
</span>

<!-- js -->
setup() {
  ...
  const pv = window.pv
  return { ..., pv}
}

然后重新启动项目,就能看到效果了:
请添加图片描述

接下来就是在博客文章的页面加上了,继续翻源码,还是在刚刚的component目录下,找到PageInfo,进去刚刚相同的操作就好了。但是发现他原本就有这一段代码:

<reco-icon
  v-if="showAccessNumber === true"
  icon="reco-eye"
>
  <AccessNumber :idVal="pageInfo.path" :numStyle="numStyle" />
</reco-icon>

也就是说官方是支持阅读量的,但通过查阅官方文档后,他们的这么解释的:

浏览量 仅在使用 Valine 时显示;

因为 浏览量 需要在页面加载时去调用相关接口,所以列表页的所有数据会一起加载下来,如果文章数量很多会影响加载速度,所以在 1.2.0 之后去掉文章列表的浏览量。

那我们也不用管了,直接使用百度的统计API就行。

修改之后可以看到如下效果:
请添加图片描述

调试

本以为大功告成了,没想到回到首页一看,寄,首页中文章列表也是用的这个组件,所以浏览量变成了首页的:
请添加图片描述

那么现在的问题是在首页的时候需要获取到各个页面的浏览量,这个好办,我们把之前pv变量设置成一个对象,把页面的url作为key,然后值为浏览量。稍微修改一下 enhanceApp.js 中相关的部分:

import {
    
     getPV } from "../util/api";
export default ({
     
      router }) => {
    
    
  // 路由切换事件处理
  router.beforeEach(async (to, from, next) => {
    
    
    //触发百度的pv统计
    if (typeof _hmt != "undefined") {
    
    
      if (to.path) {
    
    
        _hmt.push(["_trackPageview", to.fullPath]);
        await getPV().then(res => {
    
    
          let pv = {
    
    } // 修改为一个对象
          if (res.error_code) {
    
    
            // Access token 过期了
          } else {
    
    
            const items = res.data.result.items || []
            const page = items[0] || [], vis = items[1] || []
            const n = page.length
            // 首页把全部页面的浏览量添加进去
            if(to.path == '/') {
    
    
              let total = 0
              page.forEach((value, index) => {
    
    
                if(value[0].name.indexOf(window.location.origin) > -1) {
    
    
                  total += vis[index][0]
                }
              })
              pv['home'] = total
              for(let i = 0; i < n; i++) {
    
    
                pv[page[i][0].name] = vis[i][0]
              }
            } else {
    
    
              const pathUrl = window.location.origin + to.path
              for(let i = 0; i < n; i++) {
    
    
                if(page[i][0].name == pathUrl) {
    
    
                  pv[pathUrl] = vis[i][0] // 不是首页只添加自己的页面
                  break
                }
              }
            }
          }
          window.pv = pv
        })
      }
    }
    next();
  });
};

然后对应修改 Footer 组件和 PageInfo 组件的 pv 取值:

// Footer.vue
const pv = window.pv['home'] || 0

// PageInfo.vue
const pv = window.pv[window.location.origin + props.pageInfo.path] || 0

// 原本我还在想,首页中是如何知道每个PageInfo组件是属于哪一篇文章的呢,因为官方原本也有实现这个功能。结果打印props一看,好家伙,信息都在里面。
// 所以可以拿到这个 props.pageInfo.path,匹配到对应的页面就可以拿到浏览量了。

本以为真的没问题了,没想到一打包,报了一堆错误QAQ,发现是window is not defined。又是经过了一阵查找,发现没什么特别好的解决方法。只能综合网上的方法自己想一个了。

我们就是要个全局变量可以存储 pv 这个对象,那么可以把他挂在 Vue 实例上。但又有一个问题,我们在服务端获取不了当前的页面路径,使用 window.location.domain 也会报错。最后发现 enhanceApp.js 中可以接收一个变量 isServer,判断当前是否是服务端。那么只要不是在服务端,我们就能使用 window 了。

最终修改代码如下:

// enhanceApp.js
import { getPV } from "../util/api";
import Vue from 'vue'
export default ({ router, isServer }) => {
  // 路由切换事件处理
  router.beforeEach(async (to, from, next) => {
    Vue.prototype.isServer = isServer
    //触发百度的pv统计
    if (typeof _hmt != "undefined") {
      // 这里稍微修改了一下,因为被编译成html了,hash值改变就不再重复添加了
      if (to.path && (to.path == '/' || to.path != from.path)) {
        _hmt.push(["_trackPageview", to.path]);
        await getPV().then(res => {
          let pv = {}
          if (res.error_code) {
            // Access token 过期了
          } else {
            const items = res.data.result.items || []
            const page = items[0] || [], vis = items[1] || []
            const n = page.length
            if(to.path == '/') {
              let total = 0
              page.forEach((value, index) => {
                if(value[0].name.indexOf(window.location.origin) > -1) {
                  total += vis[index][0]
                }
              })
              pv['home'] = total
              for(let i = 0; i < n; i++) {
                pv[page[i][0].name] = vis[i][0]
              }
            } else {
              const pathUrl = window.location.origin + to.path
              for(let i = 0; i < n; i++) {
                if(page[i][0].name == pathUrl) {
                  pv[pathUrl] = vis[i][0]
                  break
                }
              }
            }
          }
          Vue.prototype.pv = pv
        })
      }
    }
    next();
  });
};

// PageInfo.vue
let pv = 0
if(!Vue.prototype.isServer && Vue.prototype.pv) {
  pv = Vue.prototype.pv[window.location.origin + props.pageInfo.path]
}

// Footer.vue
let pv = 0
if(!Vue.prototype.isServer && Vue.prototype.pv) {
  pv = Vue.prototype.pv['home']
}

期间还有一个小插曲,就是本地没问题,到服务端却报错了,Uncaught DOMException: Failed to execute ‘appendChild’ on ‘Node’: This node type does not support this method. at Object.appendChild 。经过查阅和调试之后,发现是 v-if 的问题,也就是在 PageInfo 和 Footer 组件中,如果你用了 v-if 去控制浏览量的显隐,因为在服务端是不会渲染的,而到了浏览器就报错了。所以把 v-if 修改成 v-show 就可以了。

这么修改之后就基本就没问题了,看看最后的效果:
请添加图片描述

这下终于大功告成了!虽然走了不少弯路,还修改了主题的源码,好在最终想要的效果也实现了。

其他

还有一点就是百度统计的 access_token 有效期只有一个月,过期了需要用 refresh_token 去获取新的,在使用手册里面也有介绍方法。等过期了我看看啥情况再做一下自动更新吧。

猜你喜欢

转载自blog.csdn.net/weixin_45732455/article/details/129975128
今日推荐