解决文章阅读统计与valine的冲突
重写主题后发现文章阅读次数统计和valine又冲突了。LeanCloud官方给的解决方法就是等SDk版本到5.0或者使用REST API。
其他版本的valine内置了文章阅读次数统计。但valineEx没有,只能自己来了。
以下函数中的app_id
,app_key
是我之前定义好的常量的,就是LeanCloud的appid和key。测试的时候使用xhr一直报跨域错误但是fetch不会,所以全部用的fetch,反正兼容性还凑合。
与网上其他方法相比的优点
- 不需要引入80几kb的sdk
- 不会和其他依赖sdk的应用冲突
valine - 合并请求,避免响应429
网上的文章都是引入0.6.4的sdk,然后给3个函数。。这么多年了都没有个新文章。
LeanCloud国内版可以使用https://api.leancloud.cn
这个域名,也可以使用自己绑定的或者共享域名。国际版不用备案域名可以绑自己域名。
最后就是LeanCloud的安全问题。。。暂时没办法。
function initCount() {
if (document.getElementsByClassName('leancloud_visitors').length === 1) {
addCount();
} else if (document.getElementsByClassName('leancloud_visitors').length > 1) {
showTime();
}
}
为避免页面中只有一篇文章的情况,第一个if应该加个条件(只有文章内页才有的dom),已经水了这么多文章懒得加了。
页面初始化或者路由变化时调用initCount
就可以了。
function showTime() {
queryCount()
.then(response => response.json())
.then(result=> {
result.results.forEach(i => {
document.getElementById(i.url).innerText = i.time;
});
})
.catch((error)=>{})
}
用于首页显示文章阅读次数,解决了网上旧方法每篇文章一个请求的蠢方法。
function addCount(){
const visItem = document.getElementsByClassName('leancloud_visitors')[0];
const url = visItem.getAttribute('id').trim();
const title = visItem.getAttribute('data-flag-title').trim();
queryCount(url)
.then(response => response.json())
.then(result => {
if (result.results.length === 0) {
createCount(title,url)
.then(response => response.json())
.then(result => {
document.getElementById(url).innerText = result.time;
})
}else{
const id = result.results[0].objectId;
updateCount(id)
.then(response => response.json())
.then(result => {
document.getElementById(url).innerText = result.time;
})
}
})
.catch((error)=>{})
}
进入文章内页会调用此函数,数据库中查询不到就调用发送创建请求的函数。
function queryCount(url){
const QueryObj = {
_method:"GET",
_ApplicationId: app_id,
_ApplicationKey: app_key
};
if (url) {
QueryObj.keys = 'time';
QueryObj.limit = 1;
QueryObj.where = {url};
} else {
QueryObj.keys = "time,url";
const URl_Arr = [];
const visItem = document.querySelectorAll('.leancloud_visitors');
visItem.forEach(function (el) {
URl_Arr.push(el.getAttribute('id').trim());
});
QueryObj.where = {url:{$in:URl_Arr}};
}
const raw = JSON.stringify(QueryObj);
const requestOptions = {
method: 'POST',
headers: {"Content-Type": "text/plain"},
body: raw
};
return fetch('https://api.leancloud.cn/1.1/classes/Counter', requestOptions)
}
不管是首页显示文章阅读次数还是文章内页,更新计算器都需要执行这个函数获取阅读次数和id。按照LeanCloud文档中写的发get请求结果就报错了。只能用特殊手段,旧版的sdk也是用这方法。
function updateCount(id) {
const raw = JSON.stringify({time:{__op:"Increment",amount:1}})
const reqOptions = {
method: 'PUT',
headers: {
"Content-Type": "application/json",
"X-LC-Id": app_id,
"X-LC-Key": app_key
},
body: raw,
}
return fetch('https://api.leancloud.cn/1.1/classes/Counter/'+id+'?fetchWhenSave=true', reqOptions)
}
更新计数器的函数,id通过queryCount得到。
function createCount(title,url){
const obj = {
title,
url,
time:1
};
const raw = JSON.stringify(obj)
const reqOptions = {
method: 'POST',
headers: {
"Content-Type": "application/json",
"X-LC-Id": app_id,
"X-LC-Key": app_key
},
body: raw,
};
return fetch('https://api.leancloud.cn/1.1/classes/Counter?fetchWhenSave=true', reqOptions)
}
新文章初始化数据的函数。
写给小白
在主题模板里添加下面的html代码,然后把之前的js加到博客的js中。代码执行后会自动查找页面中class
值为leancloud_visitors
的元素,获取其id
为查询条件。并将得到的值填充进去。
id
是文章的相对路径,data-flag-title
是文章标题。存储到LeanCloud时需要用这些内容。
<span class="iconfont iconeye" >
<span id="<%- url_for(post.path) %>" class="leancloud_visitors" data-flag-title="<%- post.title %>"></span>
</span>
解决文章阅读统计与valine的冲突
https://crosschannel.cc/daily/blog-posts-counter.html
转载或引用本文时请遵守许可协议,注明出处、不得用于商业用途!