QX-AI
GPT-4
QX-AI初始化中...
这篇文章介绍了如何在博客或网站上添加点赞功能。作者选择了一个现成的点赞系统 OrLike,并通过 Vercel 进行部署。在前端方面,作者使用了 Hexo-butterfly 主题框架,并提供了修改代码的步骤。同时,文章中也提供了代码的具体实现。
介绍自己
生成预设简介
推荐相关文章
生成AI简介

前言

  看@Shine在博客里整了个点赞功能Qexo添加点赞功能,心动,那就行动。

  懒得整一个Qexo系统,那就看看有木有现成的点赞系统拿来改改用。找到力orlike-vercel

  最终效果:

实现

部署OrLike

  注册登录leancloud,最好是国际版,创建一个应用,名称随意。在侧栏找到数据存储->结构化数据,点击创建Class,名称为OrLike,默认ACL权限修改为所有用户。

  接着在侧栏找到设置->应用凭证,复制AppID和AppKey,后续用到。

  数据库设置完成,点击下面链接部署后端到Vercel。

  部署完成后,在该Vercel项目的设置中找到环境变量,填入名为APPID(值对应之前复制的AppID)和APPKEY(对应AppKey)的环境变量,然后重新部署

  由于vercel默认域名被墙,最好绑定自己的二级域名,该域名链接即为api。

前端部署

  以Hexo-butterfly主题框架为例:

  修改layout\includes\post\reward.pug,在末尾添加以下代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
#orlike-box.orlike-box
script.
(() => {
function loadOrLike () {
new OrLike({
serverUrl: "你的api",
el: ".orlike-box",
days: 30,
});
}
window.pjax ? loadOrLike() : window.addEventListener('load', loadOrLike)
})()

  修改layout\includes\header\post-info.pug,在末尾添加以下代码,注意缩进在.meta-firstline内。

1
2
3
4
5
span.post-meta-orlike
i.iconfont.icon-aixin.fa-fw.post-meta-icon
span.post-meta-label= '点赞数:'
a(href=url_for(page.path) + '#orlike-box')
span.orlike-count

  在配置文件中全局引入该js和JQ:

orlike.js(对OrLike项目源码仓库的orlike.min.js有修改,以适配业务)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
const version = "V0.1.33"; function setCookie(cname, cvalue, exdays) { var d = new Date(); d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000)); var expires = "expires=" + d.toGMTString(); document.cookie = cname + "=" + cvalue + "; " + expires; }
function getCookie(cname) {
var name = cname + "="; var ca = document.cookie.split(';'); for (var i = 0; i < ca.length; i++) { var c = ca[i].trim(); if (c.indexOf(name) == 0) { return c.substring(name.length, c.length); } }
return "";
}
function createLink(url) { let link = $(document.createElement('link')); link.attr('href', url); link.attr('rel', 'stylesheet'); link.attr('type', 'text/css'); $('link').last().after(link); }
function OrLike({ serverUrl = "", el = "", days = 30, style = "", ifont = "", icon = { like: "fa fa-thumbs-up", dislike: "fa fa-thumbs-down" }, } = {}) { this.serverUrl = serverUrl; this.el = el; this.style = style; this.ifont = ifont; this.days = days; this.icon = icon; this.ckid = ""; this.prepare(); this.init(); }
OrLike.prototype.prepare = function () {
$(this.el).addClass("orlike-loading"); if (this.style != "") { createLink(this.style); }
if (this.ifont != "") { createLink(this.ifont); }
}
OrLike.prototype.init = function () {
server_url = this.serverUrl; obj = this; $.ajax({
type: 'GET', url: server_url + '/tmp', dataType: 'jsonp', jsonp: "callback", jsonpCallback: "success", xhrFields: { withCredentials: true }, async: true, crossDomain: true, success: function (data) {
let template = $(data.template); let icon_like = template.siblings("a.likeit.orlike").children("i"); let icon_dislike = template.siblings("a.dislikeit.orlike").children("i"); icon_like.attr('class', obj.icon.like); icon_dislike.attr('class', obj.icon.dislike); if (obj.icon.like == false)
icon_like.remove(); if (obj.icon.dislike == false)
icon_dislike.remove(); $(obj.el).removeClass("orlike-loading"); $(obj.el).html(template); obj.ckusr(obj); $('a.likeit.orlike').click({ obj: obj }, obj.like); $('a.dislikeit.orlike').click({ obj: obj }, obj.dislike);
},
});
}
OrLike.prototype.ckusr = function (obj) {
server_url = this.serverUrl; $.ajax({
type: 'GET', url: server_url + '/ckusr', dataType: 'jsonp', jsonp: "callback", jsonpCallback: "success", xhrFields: { withCredentials: true }, async: false, crossDomain: true, success: function (data) {
if (data.stat == 'ok' && data.uid != "") {
obj.ckid = data.ckid; if (!getCookie(data.ckid)) { setCookie(data.ckid, data.uid, obj.days); }
obj.query();
}
else { console.error('connect orlike failed!!!'); }
},
});
}
OrLike.prototype.query = function () {
server_url = this.serverUrl; $.ajax({
type: 'GET', url: server_url + '/qry?link=' + window.location.pathname, dataType: 'jsonp', jsonp: "callback", jsonpCallback: "success", xhrFields: { withCredentials: true }, crossDomain: true, success: function (data) {
if (data.stat == 'ok') {
$('a.likeit.orlike i span').text(data['like']);
$('span.post-meta-orlike a span').text(data['like']);
$('a.dislikeit.orlike i span').text(data['dislike']);
}
else { console.error('query orlike failed!!!'); }
},
});
}
OrLike.prototype.orl = function (obj, method) { server_url = obj.serverUrl; req_url = server_url + '/orl?method=' + method + '&link=' + window.location.pathname + '&' + obj.ckid + '=' + getCookie(obj.ckid); $.ajax({ type: 'GET', url: req_url, dataType: 'jsonp', jsonp: "callback", jsonpCallback: "success", xhrFields: { withCredentials: true }, crossDomain: true, success: function (data) { obj.query(); }, }); }
OrLike.prototype.like = function (event) { obj = event.data.obj; obj.orl(obj, 'like'); }
OrLike.prototype.dislike = function (event) { obj = event.data.obj; obj.orl(obj, 'dislike'); }

1
2
3
4
5
inject:
head:
bottom:
- <script defer="true" src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
- <script defer="true" src="/js/orlike.js"></script>

  引入CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
.orlike {
color: rgba(255, 255, 255);
font-size: 26px!important;
line-height: 2;
text-shadow: 5px 5px 5px #2ed0d9fc;
}
[data-theme=dark]
.orlike {
color: rgba(255, 255, 255, 0.85);
text-shadow: 4px 4px 4px #23a8af99;
}
.orlike:first-child{
margin-right: 36px;
}
.orlike span {
margin-left: 0.3rem;
}
.orlike-box{
margin: 15px 0 0 0;
display: flex;
width: 100%;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
position: relative;
overflow: hidden;
height: 52px;
}
.orlike:hover{
color: #f07e7e!important;
}
[data-theme=dark]
.orlike:hover{
color: #e87373e8!important;
}
.orlike-loading {
display: block;
height: 39px;
width: 10px!important;
border-radius: 50%;
border: 2px solid #acacac;
border-bottom-color: transparent;
-webkit-animation: orlike-loadingRotate 0.75s linear infinite;
animation: orlike-loadingRotate 0.75s linear infinite;
}
@-webkit-keyframes orlike-loadingRotate {
0% {
-webkit-transform: rotate(0deg);
}
50% {
-webkit-transform: rotate(180deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
@keyframes orlike-loadingRotate {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(180deg);
}
100% {
transform: rotate(360deg);
}
}

  完毕。

后记

  无