惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

G
Google Developers Blog
阮一峰的网络日志
阮一峰的网络日志
IT之家
IT之家
人人都是产品经理
人人都是产品经理
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 【当耐特】
WordPress大学
WordPress大学
Hugging Face - Blog
Hugging Face - Blog
博客园 - 叶小钗
罗磊的独立博客
宝玉的分享
宝玉的分享
月光博客
月光博客
V
V2EX
博客园 - 司徒正美
Vercel News
Vercel News
量子位
Y
Y Combinator Blog
美团技术团队
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
T
Tailwind CSS Blog
博客园 - Franky
小众软件
小众软件
I
InfoQ
A
About on SuperTechFans

Ariasakaの小窝

Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝
Ariasakaの小窝
2022-08-16 · via Ariasakaの小窝

前置教程:

前往以下网站,不保证安全性哦喵~Hexo Butterfly博客魔改的一点点基础Ariasakaの小窝

前言&效果

众所周知,b站的视频有点赞功能,这个功能能够充分地体现出观众们对视频的喜爱程度和白嫖率

同样,我们可以在博客中添加这个功能,后续我可能也会增加一个收藏功能(或者说是直接整一个账号登录?用静态网页搞登录作死的博主是屑

1660618508648

效果如下,只需要点击左侧的点赞图标即可点赞:

1660618730764

不过目前的博文点赞并没有点赞次数限制,像钉钉上课的点赞一样,你甚至可以用连点器点到1919810个赞。当然这个版本采用leancloud存储,肯定会有api调用限制的,而且反应稍慢。

1660619132596

1660619528680

1660627980542

教程部分

放出魔改教程吧!

改pug

打开 [blogRoot]\themes\butterfly\layout\includes\header\post-info.pug,在末尾添加

JS
span.post-meta-separator |&nbsp 
    span.post-meta-dianzan
        if theme.wordcount.post_wordcount
        a(href="javascript:void(0)" class="dianzan"  onclick="dianzan()")
            i.fas.fa-thumbs-up
        span.post-meta-label= _p(' 点赞') + ':'
        span.dianzan-count=0
DIFF
 - let comments = theme.comments
 #post-info
  h1.post-title= page.title || _p('no_title')
    if theme.post_edit.enable
      a.post-edit-link(href=theme.post_edit.url + page.source title=_p('post.edit') target="_blank")
        i.fas.fa-pencil-alt
      
  #post-meta
    .meta-firstline
      if (theme.post_meta.post.date_type)
        ...
      if comments.count && !comments.lazyload && page.comments !== false && comments.use
        ...
          when 'Twikoo'
            ...
          when 'Facebook Comments'
            +countBlock
              a(href=url_for(page.path) + '#post-comment')
                span.fb-comments-count(data-href=urlNoIndex())
+      span.post-meta-separator |&nbsp 
+        span.post-meta-dianzan
+          if theme.wordcount.post_wordcount
+            a(href="javascript:void(0)" class="dianzan"  onclick="dianzan()")
+              i.fas.fa-thumbs-up
+            span.post-meta-label= _p(' 点赞') + ':'
+            span.dianzan-count=0

如果你使用的是 butterfly4.2.2或者4.3.1的话,可以直接使用我改好的pug (说明一下hexo的语法高亮不支持pug,所以我用js高亮代替)

JS
- let comments = theme.comments
#post-info
  h1.post-title= page.title || _p('no_title')
    if theme.post_edit.enable
      a.post-edit-link(href=theme.post_edit.url + page.source title=_p('post.edit') target="_blank")
        i.fas.fa-pencil-alt
      
  #post-meta
    .meta-firstline
      if (theme.post_meta.post.date_type)
        span.post-meta-date
          if (theme.post_meta.post.date_type === 'both')
            i.far.fa-calendar-alt.fa-fw.post-meta-icon
            span.post-meta-label= _p('post.created')
            time.post-meta-date-created(datetime=date_xml(page.date) title=_p('post.created') + ' ' + full_date(page.date))=date(page.date, config.date_format)
            span.post-meta-separator |
            i.fas.fa-history.fa-fw.post-meta-icon
            span.post-meta-label= _p('post.updated')
            time.post-meta-date-updated(datetime=date_xml(page.updated) title=_p('post.updated') + ' ' + full_date(page.updated))=date(page.updated, config.date_format)
          else
            - let data_type_update = theme.post_meta.post.date_type === 'updated'
            - let date_type = data_type_update ? 'updated' : 'date'
            - let date_icon = data_type_update ? 'fas fa-history' :'far fa-calendar-alt'
            - let date_title = data_type_update ? _p('post.updated') : _p('post.created')
            i.fa-fw.post-meta-icon(class=date_icon)
            span.post-meta-label= date_title
            time(datetime=date_xml(page[date_type]) title=date_title + ' ' + full_date(page[date_type]))=date(page[date_type], config.date_format)
      if (theme.post_meta.post.categories && page.categories.data.length > 0)
        span.post-meta-categories
          if (theme.post_meta.post.date_type)
            span.post-meta-separator |

          each item, index in page.categories.data
            i.fas.fa-inbox.fa-fw.post-meta-icon
            a(href=url_for(item.path)).post-meta-categories #[=item.name]
            if (index < page.categories.data.length - 1)
              i.fas.fa-angle-right.post-meta-separator

    .meta-secondline
      - let postWordcount = theme.wordcount.enable && (theme.wordcount.post_wordcount || theme.wordcount.min2read)
      if (postWordcount)
        span.post-meta-separator |
        span.post-meta-wordcount
          if theme.wordcount.post_wordcount
            i.far.fa-file-word.fa-fw.post-meta-icon
            span.post-meta-label= _p('post.wordcount') + ':'
            span.word-count= wordcount(page.content)
            if theme.wordcount.min2read
              span.post-meta-separator |
          if theme.wordcount.min2read
            i.far.fa-clock.fa-fw.post-meta-icon
            span.post-meta-label= _p('post.min2read') + ':'
            span= min2read(page.content, {cn: 350, en: 160}) + _p('post.min2read_unit')
  
      //- for pv and count
      mixin pvBlock(parent_id,parent_class,parent_title)
        span.post-meta-separator |
        span(class=parent_class id=parent_id data-flag-title=page.title)
          i.far.fa-eye.fa-fw.post-meta-icon
          span.post-meta-label=_p('post.page_pv') + ':'
          if block
            block

      - const commentUse = comments.use
      if commentUse && !comments.lazyload
        case commentUse[0]
          when 'Valine'
            if theme.valine.visitor
              +pvBlock(url_for(page.path),'leancloud_visitors',page.title)
                span.leancloud-visitors-count
          when 'Waline'
            if theme.waline.pageview
              +pvBlock('','','')
                span.waline-pageview-count(data-path=url_for(page.path))
          when 'Twikoo'
            if theme.twikoo.visitor
              +pvBlock('','','')
                span#twikoo_visitors
          default
            if theme.busuanzi.page_pv
              +pvBlock('','post-meta-pv-cv','')
                span#busuanzi_value_page_pv
      else if theme.busuanzi.page_pv
        +pvBlock('','post-meta-pv-cv','')
          span#busuanzi_value_page_pv

      if comments.count && !comments.lazyload && page.comments !== false && comments.use
        - var whichCount = comments.use[0]

        mixin countBlock
          span.post-meta-separator |
          span.post-meta-commentcount
            i.far.fa-comments.fa-fw.post-meta-icon
            span.post-meta-label= _p('post.comments') + ':'
            if block
              block
      
        case whichCount
          when 'Disqus'
          when 'Disqusjs'
            +countBlock
              span.disqus-comment-count
                a(href=full_url_for(page.path) + '#disqus_thread')
          when 'Valine'
            +countBlock
              a(href=url_for(page.path) + '#post-comment' itemprop="discussionUrl")
                span.valine-comment-count(data-xid=url_for(page.path) itemprop="commentCount")
          when 'Waline'
            +countBlock
              a(href=url_for(page.path) + '#post-comment')
                span.waline-comment-count(data-path=url_for(page.path))
          when 'Gitalk'
            +countBlock
              a(href=url_for(page.path) + '#post-comment')
                span.gitalk-comment-count
          when 'Twikoo'
            +countBlock
              a(href=url_for(page.path) + '#post-comment')
                span#twikoo-count
          when 'Facebook Comments'
            +countBlock
              a(href=url_for(page.path) + '#post-comment')
                span.fb-comments-count(data-href=urlNoIndex())
      span.post-meta-separator |&nbsp 
        span.post-meta-dianzan
          if theme.wordcount.post_wordcount
            a(href="javascript:void(0)" class="dianzan"  onclick="dianzan()")
              i.fas.fa-thumbs-up
            span.post-meta-label= _p(' 点赞') + ':'
            span.dianzan-count=0

这时重新 hexo cl&&hexo s应该就能看到点赞显示了。

1660621375103

LeanCloud配置

然后你需要一个LeanCloud数据库。

如果你已经注册并且创建数据库了,就不必看教程了。

点击查看创建教程

如果你已经注册过用于评论系统的话(比如Valine),请务必使用同样的数据库,否则会出现bug导致损坏评论数据库!(我也不知道为什么,很多大佬们用Leancloud都会提示)

进入你的应用-数据存储-结构化数据,创建一个名为dianzan的class,权限改为无限制(反正点赞这玩意又不重要),创建这个class

1660627525521

然后在设置-应用凭证复制你的AppID、AppKey和REST API服务器地址,一定要保密。

至此,Leancloud部分就配置完了。

JS部分

首先添加 AV-min.js

YAML
inject:
  head:
  ...
  bottom:
  - <script src="//gcore.jsdelivr.net/npm/leancloud-storage@4.13.1/dist/av-min.js"></script>
  - ...

然后用一小段JS访问API就可以实现点赞了,在[blogRoot]/themes/butterfly/source/js里面新建dianzan.js文件,粘贴以下代码,把 {YOUR_APPID} 换成开始复制的AppId, {YOUR_APPKEY} 换成开始复制的AppKey, {YOUR_URL} 换成开始复制的分配的共享域名或者你自己绑定的域名

JAVASCRIPT
function GetUrlRelativePath() {
    var url = document.location.toString();
    var arrUrl = url.split("//");

    var start = arrUrl[1].indexOf("/");
    var relUrl = arrUrl[1].substring(start);

    if (relUrl.indexOf("?") != -1) {
        relUrl = relUrl.split("?")[0];
    }
    return relUrl;
}
$(document).ready(function () {
    const {
        Query,
        User
    } = AV;
    AV.init({
        appId: "{YOUR_APPID}",
        appKey: "{YOUR_APPKEY}",
        serverURL: "{YOUR_URL}"
    });
    var dianzans = [];
    var hrefs = [];
    var ids = [];
    const query2 = new AV.Query('dianzan');
    query2.find().then((dzs) => {
        for (i = dzs.length - 1; i >= 0; i--) {
            dianzans.push(dzs[i]["attributes"]["count"]);
            hrefs.push(dzs[i]["attributes"]["href"]);
            ids.push(dzs[i]["id"])
        }
        index = hrefs.indexOf(GetUrlRelativePath());
        console.log(dianzans[index])
        if (dianzans[index] === undefined) {
            document.getElementsByClassName("dianzan-count")[0].innerText = "0";
        } else {
            document.getElementsByClassName("dianzan-count")[0].innerText = dianzans[index];
        }
    });
})

function setCount() {
    var dianzans = [];
    var hrefs = [];
    var ids = [];
    const query2 = new AV.Query('dianzan');
    query2.find().then((dzs) => {
        for (i = dzs.length - 1; i >= 0; i--) {
            dianzans.push(dzs[i]["attributes"]["count"]);
            hrefs.push(dzs[i]["attributes"]["href"]);
            ids.push(dzs[i]["id"])
        }
        index = hrefs.indexOf(GetUrlRelativePath());
        console.log(dianzans[index])
        if (dianzans[index] === undefined) {
            document.getElementsByClassName("dianzan-count")[0].innerText = "0";
        } else {
            document.getElementsByClassName("dianzan-count")[0].innerText = dianzans[index] + 1;
        }
    });
}

function dianzan() {
    try {
        var dianzans = [];
        var hrefs = [];
        var ids = [];
        const query = new AV.Query('dianzan');
        query.find().then((dzs) => {
            for (i = dzs.length - 1; i >= 0; i--) {
                dianzans.push(dzs[i]["attributes"]["count"]);
                hrefs.push(dzs[i]["attributes"]["href"]);
                ids.push(dzs[i]["id"])
            }
            if (hrefs.indexOf(GetUrlRelativePath()) == -1) {
                console.log(1)
                const TestObject = AV.Object.extend('dianzan');
                const testObject = new TestObject();
                testObject.set('href', GetUrlRelativePath());
                testObject.set('count', 1);
                testObject.save();
            } else {
                index = hrefs.indexOf(GetUrlRelativePath());
                console.log(ids[index])
                query.get(ids[index]).then((todo) => {
                    todo.set('count', dianzans[index] + 1);
                    todo.save();
                });
            }
            setCount();
        });
    } catch (err) {
        const TestObject = AV.Object.extend('dianzan');
        const testObject = new TestObject();
        testObject.set('href', GetUrlRelativePath());
        testObject.set('count', 1);
        testObject.save();
    }

}

然后在主题配置文件中插入:

YAML
inject:
  head:
  - ...
  bottom:
  - ...
  - <script type="text/javascript" src="/js/dianzan.js"></script>

恭喜你获得了好玩的无限点赞功能!

TODO

{% checkbox checked, 魔改主题显示点赞 %} {% checkbox checked, 点赞云存储 %} {% checkbox checked, 显示点赞个数 %} {% checkbox 首页显示点赞个数 %} {% checkbox cookies记录是否点赞,一个人只能点一个 %} {% checkbox 账号登录功能 %}