玩命加载中 . . .

Hexo+GitHub免费搭建个人博客


前言


本博客的搭建参考了众多博主的搭建教程(文章主体结构参考Hexo+Github博客搭建完全教程最多),因为时间有限且个人属于前端小白,故个性化做得不是很好,还有许多需要完善的地方。另外搭建个人博客需要一些耐心,很多细节都会导致Bug的出现。本文的内容随意复制,引用的话可以加一个参考链接,谢谢😁 。希望大家都能搭建好自己舒适的博客~

搭建原因及思路

  • 原因

    • 之前是在博客园上写文章,但是总是感觉不舒服,因为有些广告啥的,另外虽然想做一些个性化,但一是因为自己是个前端小白,好多东西不会;二是不太愿意花那么多时间去弄一个不属于自己的东西。没错,第三方的平台会给我一种疏离感,而个人博客个性化极强,从头到尾这么搭建下来,不得不说心理极度舒适😂。除此之外,大一的时候上导论课也接触过一些关于服务器、前端、网站等等,也算是种下了一颗种子,但奈何自己太菜又太懒,一直没有下定决心去做。现在趁着大三暑假,花点时间搭建个人博客,也算是解决了一个心结。
  • 思路

    • 基于开源框架Hexo搭建博客,直接在GitHub Pages平台上托管博客

      其实也可以在CodingGitee上部署,Coding我没有尝试,但Gitee由于最近在创建绿色网络环境,Pages暂停服务了,现在没法申请。

    • 因为打算白嫖,所以没有买个人域名,如果买了个人域名,在GitHub上绑定之后即可访问。我白嫖的地址:https://321hjd.github.io/

教程结构安排

  • 第一部分:Hexo的初步搭建以及部署至GitHub Pages
  • 第二部分:Hexo的主题更换以及基本配置
  • 第三部分:个性化。添加各种功能,如评论系统、说说模块等
  • 第四部分:博客的性能优化

一、搭建


Hexo的初步搭建以及部署至GitHub Pages

工具说明

  • Hexo

    是一个基于Node.js的快速, 简洁且高效的静态网站生成框架. 让上百个页面在几秒内瞬间完成渲染. Hexo支持Github Flavored Markdown的所有功能, 甚至可以整合Octopress的大多数插件. 并自己也拥有强大的插件系统.

  • Git

    Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目。GitLinus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。Git与常用的版本控制工具CVS, Subversion等不同,它采用了分布式版本库的方式,不必服务器端软件支持。

  • Node.js

    简单的说Node.js就是运行在服务端的JavaScriptNode.js 是一个基于Chrome JavaScript 运行时建立的一个平台。Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行 JavaScript的速度非常快,性能非常好。

  • npm(node package manager)

    JavaScript世界的包管理工具,并且是Node.js平台的默认包管理工具

1. 安装Git

  • Windows:到Git官网下载.exe文件,安装选项全默认
    • 安装完成后使用右键的Git Bash Here,执行git --version可查看版本号
  • Linux:只需要一行指令sudo apt install git即可
  • Git教程:廖雪峰老师写的Git教程非常好,强烈建议大家看看

2. 安装Node.js和npm工具

3. 安装Hexo

  • 找个地方右键Git Bash Here,后面的指令操作都是使用Git Bash

  • 配置npm的国内镜像源:

    npm install -g cnpm --registry=https://registry.npm.taobao.or
  • 配置完成后,输入npm info hexo,如果配置成功,dist会显示

    .tarball: https://registry.nlark.com/hexo/download/hexo-5.4.0.tgz

  • 通过npm安装Hexo-g是指定全局安装,之后可以在任意位置使用hexo指令)

    npm install -g hexo
  • 然后输入hexo -v查看是否安装成功。若出现版本号,则至此已安装完成

  • 接下来初始化我们的静态网站,进入到存放博客文件的目录下

    hexo init MyBlog	# 初始化创建,将在当前目录下新建MyBlog文件夹 
    cd MyBlog			# 进入这个文件夹,这个文件夹下面将存放所有相关文件
    npm install			# 进一步安装hexo所需文件
    • 大概效果如下:

      指令执行结果

    • 指令执行完成后,指定文件夹MyBlog目录下有:

      • node_modules/Hexo的依赖包
      • scaffolds/:生成文章的一些模板
      • source/:用来存放写的文章
      • themes/:主题
      • _config.yml:博客的配置文件
      • 其它:.github/、.gitignore、_config.landscape.yml、package.json、package-lock.json
  • 打开本地服务器查看博客

    hexo generate		# 生成静态网页
    hexo server			# 打开本地服务器(默认是4000端口)

    正常情况下应该会出现下图:

    Hexo-blog

    这时博客根目录下会生成public目录,这就是我们部署到GitHub上所需要上传的文件夹。

  • Ctrl + C可关闭本地服务器

  • 常用hexo指令

4. 注册GitHub账号并新建个人仓库

  • GitHubhttps://github.com/

  • 新建项目仓库new repository,注意项目名字最好是和用户名相同,并加上.github.io后缀。比如我的repo321hjd.github.io

  • 注意勾选上README初始化,可以描述一下该repo是干嘛的

  • 然后在项目页面选择Setting并下拉,进入Pages,可以看到分配给自己的Pages(如果没正常显示,可能还差点啥,具体记不太清楚了,当时没记录😢)​​

    GitHub Pages

5. 生成本地SSH并添加至GitHub

  • 生成SSH并添加至GitHub,使得GitHub可以识别本地(nameemail可以和注册Github时的不同)

    git config --global user.name "yourname"	# name按自己喜好取
    git config --global user.email "youremail"	# global代表本机上任一地方的Git用户都是此处设置的
  • 创建SSH

    ssh,简单来讲,就是一个秘钥,其中,id_rsa是你这台电脑的私人秘钥,不能给别人看的,id_rsa.pub是公共秘钥,可以随便给别人看。把这个公钥放在GitHub上,这样当你链接GitHub自己的账户时,它就会根据公钥匹配你的私钥,当能够相互匹配时,才能够顺利的通过git上传你的文件到GitHub上。

    ssh-keygen -t rsa -C "youremail"	# 刚刚设置的email
  • 这时它会告诉你已经生成了.ssh文件夹,应该是在系统盘的用户目录下,如:C:\Users\username\.ssh。找到该文件夹并复制id_rsa.pub中的所有内容

  • 打开GitHub,在头像下面点击Settings,再点击SSH and GPG keys,新建一个SSH,随便取一个名字,然后将刚刚复制的内容全部粘贴进去,如图:

    示例-SSH

  • 再在git bash输入ssh -T git@github.com,若出现如下结果,则添加成功

    示例-success

  • 至此,我们已经可以在本地建立repo并与GitHub连接起来,如pull or push

6. 将Hexo部署至GitHub

  • 这一步,会将Hexo生成的文章部署到GitHub上。

  • 首先我们需要安装一个插件deployer-git,这样我们才能用命令部署至GitHub

    npm install hexo-deployer-git --save
  • 然后打开博客根目录的_config.yml文件,

    • 修改url部分并新增root,写为

      url: https://{username}.github.io/	# Pages地址
      root: /							    # 网站根目录
    • 修改最后一行的配置

      deploy:
        type: git
        repository: https://github.com/{username}/{yourrepo}
        # 示例:https://github.com/321hjd/321hjd.github.io
        branch: master
  • 最后执行以下命令,部署成功,此时可以访问GitHub分配的Pages如我的https://321hjd.github.io看到博客主页

    hexo clean		# 清除缓存(网页正常情况下可以忽略此条命令,执行该指令后,会删掉站点根目录下的public文件夹)
    hexo generate	# 生成静态页面至public目录
    hexo deploy		# 自动生成网站静态文件并部署到设定仓库

    注意:若这一步完成后访问不了Pages,可以参考本节的Q&A,若还是无法解决,请仔细查看上述步骤是否正常完成,或根据本节的参考链接跳转至其他大佬处查询。

7. 写文章并发布文章

建议写一个test文档,专门用于测试功能是否能正确实现。
另外markdown编辑器建议使用Typora,非常好用~

  • 新建test文档。在博客根目录下右键打开git bash,执行指令

    hexo new post "test"
    • 此时打开xxx/source/_posts可以发现多了一个test.md
    • 编辑该文件并执行hexo ghexo s可以本地预览,也可以继续执行hexo d部署至GitHub,这时候就可以在你的Pages上看到发布的文章了

Q&A

Q:使用GitHub的pages服务,部署到GitHub后访问username.github.io总是无法连接(手机热点/WiFi都不行,不知道为啥)
github.io无法连接
A:在站长之家查看博客(https://{username}.github.io)的IP地址,修改C:\Windows\System32\drivers\etc\HOSTS文件(需要管理员权限),将IP地址 {username}.github.io添加到文件最后即可(如185.199.111.153 321hjd.github.io)。(枯了,还是有缺陷,电脑连手机热点的时候没法访问,只能用WiFi,但是手机热点上GItHub感觉又要容易一些😢GiteePages服务快点恢复吧😭​)

参考链接

二、主题基本配置

1. Hexo相关目录文件介绍

具体都可以参考官方文档

1.1 博客目录结构

- node_modules		# node.js库目录
- public			# 生成的网页文件目录
- scaffolds			# 新文章或页面的模板文件
- source			# 最常用的目录,后面个性化会新增很多
    - _data			# 存放一些页面的配置文件
    - _posts		# 文章存放的目录
    - about			# “关于”页面
    - archives		# “归档”页面
    - categories	# “分类”页面
    - friends		# “友情链接”页面
    - tags			# “标签”页面
- themes			# 存放主题

1.2 Hexo基本配置

  • 网站信息

    title: Hexo				# 网站标题
    subtitle: ''			# 网站副标题
    description: ''			# 网站描述,主要用于SEO,告诉搜索引擎一个关于您站点的简单描述,通常建议在其中包含您网站的关键词
    keywords:				# 网站关键词
    author: John Doe		# 作者
    language: en			# 语言,简体中文比如zh-CN(可以后面换了主题后再改)
    timezone: ''			# 时区,比如UTC/America/Japan,可以不填
  • 网址

    url:								# 网址
    root:								# 网站根目录
    permalink: :year/:month/:day/:title/	# 文章的永久链接格式	
    permalink_defaults:					# 永久链接中各部分的默认值
    ...
    • 使用默认的permalink的话,生成文章test.md的链接就是

      https://{username}.github.io/2021/7/22/test

    • 后面会将关于permalink的优化(主要是防止修改文章名后链接发生变化)

  • 主题:theme: landscap,默认是landscape,要更换主题下载后放入themes文件夹下,然后修改此处即可

  • Front-matter

    • Front-mattermd文件最上方以 ---分隔的区域,用于指定个别文件的变量,具体可参考Front-matter

      注意下面部分属性是需要下载主题以后才能配置的,暂时默认就好,后续更换主题后再改也不迟~

    title: "test"			# 文章标题,可以和.md文件名不同(注意Windows下文件名特殊字符的问题)
    date: 2021-07-21 14:46:34 # 文章生成日期
    author: hjd				# 作者
    img:					# 文章封面图片,缺省应该是会按照一定的规则从主题目录下的xxx/source/medias/featureimages/中拉取图片
    coverImg:				# 轮播图片
    top: false				# 置顶
    cover: false			# 是否在首页进行轮播
    toc: true				# 目录
    mathjax: false			# 是否支持mathjax,即数学公式
    password:				# 文章密码
    summary:				# 简介
    tags:					# 标签,注意多级标签这样写
      - tag1
      - tag2
      - ...
    categories:				# 分类
  • layout

    • 三种默认布局:post、page、draft,即scaffolds目录下的三个模板

      • 注意:那三个模板中的Front-matter是可以修改的
    • post:当使用指令hexo new test时,默认使用的布局是post,即source/_posts/下的文件,完整指令应该是hexo new {layout} "title"

    • page:执行hexo new page newpage,会在source目录下新建newpage文件夹和其中的index.md,这样访问该newpage的路径就是:

      https://{username}.github.io/newpage

    • draft:草稿,想写文章但不想别人看或者暂时不发出去,即预览或部署时令系统忽略该文章

      • 执行hexo new draft newdraft,会生成source/_drafts/newdraft.md文件
      • 想要预览该草稿时,可以执行hexo server --draft指令
      • 想要将草稿发表致至_posts中,执行hexo publish draft newdraft即可(_draft/中的test.md将被移动至_posts/

2. 更换主题

注意,我使用的主题是hexo-theme-materyREADME中有配置相关介绍)。当然你也可以使用其它主题比如相当受欢迎的NexT。后续教程全部都是针对matery主题的,部分地方可以相互借鉴,但存在一定差异,请各位看官斟酌。

关于该主题的特性就不多说了,GitHub上有介绍,大家git clone下来后也可以自行体会,下面主要介绍基本的一些配置和问题的解决。

关于下面的一些功能实现,建议大家专门写一个test.md来测试每一项功能。

2.1 下载主题并更换

  • themes/目录下执行该指令

    git clone https://github.com/blinkfox/hexo-theme-matery.git
  • 然后将博客根目录下_config.yml中的theme属性值改为hexo-theme-matery

2.2 添加404页面

  • /source/目录下新建404.md

    title: 404 
    date: 2021-07-14 00:00:00 
    type: "404" 
    layout: "404" 
    description: "经典404 Not Found →_→" 
  • 然后在/themes/hexo-theme-matery/layout目录下新建一个404.ejs文件

    <style type="text/css">
        /* don't remove. */
        .about-cover {
            height: 90.2vh;
        }
    </style>
    <div class="bg-cover pd-header about-cover">
        <div class="container">
            <div class="row">
                <div class="col s10 offset-s1 m8 offset-m2 l8 offset-l2">
                    <div class="brand">
                        <div class="title center-align">
                            404
                        </div>
                        <div class="description center-align">
                            <%= page.description %>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    
    <% if (theme.banner.enable) { %>
        <script>
            // 每天切换 banner 图.  Switch banner image every day.
            var bannerUrl = "<%- theme.jsDelivr.url %><%- url_for('/medias/banner/') %>" + new Date().getDay() + '.jpg';
            $('.bg-cover').css('background-image', 'url(' + bannerUrl + ')');
        </script>
    <% } else { %>
        <script>
            $('.bg-cover').css('background-image', 'url(<%- theme.jsDelivr.url %><%- url_for('/medias/banner/0.jpg') %>)');
        </script>
    <% } %>
    

2.3 代码高亮

  • 根据hexo-theme-matery的配置建议,直接使用prismjs

    npm uninstall hexo-prism-plugin		# 若node_modules中有hexo-prism-plugin插件,先写在
  • 然后修改博客根目录下的_config.yml配置文件

    highlight:
      enable: false				# 改为false
      line_number: true
      auto_detect: false
      tab_replace: ''
      wrap: true
      hljs: false
    prismjs:
      enable: true				# 改为true
      preprocess: true
      line_number: true
      tab_replace: ''
  • 默认的prismjs主题是Tomorrow Night,若需要更换,到prismjs download page下载喜欢的css文件,然后替换themes/hexo-theme-matery/source/libs/prism/prism.css即可

    这里发现了一些问题,如c++、yml等无法高亮,暂时还没找到解决方案⊙﹏⊙∥。
    另外注意代码块前面不能有列表符号,否则不能正常渲染。

2.4 数学公式渲染

  • 存在的问题:Hexo默认的渲染引擎hexo-renderer-markedmarkdown语法冲突,因为该引擎会将一些特殊的markdown符号转换为相应的HTML标签,比如在markdown语法中,下划线'_'代表斜体,但会被该渲染引擎处理为<em>标签,类似的还有'*'、'{'、'}、'\'

  • 解决方案:

    • 更换Hexo的渲染引擎

      npm uninstall hexo-renderer-marked --save	# 卸载原来的引擎
      npm install hexo-renderer-kramed --save		# kramed是与marked相近的轻量级渲染引擎,只是在后者的基础上修复了一些bug
    • 然后修复一些行内渲染的bug

      • 打开博客根目录的node_modules/kramed/lib/rules/inline.js文件,将第11行的escape变量做相应修改(这一步是在原基础上取消了对\,{,}的转义)
      //  escape: /^\\([\\`*{}\[\]()#$+\-.!_>])/,
      escape: /^\\([`*\[\]()#$+\-.!_>])/,		//注意需要逗号
      • 同时将第20行的em变量做相应修改
      //  em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
      em: /^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
    • 接下来在主题中开启mathjax开关。打开主题目录下的配置文件_config.yml,将mathjax默认的false修改为true

      mathjax:
        enable: true
        per_page: true
        cdn: https://cdn.bootcss.com/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML
    • 最后在文章的Front-matter中开启mathjax(不需要数学公式的文章建议关闭,因为mathjax的渲染较为耗时)

      ---
      title: test
      author: hjd
      mathjax: true
      tags: 
      ---

    最后还是存在一点问题,比如连续的花括号渲染时会失败。不过在中间加上空格就好了。ps:这是参考教程说的,但可能后面作者已经修复了这个bug,我测试的时候并没有发现有问题😂

2.5 文章图片引用

  • 问题:部署后文章中插入的图片不显示

  • 解决方案

    • 首先安装插件hexo-asset-image
    npm install https://github.com/7ym0n/hexo-asset-image --save 
    • 然后打开博客根目录的_config.yml,将post_asset_folder的值修改为true(这时再生成文章时会在_posts目录下生成与文章同名的文件夹)

      其实这一步也可以不用,看个人喜好,是不是喜欢把同一篇文章的图片都放在一起

    • 最后插入图片的路径有三种

      • 方法一:![](imgname.jpg)(缺点是本地Typora无法预览)
      • 方法二:相对路径。![](article/imgname.jpg)(这种方法建议打开上一步那个post_asset_folder开关;或者直接建一个文件夹专门存放所有文章的图片)
      • 方法三:{% asset_img example.jpg This is an example image %}(参考自官方文档)

    当然还有一种方法是直接将图片上传到图床,然后直接引用图床链接。

2.6 添加表情支持

  • 目的:令博客可以使用markdown的表情语法(如<span class="github-emoji" alias="cry" style="" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/1f622.png?v8">&#x1f622;</span>😢

  • 最开始是根据网上很多的教程包括matery的官方README文件的描述,安装hexo-filter-github-emojis,但奈何安装时总是报错,最后使用了next-theme主题的emoji插件:hexo-filer-emoji

    # npm install hexo-filter-github-emojis --save	# 大家可以先试试这个
    npm install hexo-filter-emoji --save
  • 然后配置博客根目录配置文件_config.ymlemoji属性即可

    # 添加GitHub的emoji支持 
    emoji:   
    	enable: true   
    	className: github-emoji   
    	styles:   
    	customEmojis:

2.7 添加建站时间

  • 修改/themes/hexo-theme-matery/layout/_partial中的footer.ejs,在最后加上:(原来的文件中似乎有这部分代码,看情况修改吧)

    <script language=javascript>
        function siteTime() {
            window.setTimeout("siteTime()", 1000);
            var seconds = 1000;
            var minutes = seconds * 60;
            var hours = minutes * 60;
            var days = hours * 24;
            var years = days * 365;
            var today = new Date();
            var todayYear = today.getFullYear();
            var todayMonth = today.getMonth() + 1;
            var todayDate = today.getDate();
            var todayHour = today.getHours();
            var todayMinute = today.getMinutes();
            var todaySecond = today.getSeconds();
            /* Date.UTC() -- 返回date对象距世界标准时间(UTC)1970年1月1日午夜之间的毫秒数(时间戳)
            year - 作为date对象的年份,为4位年份值
            month - 0-11之间的整数,做为date对象的月份
            day - 1-31之间的整数,做为date对象的天数
            hours - 0(午夜24点)-23之间的整数,做为date对象的小时数
            minutes - 0-59之间的整数,做为date对象的分钟数
            seconds - 0-59之间的整数,做为date对象的秒数
            microseconds - 0-999之间的整数,做为date对象的毫秒数 */
            var t1 = Date.UTC(2017, 09, 11, 00, 00, 00); //北京时间2018-2-13 00:00:00
            var t2 = Date.UTC(todayYear, todayMonth, todayDate, todayHour, todayMinute, todaySecond);
            var diff = t2 - t1;
            var diffYears = Math.floor(diff / years);
            var diffDays = Math.floor((diff / days) - diffYears * 365);
            var diffHours = Math.floor((diff - (diffYears * 365 + diffDays) * days) / hours);
            var diffMinutes = Math.floor((diff - (diffYears * 365 + diffDays) * days - diffHours * hours) / minutes);
            var diffSeconds = Math.floor((diff - (diffYears * 365 + diffDays) * days - diffHours * hours - diffMinutes * minutes) / seconds);
            document.getElementById("sitetime").innerHTML = "本站已运行 " +diffYears+" 年 "+diffDays + " 天 " + diffHours + " 小时 " + diffMinutes + " 分钟 " + diffSeconds + " 秒";
        }/*因为建站时间还没有一年,就将之注释掉了。需要的可以取消*/
        siteTime();
    </script>
  • 然后在前面如copyright声明后加上以下代码即可

    <br>             
    <span id="sitetime"></span><span class="my-face">(ง •_•)ง</span> 
    <br>

2.8 不蒜子初始化计数

  • 修改/themes/hexo-theme-matery/layout/_partial中的footer.ejs,在最后加上:

    <script> 
    	$(document).ready(function () {
    		var int = setInterval(fixCount, 50); // 50ms周期检测函数
    		var pvcountOffset = 0; // 初始化首次数据
    		var uvcountOffset = 0; 
    		function fixCount() { 
    			if (document.getElementById("busuanzi_container_site_pv").style.display != "none") {
    				$("#busuanzi_value_site_pv").html(parseInt($("#busuanzi_value_site_pv").html()) + pvcountOffset); clearInterval(int);
    				} 
    			if ($("#busuanzi_container_site_pv").css("display") != "none") {
    				$("#busuanzi_value_site_uv").html(parseInt($("#busuanzi_value_site_uv").html()) + uvcountOffset); // 加上初始数据
    				clearInterval(int); // 停止检测
    			} 
    		} 
    	});
    </script> 
  • 然后把上面关于不蒜子的一段代码增加两个style='display:none'

    <% if (theme.busuanziStatistics && theme.busuanziStatistics.enable) { %>
    	<% if (theme.busuanziStatistics && theme.busuanziStatistics.totalTraffic) { %>         
    		<span id="busuanzi_container_site_pv" style='display:none'></span>    
    			&nbsp;|&nbsp;<i class="far fa-eye"></i>&nbsp;<%- __('siteTotalVisits') %>:&nbsp;   
    			<span id="busuanzi_value_site_pv" class="white-color"></span>            
    	<% } %>
    	<% if (theme.busuanziStatistics && theme.busuanziStatistics.totalNumberOfvisitors) { %>         
    		<span id="busuanzi_container_site_uv" style='display:none'></span>   
    			&nbsp;|&nbsp;<i class="fas fa-users"></i>&nbsp;<%- __('siteTotalVisitors') %>:&nbsp;       
    			<span id="busuanzi_value_site_uv" class="white-color"></span>       
    	<% } %>
    <% } %>

注意这里除了增加了两个style='display:none',还修改了两个<span>的位置,顺带也解决了后面不蒜子计数与live2d模型的冲突。如果要看每一步的操作,请移步洪卫大佬的教程:Hexo+Github博客搭建完全教程

2.9 字数统计、访问人数及其它

  • 添加文章总字数、站点访问人数、站点文章总字数以及文章更新日期

    • 下载hexo-wordcount插件
    npm i --save hexo-wordcount
    • 修改主题配置文件_config.yml,激活配置即可
    postInfo:
      date: true        # 发布日期
      update: true      # 更新日期
      wordCount: true   # 文章字数统计
      totalCount: true  # 站点总文章字数
      min2read: true    # 文章阅读时长
      readCount: false  # 文章阅读次数
    • 注意此时还不能看到站点文章总字数的统计,还需修改/themes/hexo-theme-matery/layout/_partial中的footer.ejs,添加如下代码
    <% if (theme.postInfo.totalCount) { %>
    	&nbsp;<i class="fas fa-chart-area"></i>&nbsp;站点总字数:&nbsp;<span
         class="white-color"><%= totalcount(site) %></span>&nbsp;<% } %>
  • 开启首页轮播功能

    • 配置source/_data/cover.json或直接将文章Front-Matter中的cover属性置为true即可
  • 添加搜索功能

    • 下载hexo-generator-search插件:

      npm install hexo-generator-search --save

    • 然后在根目录下的_config.yml中配置

      search:
        path: search.xml
        field: post
  • 修改scaffolds下模板的Font-matter,放出我的:

    • postdraft建议用一样的

      title: {{ title }}
      date: {{ date }}
      author: hjd
      img:
      coverImg:
      top: false
      cover: false
      toc: true
      mathjax: false
      password:
      summary:
      tags:
      categories:
    • page

      title: {{ title }}
      date: {{ date }}
      type: 
      layout: 
  • 其它:如友情链接、关于等页面可参考hexo-theme-matery官方文档

参考链接

三、个性化

1. 添加博客动态标签

  • 打开themes/hexo-theme-matery/layout/layout.ejs,在对应位置添加如下代码即可

    <script type="text/javascript">   
        var OriginTitile = document.title, st;    
        document.addEventListener("visibilitychange", function () {
            document.hidden ? (document.title = "🙈😜有本事点我", clearTimeout(st)) : (document.title = "( ఠൠఠ )ノ啊你还真点啊", 
                                                                                  st = setTimeout(function () {
                document.title = OriginTitile             
            }, 3e3))    
        }) 
    </script>

2. 修改壁纸、添加live2d模型

  • 修改壁纸:在themes\Matery\source\css\matery.css文件中找到body,修改如下

    body {
        /*background-color: #eaeaea;*/
    	background: linear-gradient(60deg, rgba(255, 165, 150, 0.5) 5%, rgba(0, 228, 255, 0.35)) 0% 0% / cover, url("https://ae01.alicdn.com/kf/H18a4b998752a4ae68b8e85d432a5aef0l.png"), url("https://i.loli.net/2021/07/17/kYX7dl5qtKpVeMv.jpg") 0px 0px;
    	background-attachment: fiexd;
        margin: 0;
        color: #34495e;
        overflow-x: hidden;
        overflow-y: auto;
    }
  • 添加live2d模型

    • 安装依赖:npm install --save hexo-helper-live2d

    • 安装模型(可以上网搜搜有哪些模型,这里以狗狗为例),先在博客根目录的_config.yml中新增配置

      # live2D模型配置
      live2d: 
        enable: true
        scriptFrom: local
        pluginRootPath: live2dw/ 
        pluginJsPath: lib/ 
        pluginModelPath: assets/
        tagMode: false 
        debug: false 
        model:
            use: live2d-widget-model-wanko 
        display:
            position: right
            hOffset: 100      # 水平偏移
            vOffset: -50      # 垂直偏移
            width: 150 
            height: 300 
        mobile: # 手机显示开关
            show: true 
        react: 
            opacity: 0.7
    • 然后执行指令即可:npm install live2d-widget-model-wanko

    注意:这里模型与不蒜子似乎有冲突,不过前面添加建站时间部分已经顺带解决了。即修改<span>的部分。

3. 取消渐变色、滚动条美化、直达评论按钮

  • 取消渐变色:在themes\Matery\source\css\matery.css找到.bg-cover:after,注释掉即可

    /*去除首页蒙版*/
    /*.bg-cover:after {
        -webkit-animation: rainbow 60s infinite;
        animation: rainbow 60s infinite;
    }*/
  • 滚动条美化:在themes\Matery\source\css\matery.css样式添加如下:

    /* 滚动条 */
    ::-webkit-scrollbar-thumb {    
    	background-color: #00FFFF;    
    	background-image: -webkit-linear-gradient(45deg,rgba(255,255,255,.4) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.4) 50%,rgba(255,255,255,.4) 75%,transparent 75%,transparent);    
    	border-radius: 3em;
    } 
    
    ::-webkit-scrollbar-track {   
    	background-color: #CCFFCC;   
    	border-radius: 3em;
    } 
    
    ::-webkit-scrollbar {     
    	width: 8px;     
    	height: 15px; 
    } 
  • 直达评论按钮(这一条可以等添加完Valine评论模块再做)

    • 新建文件themes\Matery\layout\_partial\back-comment.ejs,粘贴如下代码(我这里评论是valine,直接填写的valine的id——href="#vcomments",如果是其他评论,对应修改即可。)

      <!-- 直达评论 -->
      <div id="to_comment" class="comment-scroll">
          <a class="btn-floating btn-large waves-effect waves-light" href="#vcomments" title="直达评论">
              <i class="fas fa-comments"></i>
          </a>
      </div>
      
    • themes\Matery\layout\_partial\valine.ejs文末添加一条,引用第一步的内容

      <%- partial('_partial/back-comment.ejs') %>
    • 增加样式。在themes\Matery\source\css\matery.css添加内容如下:

      /*直达评论按钮样式*/
      .comment-scroll {    
      	position: fixed;    
      	right: 15px;    
      	bottom: 135px;    
      	padding-top: 15px;  
      	margin-bottom: 0;   
      	z-index: 998;
      } 
      
      .comment-scroll .btn-floating {   
      	background: linear-gradient(to bottom right, #FF9999 0%, #00FFFF 100%); 
      	width: 48px;    
      	height: 48px;
      }
      
      .comment-scroll .btn-floating i {  
      	line-height: 48px;    
      	font-size: 1.8rem; 
      } 

4. 导航栏优化

4.1 菜单修改

  • 这里修改了一些菜单的布局,主要是做了如下改变:

    • 将时轴、标签、分类放入归档页面下
    • 新增一级菜单-清单,并在其下添加相册、音乐、书单、电影、资源等页面
    • 新增一级菜单-说说、工具箱
  • 方法:

    • 修改主题下的_config.yml(参考注释即可),如:

      menu:
        Index:
          url: /
          icon: fas fa-home
        Archives:
          icon: fas fa-archive
          children:
            - name: 时轴
              url: /archives
              icon: fas fa-paper-plane
            - name: 分类 
              url: /categories
              icon: fas fa-bookmark 
            - name: 标签
              url: /tags
              icon: fas fa-tags
        List:
          icon: fas fa-heartbeat
          children:
            - name: 音乐 
              url: /music
              icon: fas fa-music
            - name: 相册
              url: /galleries
              icon: fas fa-image
            - name: 书单
              url: /books
              icon: fas fa-list
            - name: 电影
              url: /films
              icon: fas fa-film
            - name: 资源
              url: /resources
              icon: fas fa-cloud-download-alt
        About:
          url: /about
          icon: fas fa-user-circle
        Artitalk:
          url: /artitalk
          icon: fas fa-heart
        Contact:
          url: /contact
          icon: fas fa-comments
        Friends:
          url: /friends
          icon: fas fa-address-book
        Tools:
          url: /tools
          icon: fas fa-toolbox
      • 其中的icon图标可以到Font Awesome中选择自己喜欢的
    • 然后需要新建对应的page(方法同建立关于、友链等页面)

      hexo new page music
      hexo new page galleries
      hexo new page books
      hexo new page films
      hexo new page resources
      hexo new page artitalk
      hexo new page tools
      • 记得将对应生成的index.md中的typelayout都改为对应的标题
    • 汉化。需要修改两个文件:themes/hexo-theme-matery/layout/_partial/下的navigation.ejsmobile-nav.ejs,模仿源代码添加几行代码即可

      var menuMap = new Map();
      menuMap.set("Index", "首页");
      menuMap.set("Tags", "标签");
      menuMap.set("Categories", "分类");
      menuMap.set("Archives", "归档");
      menuMap.set("About", "关于");
      menuMap.set("Artitalk", "说说");
      menuMap.set("Contact", "留言板");
      menuMap.set("Friends", "友情链接");
      menuMap.set("List", "清单"); 
      menuMap.set("Tools", "工具箱");

4.2 相册

  • 上一步已经新建了galleries页面,其typelayout均为galleries

  • 添加themes/hexo-theme-matery/source/css/gallery.css文件

    .gallery-wrapper{
      padding-top: 30px;
    }
    .gallery-wrapper .gallery-box{
      padding: 5px !important;
    }
    
    .gallery-wrapper .gallery-item {
      display: block;
      overflow: hidden;
      background-color: #fff;
      padding: 5px;
      padding-bottom: 0;
      position: relative;
      -moz-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.22);
      -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.22);
      box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.22);
    }
    
    .gallery-cover-box{
      width: 100%;
      padding-top: 60%;
      text-align: center;
      overflow: hidden;
      position: relative;
      background: center center no-repeat;
      -webkit-background-size: cover;
      background-size: cover;
    }
    
    .gallery-cover-box .gallery-cover-img {
      display: inline-block;
      width: 100%;
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%,-50%);
    }
    .gallery-item .gallery-name{
      font-size: 14px;
      line-height: 24px;
      text-align: center;
      color: #666;
      margin: 0;
    }
    
    .waterfall {
      column-count: 3;
      column-gap: 1em;
    }
    .photo-wrapper{
      padding-top: 20px;
    }
    .photo-item {
      display: block;
      padding: 10px;
      padding-bottom: 0;
      margin-bottom: 14px;
      font-size: 0;
      -moz-page-break-inside: avoid;
      -webkit-column-break-inside: avoid;
      break-inside: avoid;
      background: white;
      -moz-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.22);
      -webkit-box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.22);
      box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.22);
    }
    .photo-item img {
      width: 100%;
    }
    .photo-item .photo-name{
      font-size: 14px;
      line-height: 30px;
      text-align: center;
      margin-top: 10px;
      margin-bottom: 10px;
      border-top: 1px solid #dddddd;
    }
    
    /*适配移动端布局*/
    @media only screen and (max-width: 601px) {
      .waterfall {
        column-count: 2;
        column-gap: 1em;
      }
    }
  • themes/hexo-theme-matery/layout/目录下新建galleries.ejsgallery.ejs文件

    注意:此处galleries.ejs是整个相册页面的配置,gallery.ejs是单独某一个相册的配置。

    • 这是galleries.ejs文件

    注意其中https://cdn.jsdelivr.net/gh/321hjd/ImageBed/galleries/是我使用CDN加速后的图床链接(后面会讲到图床搭建和CDN加速,可以先使用我的看看效果,这也是需要修改的地方,具体如何取决于你的/source/_data/galleries.json如何配置)

    <link rel="stylesheet" href="/css/gallery.css">
    
    <%- partial('_partial/bg-cover') %>
    
    <main class="content">
        <div class="container">
            <% if (site.data && site.data.galleries) { %>
            <% var galleries = site.data.galleries; %>
            <div class="gallery-wrapper row">
                <% for (var i = 0, len = galleries.length; i < len; i++) { %>
                <% var gallery = galleries[i]; %>
                <div class="col s6 m4 l4 xl3 gallery-box">
                    <a href="./<%- gallery.name %>" class="gallery-item" data-aos="zoom-in-up">
                        <div class="gallery-cover-box" style="background-image: url(https://cdn.jsdelivr.net/gh/321hjd/ImageBed/galleries/<%- gallery.cover%>)">
                            <!--<img src="https://cdn.jsdelivr.net/gh/321hjd/ImageBed/galleries/<%- gallery.cover %>" alt="img" class="gallery-cover-img">-->
                        </div>
                        <p class="gallery-name">
                            <%- gallery.name %>
                        </p>
                    </a>
                </div>
                <% } %>
            </div>
            <% } %>
        </div>
    </main>
    • 这是gallery.ejs文件,同样url需要修改为自己的图床地址
    <link rel="stylesheet" href="/css/gallery.css">
    <link rel="stylesheet" type="text/css" href="<%- theme.libs.css.fancybox %>">
    <link rel="stylesheet" type="text/css" href="<%- theme.libs.css.justifiedGallery %>">
    
    <%- partial('_partial/post-cover') %>
    
    <%
    let galleries = [];
    if (site.data && site.data.galleries) {
        galleries = site.data.galleries;
    }
    var pageTitle = page.title;
    function getCurrentGallery(galleries, pageTitle) {
        for (let i = 0; i < galleries.length; i++) {
            if (galleries[i]['name'] == pageTitle) {
                return galleries[i];
            }
        }
    }
    var currentGallery = getCurrentGallery(galleries, pageTitle)
    var photos = currentGallery.photos;
    let imageStr = ''
    for (var i = 0, len = photos.length; i < len; i++) {
        var photo = photos[i];
    <!-- 这儿的网址:https://cdn.jsdelivr.net/gh/321hjd/ImageBed/galleries/ 改为你图片放的位置的网址,比如你用Github图床的话,就改为你图床的网址 -->
        imageStr += "<a href=\"https://cdn.jsdelivr.net/gh/321hjd/ImageBed/galleries/" + photo + "\"\n" +
                "     class=\"photo-item\" rel=\"example_group\"\n" +
                "     data-fancybox=\"images\">\n" +
                "      <img src=\"https://cdn.jsdelivr.net/gh/321hjd/ImageBed/galleries/" + photo + "\"\n" +
                "       alt=" + photo + ">\n" +
                "    </a>"
    }
    %>
    
    <!--   "  <p class=\"photo-name\">" + photo + "</p>\n" +
    文件名先注释掉  -->
    
    <!-- 不加密写法 -->
    <!-- <div class="container">
        <div class="photo-wrapper" >
            <div class="waterfall" id="mygallery">
                <%- imageStr %>
            </div>
        </div>
    </div> -->
    
    <main class="content" >
    <!-- 加密写法 -->
    <div class="container">
        <div class="photo-wrapper">
            <% if (page.password ) { %>
                <!-- <script src="/lib/crypto-js.js"></script> -->
                <script src="/js/crypto-js.js"></script>
                <script src="/js/gallery-encrypt.js"></script>
                <div id="hbe-security">
                    <div class="hbe-input-container">
                        <input type="password" class="hbe-form-control" id="pass"  placeholder="请输入密码查看内容"/>
                        <a href="javascript:;" class="btn-decrypt" id="btn_decrypt">解密</a>
                    </div>
                </div>
                <div  id="mygallery">
                    <div class="waterfall" id="encrypt-blog" style="display:none">
                        <%- aes(imageStr, page.password) %>
                    </div>
                </div>
                
            <% } else { %>
                <div class="waterfall" id="encrypt-blog">
                    <%- imageStr %>
                </div>
            <% } %>
        </div>
    </div>
    <main>
    <script src="<%- theme.libs.js.lazyload %>"></script>
    <script src="<%- theme.libs.js.fancybox %>"></script>
    <script src="<%- theme.libs.js.justifiedGallery %>"></script>
    
    <script>
      // $(".waterfall").lazyload();
    $("a[rel=example_group]").fancybox();
    //  不加密写法
    // $("#mygallery").justifiedGallery({margins: 5, rowHeight: 150});
    $("#encrypt-blog").justifiedGallery({margins: 5, rowHeight: 150});
    </script>
  • source/galleries/下创建相册(比如“壁纸”,用于下面测试)文件夹,并在其下创建index.md,并设置Front-mattery(注意这里的typelayout都是gallery而非galleries,这与前面的gallery.ejs、galleries.ejs相关)

    ---
    title: 壁纸
    date: 2021-07-19 20:27:35
    type: gallery
    layout: gallery
    ---
  • 在根目录下新建/source/_data/galleries.json,添加如下内容

    这里的name必须和上一步的title一致。另外我的图床图片地址是/galleries/星空/01.jpg,所以前面ejs文件中的url是那样。

    [
      {
        "name": "壁纸",	
        "cover": "星空/01.jpg",
        "description": "壁纸",
        "photos": [
          "星空/01.jpg",
          "星空/02.jpg",
          "星空/03.jpg",
          "星空/04.jpg",
          "星空/05.jpg",
          "星空/06.jpg",
          "星空/07.jpg",
          "星空/08.jpg",
          "星空/09.jpg",
          "星空/10.jpg",
          "星空/11.jpg",
          "星空/12.jpg",
          "星空/13.jpg",
          "星空/14.jpg",
          "星空/15.jpg",
          "星空/16.jpg"
        ]
      }
    ]
  • 现在编译一下应该可以显示了,但是布局很难看且不能放大。因为还需要两个插件fancyboxjustifiedGallery。(gallery.ejs文件里引用了,但我们没下载这俩插件)

    • 打开主题目录下的配置文件_config.yml,找到存放前端库链接的地方(可搜索libs),将两插件对应的cssjs链接写在那儿(不同的版本可以到官网上去找)。

       css:
      # 新增插件-用于调整相册布局,可以令图片具有点击放大功能,且布局美观
         fancybox: https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.css     
         justifiedGallery: https://cdn.staticfile.org/justifiedGallery/3.7.0/css/justifiedGallery.min.css
        js:
         # 新增插件-用于调整相册布局
         fancybox: https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.js     
         justifiedGallery: https://cdn.staticfile.org/justifiedGallery/3.7.0/js/jquery.justifiedGallery.min.js
    • 现在编译就可以看到比较舒适的相册页面了。

  • 相册加密(AES加密)

    • 具体实现可以参考:使用AES算法加密Hexo相册

    • 在主题根目录下新建目录及文件:scripts/helpers/encrypt.js

      /* global hexo */
      'use strict';
      const CryptoJS = require('crypto-js');
      hexo.extend.helper.register('aes', function(content,password){
        content = escape(content);
        content = CryptoJS.enc.Utf8.parse(content);
        content = CryptoJS.enc.Base64.stringify(content);
        content = CryptoJS.AES.encrypt(content, String(password)).toString();
      
        return content;
      });
    • 然后修改gallery.ejs文件(这一步不需要做,因为前面那段代码其实已经写好了,就是“加密写法”那里)

    • 修改/themes/hexo-theme/matery/source/css/my.css,美化解密按钮

      .hbe-input-container  .btn-decrypt{
        display: inline-block;
        vertical-align: top;
        width: 120px;
        height: 32px;
        line-height: 32px;
        font-size: 16px;
        color: #ffffff;
        background-color: #3f90ff;
        text-align: center;
        -webkit-border-radius: 3px;
        -moz-border-radius: 3px;
        border-radius: 3px;
      }
    • 手动安装crypto-js插件,到node_modules/crypto-js/下找到crypto-js.js文件,并复制到主题目录下的source/js/下(注意gallery.ejs中的引用目录可能需要修改<script src="/js/crypto-js.js"></script>

      npm install crypto-js
    • 然后在主题目录的source/js/下新建gallery-encrypt.js,将我的代码粘进去就好(主要是不知道原来是从哪儿找来的了😢

      https://cdn.jsdelivr.net/gh/321hjd/CDN-for-Hexo@CDN-for-Hexo-0.0.3/source/js/gallery-encrypt.js

    • 最后需要在相册比如“壁纸”目录下index.md中的Front-matter中添加password,自己设置一个密码就好,如:password: 123

4.3 音乐模块

这里我是设置了一个吸底模式的音乐模块和一个单独音乐页面。如果愿意就把音乐页面放在主页,根据注释操作即可。另外注意歌单歌曲过多可能会显示不出来,尽量少一些为好。(建议QQ音乐,网易云经常抽风,不知道为啥)

  • 吸底模式:参考主题目录的_config.yml注释即可

    # 是否在首页显示音乐.
    music:
      enable: true
      title: #非吸底模式有效
        enable: true
        show: 听听音乐
      autoHide: true    # hide automaticaly
      server: netease   #require	music platform: netease(网易云), tencent, kugou, xiami, baidu
      type: playlist    #require song, playlist, album, search, artist
      id: 6862612332     #require	song id / playlist id / album id / search keyword
      fixed: true      # 开启吸底模式
      autoplay: false   # 是否自动播放
      theme: '#42b983'
      loop: 'all'       # 音频循环播放, 可选值: 'all', 'one', 'none'
      order: 'random'   # 音频循环顺序, 可选值: 'list', 'random'
      preload: 'auto'   # 预加载,可选值: 'none', 'metadata', 'auto'
      volume: 0.7       # 默认音量,请注意播放器会记忆用户设置,用户手动设置音量后默认音量即失效
      listFolded: true  # 列表默认折叠
      hideLrc: true     # 隐藏歌词
    # 提示: server可选netease(网易云音乐),tencent(QQ音乐),kugou(酷狗音乐),xiami(虾米音乐),baidu(百度音乐)。 type可选song(歌曲),playlist(歌单),album(专辑),search(搜索关键字),artist(歌手) id获取示例: 浏览器打开网易云音乐,点击我喜欢的音乐歌单,地址栏有一串数字,playlist的id即为这串数字。
  • 单独音乐页面

    • 同样配置主题目录下的_config.yml

      # 单独的音乐页面.(注意是musics,与之前的区分开)
      musics:
        enable: true
        url: /music	# 这是前面菜单优化部分新建的音乐页面的路径
        title:          #非吸底模式有效
          enable: true
          show: 听听音乐
        server: netease   #require music platform: netease, tencent, kugou, xiami, baidu
        type: playlist    #require song, playlist, album, search, artist
        id: 6862612332     #require song id / playlist id / album id / search keyword
        fixed: false      # 开启吸底模式
        autoplay: false   # 是否自动播放
        theme: '#42b983'
        loop: 'all'       # 音频循环播放, 可选值: 'all', 'one', 'none'
        order: 'random'   # 音频循环顺序, 可选值: 'list', 'random'
        preload: 'auto'   # 预加载,可选值: 'none', 'metadata', 'auto'
        volume: 0.7       # 默认音量,请注意播放器会记忆用户设置,用户手动设置音量后默认音量即失效
        listFolded: false  # 列表默认折叠
        listMaxHeight: "525px" #列表最大高度
    • themes/hexo-theme-matery/layout/_widget/下的music.ejs复制一份命名为musics.ejs

    • 然后再在themes/hexo-theme-matery/layout/下新建musics.ejs文件,粘贴代码:

      <style type="text/css">
          /* don't remove. */
          .about-cover {
              height: 75vh;
          }
      </style>
      
      <%- partial('_partial/bg-cover') %>
      
      <main class="content">
          <div id="aboutme" class="container about-container">
              <div class="card">
                  <div class="card-content">
                      <div class="music-player">
                          <% if (theme.musics && theme.musics.enable) { %>
                              <%- partial('_widget/musics') %>
                              <style>
                              .bubbles > .particle {
                                  /*初始透明度为0*/
                                  opacity: 0;
                                  position: absolute;
                                  /*初始颜色为荧光色,透明度为0.7*/
                                  background-color: rgba(128,255,0,0.7);
                                  /*使用bubbles动画,持续时间18秒,缓慢进入,无限循环*/
                                  animation: bubbles 18s ease-in infinite;
                                  border-radius: 100%;
                              }
                              /*css keyframes 动画*/
                              @keyframes bubbles {
                                  0% {
                                      opacity: 0;
                                  }
                                  5% {
                                      opacity: 1;
                                      transform: translate(0, -20%);
                                  }
                                  /*这里-8000%表示是气泡的8000%*/
                                  100% {
                                      opacity: 0;
                                      transform: translate(0, -8000%);
                                  }
                              }
                              </style>
                              <!-- 这里让元素宽度100%(和页面等宽) -->
                              <div style="width: 100%; height: 100%; position: relative; bottom: 0px;" class="particletext bubbles">
                              </div>
                              <script type="text/javascript" src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
                              <script>
                                function bubbles() {
                                   $.each($(".particletext.bubbles"), function(){
                                      var bubblecount = ($(this).width()/50)*10;
                                      for(var i = 0; i <= bubblecount; i++) {
                                         var size = ($.rnd(40,80)/10);
                                         //这里的animation-delay很重要,关系到你的特效是否看上去是连续无断层的,上一步中css是18秒,所以这一步中延迟时间就设置成$.rnd(0,180)/10)
                                         $(this).append('<span class="particle" style="top:' + $.rnd(20,80) + '%; left:' + $.rnd(0,95) + '%;width:' + size + 'px; height:' + size + 'px;animation-delay: ' + ($.rnd(0,180)/10) + 's;"></span>');
                                      }
                                   });
                                }
                                jQuery.rnd = function(m,n) {
                                    m = parseInt(m);
                                    n = parseInt(n);
                                    return Math.floor( Math.random() * (n - m + 1) ) + m;
                                }
                                bubbles();
                              </script>
                              
                          <% } %>
                      </div>
                  </div>
              </div>
          </div>
      </main>

4.4 快速导航

这一部分暂时没做完个性化,仅仅是将别人的导航页面copy过来了而已。下面只介绍基本方法。另外其实有两种,一种是真正的导航页面;另一种是简单的浏览器主页。我比较偏向于简约版的后者。

  • 绕过渲染。因为hexo 编译会对主题模板进行渲染之后生成静态页面,但是这个导航的网站本身就是 html文件,因此不需要渲染,那么跳过渲染就需要配置根目录_config.yml中的 skip_render

    # 指定目录跳过hexo渲染
    skip_render:
      - 'tools/**'
  • 工具箱页面在4.1节已经新建完成。

  • 添加WebStackPage导航网站(这是一位名叫 Viggo 的UI设计师的公益项目,开源的静态网站,源码本身就是成品,下载代码之后就可以直接使用。)

    • 从官方项目地址克隆到本地

      git clone https://github.com/WebStackPage/WebStackPage.github.io 
    • 将里面的文件放在博客根目录的source/tools/下即可

    • 这时候编译进入<工具箱>页面应该能看到如下效果

    WebStackPage

    • 然后后续自己修改细节即可
  • 添加D.Young大叔设计的主页

    • 同上,克隆到本地然后放入tools/再编译即可。效果如下:

    主页

5. Valine评论模块

5.1 Valine评论模块添加

  • leancloud官网注册并创建应用(建议使用国际版,因为后面的artitalk模块使用国际版更加方便)

  • 修改主题目录下配置文件_config.yml,激活Valine

    valine:
      enable: true
      appId: XXXXXXXXXXXXXXXXXXXXX	# appId和appKey是在leancloud注册后获取的(设置->应用凭证)
      appKey: XXXXXXXXXXXXXXXXXXXX
      notify: true
      verify: true
      visitor: true
      avatar: 'mm' # Gravatar style : mm/identicon/monsterid/wavatar/retro/hide
      pageSize: 10
      placeholder: 'just go go' # Comment Box placeholder
  • 为添加博主、访客、小伙伴等tag,以及直接通过邮箱或QQ拉取头像,直接使用大佬魔改后的Valine.min.js文件,并覆盖themes/hexo-theme-matery/source/libs/valine/Valine.min.js

  • 然后配置themes/hexo-theme-matery/layout/_partia/valine.ejs文件

    <script>
    	new Valine({ 
    		el: '#vcomments', 
    		enableQQ: '<%= theme.valine.enableQQ %>',  
    		appId: '<%- theme.valine.appId %>',
    		appKey: '<%- theme.valine.appKey %>', 
    		visitor: '<%- theme.valine.visitor %>' === 'true',
    		avatar: '<%- theme.valine.avatar %>',
    		pageSize: '<%- theme.valine.pageSize %>', 
    		lang: '<% if (config.language == "zh-CN") { %>zh-cn<% } else { %>en<% } %>', 
    		placeholder: '<%= theme.valine.placeholder %>',
    		meta: ['nick', 'mail'],
    		requiredFields: ['nick','mail'],	//必填项
    		tagMeta: ["博主", "小伙伴", "访客"],
    		master: ["d502ea4605b856df3b9b73bad1e8592e"],	// 我的邮箱(MD5加密后)似乎只能用小写,大写无法识别
    		// friends: // 小伙伴MD5加密后的邮箱
    		// metaPlaceholder: // 昵称和邮箱无内容时的显示内容
    		recordIP: true, 
    		emojiCDN: '//i0.hdslb.com/bfs/emote/',
    		// 表情title和图片映射
    		emojiMaps: { 
                //第一个是自定义表情的示例,模仿添加即可
    			"让我瞅瞅": "https://i.loli.net/2021/07/18/bzTH82kc7KnsBXC.jpg",
    			"tv_doge": "6ea59c827c414b4a2955fe79e0f6fd3dcd515e24.png", 
    			"tv_亲亲": "a8111ad55953ef5e3be3327ef94eb4a39d535d06.png", 
    			"tv_偷笑": "bb690d4107620f1c15cff29509db529a73aee261.png",
    			"tv_再见": "180129b8ea851044ce71caf55cc8ce44bd4a4fc8.png", 
    			"tv_冷漠": "b9cbc755c2b3ee43be07ca13de84e5b699a3f101.png",
    			"tv_发怒": "34ba3cd204d5b05fec70ce08fa9fa0dd612409ff.png",
    			"tv_发财": "34db290afd2963723c6eb3c4560667db7253a21a.png", 
    			"tv_可爱": "9e55fd9b500ac4b96613539f1ce2f9499e314ed9.png", 
    			"tv_吐血": "09dd16a7aa59b77baa1155d47484409624470c77.png", 
    			"tv_呆": "fe1179ebaa191569b0d31cecafe7a2cd1c951c9d.png",
    			"tv_呕吐": "9f996894a39e282ccf5e66856af49483f81870f3.png",
    			"tv_困": "241ee304e44c0af029adceb294399391e4737ef2.png",
    			"tv_坏笑": "1f0b87f731a671079842116e0991c91c2c88645a.png",
    			"tv_大佬": "093c1e2c490161aca397afc45573c877cdead616.png",
    			"tv_大哭": "23269aeb35f99daee28dda129676f6e9ea87934f.png",
    			"tv_委屈": "d04dba7b5465779e9755d2ab6f0a897b9b33bb77.png",
    			"tv_害羞": "a37683fb5642fa3ddfc7f4e5525fd13e42a2bdb1.png",
    			"tv_尴尬": "7cfa62dafc59798a3d3fb262d421eeeff166cfa4.png",
    			"tv_微笑": "70dc5c7b56f93eb61bddba11e28fb1d18fddcd4c.png",
    			"tv_思考": "90cf159733e558137ed20aa04d09964436f618a1.png",
    			"tv_惊吓": "0d15c7e2ee58e935adc6a7193ee042388adc22af.png", 
    			"tv_打脸": "56ab10b624063e966bfcb76ea5dc4794d87dfd47.png",
    			"tv_抓狂": "fe31c08edad661d63762b04e17b8d5ae3c71a757.png",
    			"tv_抠鼻": "c666f55e88d471e51bbd9fab9bb308110824a6eb.png", 
    			"tv_斜眼笑": "911f987aa8bc1bee12d52aafe62bc41ef4474e6c.png",
    			"tv_无奈": "ea8ed89ee9878f2fece2dda0ea8a5dbfe21b5751.png",
    			"tv_晕": "5443c22b4d07fb1907ccc610c8e6db254f2461b7.png",
    			"tv_流汗": "cead1c351ab8d79e9f369605beb90148db0fbed3.png",
    			"tv_流泪": "7e71cde7858f0cd50d74b0264aa26db612a8a167.png",
    			"tv_流鼻血": "c32d39db2737f89b904ca32700d140a9241b0767.png",
    			"tv_点赞": "f85c354995bd99e28fc76c869bfe42ba6438eff4.png",
    			"tv_生气": "26702dcafdab5e8225b43ffd23c94ac1ff932654.png", 
    			"tv_生病": "8b0ec90e6b86771092a498c54f09fc94621c1900.png", 
    			"tv_疑问": "0793d949b18d7be716078349c202c15ff166f314.png",
    			"tv_白眼": "c1d59f439e379ee50eef488bcb5e5378e5044ea4.png",
    			"tv_皱眉": "72ccad6679fea0d14cce648b4d818e09b8ffea2d.png",
    			"tv_目瞪口呆": "0b8cb81a68de5d5365212c99375e7ace3e7891b7.png",
    			"tv_睡着": "8b196675b53af58264f383c50ad0945048290b33.png",
    			"tv_笑哭": "1abc628f6d4f4caf9d0e7800878f4697abbc8273.png",
    			"tv_腼腆": "89712c0d4af73e67f89e35cbc518420380a7f6f4.png",
    			"tv_色": "61822c7e9aae5da76475e7892534545336b23a6f.png",
    			"tv_调侃": "4bc022533ef31544ca0d72c12c808cf4a1cce3e3.png",
    			"tv_调皮": "b9c41de8e82dd7a8515ae5e3cb63e898bf245186.png", 
    			"tv_鄙视": "6e72339f346a692a495b123174b49e4e8e781303.png", 
    			"tv_闭嘴": "c9e990da7f6e93975e25fd8b70e2e290aa4086ef.png",
    			"tv_难过": "87f46748d3f142ebc6586ff58860d0e2fc8263ba.png",
    			"tv_馋": "fc7e829b845c43c623c8b490ee3602b7f0e76a31.png",
    			"tv_鬼脸": "0ffbbddf8a94d124ca2f54b360bbc04feb6bbfea.png",
    			"tv_黑人问号": "45821a01f51bc867da9edbaa2e070410819a95b2.png",
    			"tv_鼓掌": "1d21793f96ef4e6f48b23e53e3b9e42da833a0f6.png" 
    			// ... 更多表情 
    		} 
    	});
    
    </script>

5.2 增强评论系统

  • 功能:

    • 支持评论回复提醒(微信/QQ/邮件)
    • 支持@对方时给对方发送邮件并自带主题
  • leancloud上部署评论增强系统:Valine-Admin-server(使用的是小康改版)

  • 配置环境变量:云引擎->设置->自定义环境变量

    我只设置了邮件和微信提醒,没用QQ的。设置完成后再次部署生效。

    变量 示例 说明
    SITE_NAME hjd’blog [必填]博客名称
    SITE_URL https://321hjd.github.io/ [必填]首页地址
    SMTP_SERVICE QQ 邮件服务提供商,支持 QQ、163、126、Gmail以及更多
    SMTP_USER 2857126002@qq.com [必填]SMTP登录用户
    SMTP_PASS xxx [必填]SMTP登录密码(QQ邮箱可通过设置-账户-SMTP服务-生成授权码获取)
    SENDER_NAME hjd’blog [必填]发件人
    SENDER_EMAIL 2857126002@qq.com [必填]发件邮箱
    BLOGGER_EMAIL 2857126002@qq.com [可选]博主通知收件地址,默认使用SENDER_EMAIL
    SCKEY xxx Server酱 SCKEY 用于微信通知
    DISABLE_EMAIL false 如果为true,关闭邮件通知
    TEMPLATE_NAME custom2 设置回复邮件的主题样式
  • 微信提醒还需要按照Server酱-消息通道 的指示注册企业微信并创建应用才行

  • 博主回复别人后的邮件提醒效果:

    邮件提醒
  • 有人评论时的微信提醒效果

    微信提醒
  • 后台管理。增删改评论在leancloud的数据存储->结构化数据->Comment处操作即可

  • 防止休眠(如果不设置,每过一段时间重新部署,才能收到评论提醒)。需要购买域名,具体请参考:Valine评论系统详解

6. 说说模块Artitalk

  • leancloud官网(建议使用国际版,否则需要配置serverurl)注册并绑定手机号和邮箱。然后创建应用(与Valine不是同一个)

    注意下面一定要设置好(尤其是权限),否则可能发不了说说,或者任意人都能在你的博客上修改或发表说说。

    • 结构化数据中创建class,命名为shuoshuo
    • 在你新建的应用中找到结构化数据下的用户。点击添加用户,输入想用的用户名及密码。(这就是你用来发说说的账号)
    • 回到结构化数据中,点击 class 下的 shuoshuo。找到权限,在 Class 访问权限中将 add_fields 以及 create 权限设置为指定用户,输入你刚才输入的用户名会自动匹配。为了安全起见,将 deleteupdate 也设置为跟它们一样的权限。(注意一定要等匹配后看到显示了objectId才没问题)
    • 然后新建一个名为atComment的class,权限默认
    • 点击 class 下的 _User 添加列,列名称为 img,默认值填上你这个账号想要用的发布说说的头像url,这一项不进行配置,说说头像会显示为默认头像 —— Artitalk 的 logo。
    • _User 中的权限全部调为指定用户,或者数据创建者,为了保证不被篡改用户数据已达到强制发布说说
  • 下载Artitalk并放入组件

    git clone --depth 2 git@github.com:ArtitalkJS/Artitalk.git
    • themes/hexo-theme-matery/source/libs/下新建artitalk文件夹。将下载所得Artitalkdist下的组件代码(两个文件:artitalk.min.jsartitalk.min.css)全部放入artitalk/
  • 引入该模块。修改主题配置文件_config.yml,在libs下加入刚刚的两个文件,如:

    libs:
      css:
        artitalk: /libs/artitalk/artitalk.min.css
       js:
        artitalk: /libs/artitalk/artitalk.min.js 
  • 引入css。在themes/hexo-theme-matery/layout/_partial/head.ejs的尾部对应位置引入css(参照其它代码即可)

    <link rel="stylesheet" type="text/css" href="<%- theme.jsDelivr.url %><%- url_for(theme.libs.css.artitalk) %>">
  • 模块准备。在主题目录下 /layout/ 目录新建一个 artitalk.ejs 文件

    <%- partial('_partial/bg-cover') %>
    
    <style ype="text/css">
    
    #pubShuo {
    
      margin-right: 5px;
    }
    
    #operare_artitalk .shuoshuo_input_log {
        outline-style: none;
        margin-top: 5px;
        border: 1px solid #ccc;
        border-radius: 6px;
        padding: 8px 16px;
        font-size: 12px;
        background-color: transparent;
    
        color: #0bb7fbd6;
        width: 70%;
        height: 28px;
        margin-left: 10px;
    }
    
    #artitalk_main {
    
      margin-top: 5px ;
      margin-left: 5%;
      margin-right: 5%;
    
    }
    
    #lazy{
      margin-top: 40px;
    }
    
    #artitalk_main .cbp_tmtimeline > li .cbp_tmlabel::after {  
      right: 100%;  
      border: solid transparent;
      z-index: -1; 
      content: " "; 
      height: 0;  
      width: 0;   
      position: absolute;
      pointer-events: none; 
      border-right-color:  #0bb7fbd6 ;
      border-width: 10px;   
      top: 4px; 
    }
    
    </style>
    
    
    <script src="<%- theme.jsDelivr.url %><%- url_for(theme.libs.js.artitalk) %>"></script>
    
    <article id="articles11" class="container  chip-container">
      <div class="row ">
    
          <div class=" card">
            <div class="card-content" >
              <div class="tag-title center-align">
                    <i class="fas fa-pen-alt"></i> 说说
               </div>
              <div id="artitalk_main"></div>
            </div>  
          </div>
    
      </div>
    </article>
    <script>
      new Artitalk({
            appId: "<%=  theme.artitalk.appId  %>",
            appKey: "<%=  theme.artitalk.appKey  %>",
          <% if (theme.artitalk.serverURL) { %>
              serverURL: "<%=  theme.artitalk.serverURL  %>",
          <% } %>
          <% if (theme.artitalk.lang) { %>
              lang: "<%=  theme.artitalk.lang  %>",
          <% } %>
          <% if (theme.artitalk.pageSize) { %>
              pageSize: "<%=  theme.artitalk.pageSize  %>",
          <% } %>
          <% if (theme.artitalk.shuoPla) { %>
              shuoPla: "<%=  theme.artitalk.shuoPla  %>",
          <% } %>
          <% if (theme.artitalk.avatarPla) { %>
              avatarPla: "<%=  theme.artitalk.avatarPla  %>",
          <% } %>
          <% if (theme.artitalk.motion == 0) { %>
              motion: 0,
          <% } else { %>
              motion: 1,
          <% }  %>
          <% if (theme.artitalk.bgImg) { %>
              bgImg: "<%=  theme.artitalk.bgImg  %>",
          <% } %>
          <% if (theme.artitalk.color1) { %>
              color1: "<%=  theme.artitalk.color1  %>",
          <% } %>
          <% if (theme.artitalk.color2) { %>
              color2: "<%=  theme.artitalk.color2  %>",
          <% } %>
          <% if (theme.artitalk.color3) { %>
              color3: "<%=  theme.artitalk.color3  %>",
          <% } %>
          <% if (theme.artitalk.cssUrl) { %>
              cssUrl: "<%=  theme.artitalk.cssUrl  %>",
          <% } %>
              atEmoji: {
                  baiyan: "https://cdn.jsdelivr.net/gh/Artitalk/Artitalk-emoji/baiyan.png",
                  bishi: "https://cdn.jsdelivr.net/gh/Artitalk/Artitalk-emoji/bishi.png",
                  bizui: "https://cdn.jsdelivr.net/gh/Artitalk/Artitalk-emoji/bizui.png",
                  chan: "https://cdn.jsdelivr.net/gh/Artitalk/Artitalk-emoji/chan.png",
                  daku: "https://cdn.jsdelivr.net/gh/Artitalk/Artitalk-emoji/daku.png",
                  dalao: "https://cdn.jsdelivr.net/gh/Artitalk/Artitalk-emoji/dalao.png",
                  dalian: "https://cdn.jsdelivr.net/gh/Artitalk/Artitalk-emoji/dalian.png",
                  dianzan: "https://cdn.jsdelivr.net/gh/Artitalk/Artitalk-emoji/dianzan.png",
                  doge: "https://cdn.jsdelivr.net/gh/Artitalk/Artitalk-emoji/doge.png",
                  facai: "https://cdn.jsdelivr.net/gh/Artitalk/Artitalk-emoji/facai.png",
                  fadai: "https://cdn.jsdelivr.net/gh/Artitalk/Artitalk-emoji/fadai.png",
                  fanu: "https://cdn.jsdelivr.net/gh/Artitalk/Artitalk-emoji/fanu.png",
               },
         })
    </script>
    
  • 在主题配置文件中添加artitalk配置

    artitalk:
      enable: true
      appId: # 刚刚创建应用的AppID
      appKey: # 刚刚创建应用的AppKey
      lang: zh # 语言设置,zh为汉语,en为英语,es为西班牙语。默认为汉语  
      pageSize: 10  #每页说说的显示数量   
      # shuoPla: #在编辑说说的输入框中的占位符  
      avatarPla: # https://cdn.jsdelivr.net/gh/321hjd/321hjd.github.io/source/medias/avatar.jpg #自定义头像url的输入框的占位符  
      # motion: #加载动画的开关,1为开,0为关,默认为开  
      # bgImg: #说说输入框背景图片url  
      color1: linear-gradient(45deg, rgb(109, 208, 242) 15%, rgb(245, 200, 190) 85%)  #说说背景颜色1&按钮颜色1  
      color2: linear-gradient(45deg, rgb(109, 208, 242) 15%, rgb(245, 200, 190) 85%)  #说说背景颜色2&按钮颜色2  
      color3: black #说说字体颜色
  • 创建说说页面并添加链接。在第三部分的4.1节已经创建完成。

  • 现在编译再进入说说页面应该就可以了。

参考链接

四、性能优化

1. 图片懒加载

  • 安装图片懒加载插件:hexo-lazyload-image

    npm install hexo-lazyload-image --save
  • 在博客根目录下的配置文件末尾添加

    # 懒加载配置
    lazyload:
      enable: true
      onlypost: false   # 是否只对文章的图片做懒加载
      loadingImg: /medias/loading.gif # 即放一个表示加载中的图片(这个图片得自己去找一个放在themes/hexo-theme-matery/source/medias/目录下)
  • 一般情况下懒加载会和gallery插件会发生冲突,结果可能就是点开图片,左翻右翻都是loading image。matery主题的解决方案是:修改 /themes/matery/source/js 中的 matery.js文件,在第108行加上

    $(document).find('img[data-original]').each(function(){
        $(this).parent().attr("href", $(this).attr("data-original"));
    });
  • 可能还有个小问题,首页的logo点击会直接打开logo图,而不是跳到首页。解决方案:打开 /themes/matery/layout/_partial/header.ejs文件,

    imgspan的两个头加个div

    <div class="brand-logo">
        <a href="<%- url_for() %>" class="waves-effect waves-light">
            <div>
                <% if (theme.logo !== undefined && theme.logo.length > 0) { %>
                <img src="<%= theme.logo %>" class="logo-img" alt="LOGO">
                <% } %>
                <span class="logo-span"><%- config.title %></span>
            </div>
        </a>
    </div>
  • 懒加载优化(即提前加载图片,其实也可以不做)。具体请参考:Hexo进阶之各种优化

2. 跳转页面载入动画

  • 在博客根目录下新建文件夹scripts(之前加密相册时已经建好了其实),然后在该目录下新建loading-pages.js,填入代码即可

    /* global hexo */
    "use strict";
    hexo.extend.filter.register('after_render:html', function (htmlContent) {
         const injectHead =
     `<style type="text/css" lang="css">
        #loading-container{
            position: fixed;
            top: 0;
            left: 0;
            min-height: 100vh;
            width: 100vw;
            z-index: 9999;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            background: #FFF;
            text-align: center;
            /* loader页面消失采用渐隐的方式*/
            -webkit-transition: opacity 1s ease;
            -moz-transition: opacity 1s ease;
            -o-transition: opacity 1s ease;
            transition: opacity 1s ease;
        }
        .loading-image{
            width: 120px;
            height: 50px;
            transform: translate(-50%);
        }
    
        .loading-image div:nth-child(2) {
            -webkit-animation: pacman-balls 1s linear 0s infinite;
            animation: pacman-balls 1s linear 0s infinite
        }
    
        .loading-image div:nth-child(3) {
            -webkit-animation: pacman-balls 1s linear .33s infinite;
            animation: pacman-balls 1s linear .33s infinite
        }
    
        .loading-image div:nth-child(4) {
            -webkit-animation: pacman-balls 1s linear .66s infinite;
            animation: pacman-balls 1s linear .66s infinite
        }
    
        .loading-image div:nth-child(5) {
            -webkit-animation: pacman-balls 1s linear .99s infinite;
            animation: pacman-balls 1s linear .99s infinite
        }
    
       .loading-image div:first-of-type {
            width: 0;
            height: 0;
            border: 25px solid #49b1f5;
            border-right-color: transparent;
            border-radius: 25px;
            -webkit-animation: rotate_pacman_half_up .5s 0s infinite;
            animation: rotate_pacman_half_up .5s 0s infinite;
        }
        .loading-image div:nth-child(2) {
            width: 0;
            height: 0;
            border: 25px solid #49b1f5;
            border-right-color: transparent;
            border-radius: 25px;
            -webkit-animation: rotate_pacman_half_down .5s 0s infinite;
            animation: rotate_pacman_half_down .5s 0s infinite;
            margin-top: -50px;
        }
        @-webkit-keyframes rotate_pacman_half_up {0% {transform: rotate(270deg)}50% {transform: rotate(1turn)}to {transform: rotate(270deg)}}
    
        @keyframes rotate_pacman_half_up {0% {transform: rotate(270deg)}50% {transform: rotate(1turn)}to {transform: rotate(270deg)}}
    
        @-webkit-keyframes rotate_pacman_half_down {0% {transform: rotate(90deg)}50% {transform: rotate(0deg)}to {transform: rotate(90deg)}}
    
        @keyframes rotate_pacman_half_down {0% {transform: rotate(90deg)}50% {transform: rotate(0deg)}to {transform: rotate(90deg)}}
    
        @-webkit-keyframes pacman-balls {75% {opacity: .7}to {transform: translate(-100px, -6.25px)}}
    
        @keyframes pacman-balls {75% {opacity: .7}to {transform: translate(-100px, -6.25px)}}
    
    
        .loading-image div:nth-child(3),
        .loading-image div:nth-child(4),
        .loading-image div:nth-child(5),
        .loading-image div:nth-child(6){
            background-color: #49b1f5;
            width: 15px;
            height: 15px;
            border-radius: 100%;
            margin: 2px;
            width: 10px;
            height: 10px;
            position: absolute;
            transform: translateY(-6.25px);
            top: 25px;
            left: 100px;
        }
        .loading-text{
            margin-bottom: 20vh;
            text-align: center;
            color: #2c3e50;
            font-size: 2rem;
            box-sizing: border-box;
            padding: 0 10px;
            text-shadow: 0 2px 10px rgba(0,0,0,0.2);
        }
        @media only screen and (max-width: 500px) {
             .loading-text{
                font-size: 1.5rem;
             }
        }
        .fadeout {
            opacity: 0;
            filter: alpha(opacity=0);
        }
        /* logo出现动画 */
        @-webkit-keyframes fadeInDown{0%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}100%{opacity:1;-webkit-transform:none;transform:none}}
        @keyframes fadeInDown{0%{opacity:0;-webkit-transform:translate3d(0,-100%,0);}}
     </style>
     <script>
    (function () {
        const loaded = function(){
           setTimeout(function(){
                const loader = document.getElementById("loading-container");
                loader.className="fadeout" ;//使用渐隐的方法淡出loading page
                // document.getElementById("body-wrap").style.display="flex";
                setTimeout(function(){
                    loader.style.display="none";
                },1000); 
            },1000);//强制显示loading page 1s  
        };
        loaded();
    })()
     </script>`;
         const injectBody = `
     <div id="loading-container">
         <p class="loading-text">玩命加载中 . . . </p> 
         <div class="loading-image">
             <div></div>
             <div></div>
             <div></div>
             <div></div> 
             <div></div>
         </div>
     </div>`;
         if (/<\/head>/gi.test(htmlContent)) {
             let lastIndex = htmlContent.lastIndexOf('</head>');
             htmlContent = htmlContent.substring(0, lastIndex) + injectHead + htmlContent.substring(lastIndex, htmlContent.length);
         }
         if (/<body>/gi.test(htmlContent)) {
             let index = htmlContent.indexOf('<body>');
             htmlContent = htmlContent.substring(0, index) + injectBody + htmlContent.substring(index, htmlContent.length);
         }
         return htmlContent;
     }, 1);

3. 新建文章时自动打开本地md编辑器

  • 在博客根目录下的scripts/下新建auto_open.js,添加代码:

    var spawn = require('child_process').exec;
    
    // Hexo 2.x 用户复制这段
    //hexo.on('new', function(path){
      //spawn('start  "markdown编辑器绝对路径.exe" ' + path);
    //});
    
    // Hexo 3 用户复制这段
    hexo.on('new', function(data){
      spawn('start  "D:\Program Files\Typora\Typora.exe" ' + data.path);
    });
    • 注意:Typora.exe的路径根据实际情况修改。

4. jsDelivr + GitHub实现免费CDN加速

  • CDN简介及原理:如何使用jsDelivr+Github 实现免费CDN加速?

  • jsDelivr:免费、快速和可信赖的CDN加速服务

  • 实现

    • 新建GitHub仓库(我的叫CDN-for-Hexo

    • 将仓库克隆到本地:git clone git@github.com:{username}/{repo}.git

    • 将需要加速的资源文件复制到该本地仓库并上传到GitHub仓库(Hexo的静态资源cssjs、图片等)。我是将主题下的整个source文件夹都传上去了。

      git add .		# 添加所有文件到暂存区
      git status		# 查看状态
      git commit -m "CDN加速,第一次提交"		# 将文件提交到仓库
      git push		# 推送至远程仓库
    • 点击右边的release发布版本。如CDN-for-Hexo-1.0

  • 修改主题目录下的配置文件,通过jsDelivr引用资源。如:

    libs:
      css:
        matery: https://cdn.jsdelivr.net/gh/321hjd/CDN-for-Hexo@b4706a7/source/css/matery.css
        mycss: https://cdn.jsdelivr.net/gh/321hjd/CDN-for-Hexo@b4706a7/source/css/my.css
    • 引用方式为:https://cdn.jsdelivr.net/gh/你的用户名/你的仓库名@发布的版本号/文件路径

    经过测试,不写版本号似乎不能引用到最新资源。需要引用最新版的话,最好是仓库名@版本号CDN-for-Hexo@b4706a7而非CDN-for-Hexo@CDN-for-Hexo-1.0

    注:jsdelivr可以自动帮你生成.min版的jscss,所以你在设置jscss路径中可以直接写.min.xxx

  • 修改完成后再编译部署,会发现访问速度快了很多~

5. 文章永久链接优化

  • 为什么要生成唯一永久文章链接:确保在我们修改了Front-matter 内的博客标题title或创建日期date字段之后而不会改变链接地址。

  • 安装插件:

    npm install hexo-abbrlink --save
  • 配置。修改博客根目录配置文件的permalink属性

    permalink: posts/:abbrlink.html  # 此处可以自己设置,也可以直接使用 :/abbrlink
    abbrlink:
        alg: crc32   #算法: crc16(default) and crc32
        rep: hex     #进制: dec(default) and hex
  • 生成完后,原md文件的Front-matter 内会增加abbrlink 字段,值为生成的ID 。至此我们的文章链接将变为:

    https://{username}.github.io/posts/{abbrlink_id}.html

  • 引发的问题:插入图片的路径发生变化,前面新增了一个对应文章的abbrlink_id目录

    • 分析:生成图片链接时自己把abbrlink加上,是因为原来hexo的设计思想(因为post_asset_folder的存在)是将文档的图片放置在同名文件夹下,然后将md转换为html同样以该结构存储,即

      - 根目录(按原来的结构应该是/public/year/month/day/)
      	- MDfilename.html
      	- MDfilename_folder
        		- xxx.jpg
        		- ...
    • 解决方案:修改/node_modules/hexo-asset-image/index.js中的两行(即自己把abbrlink加入到image的生成路径中)

      • 在源码的12行附近var link = data.permalink;这一行的下面,添加 一行var abbrlink = data.abbrlink(即自己定义一个变量abbrlink获取生成的abbrlink
      • 在源码的51行附近,将原来的 $(this).attr('src' , config.root + link + src);改为$(this).attr('src' , config.root + link + abbrlink + '/' + src);

参考链接


文章作者: hjd
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 hjd !
评论
  目录