Hexo 实现实时预览编辑

点击下拉查看具体内容

参考自:Hexo 实现实时预览编辑 | 木头的博客 (mutoe.com)

主要在项目目录下安装 hexo-browsersync 插件

npm install hexo-browsersync --save

然后运行 hexo server, 看到以下内容就说明启动成功啦.【针对_config.Butterfly.yml需要重启hexo s】

[Browsersync] Access URLs:
 ----------------------------------
          UI: http://localhost:3001
 ----------------------------------
 UI External: http://localhost:3001
 ----------------------------------
INFO  Start processing
INFO  Hexo is running at http://localhost:4000/ . Press Ctrl+C to stop.

解决hexo引入图床,手机和web不显示图片的问题

点击下拉查看具体内容

这里以Butterfly主题为例

在butterfly\layout\includes\head.pug中【其中加号为需要添加的】

meta(name="author" content=pageAuthor)
meta(name="copyright" content=pageCopyright)
meta(name ="format-detection" content="telephone=no")
meta(name="theme-color" content=themeColor)
+ meta(name="referrer" content="no-referrer")

背景音乐添加

点击下拉查看具体内容

参考自hexo-butterfly魔改记录大全 | Black Flies (yyyzyyyz.cn)

这里参考作者的全局吸底Aplayer教程,为方便后续自己查阅,特摘抄出来。

首先安装hexo-tag-aplayer插件,官方github;

博客根目录安装:

npm install --save hexo-tag-aplayer

由于需要全局都插入aplayer和meting资源,为了防止插入重复的资源,需要把asset_inject设为false

在hexo的配置文件中

aplayer:
  meting: true
  asset_inject: false

在主题配置文件中,enable设为true和per_page设为true

# Inject the css and script (aplayer/meting)
aplayerInject:
  enable: true
  per_page: true

在跳转页面时不关闭音乐,需要开启pjax

# Pjax
# It may contain bugs and unstable, give feedback when you find the bugs.
# https://github.com/MoOx/pjax
pjax:
  enable: true
  exclude:
    # - xxxx
    # - xxxx

然后把代码插入到页脚中

 bottom:
    # - <script src="xxxx"></script>
    #require APlayer 
+    - <div class="aplayer no-destroy" data-id="6693541741" data-server="netease" data-type="playlist" data-fixed="true" data-autoplay="true" data-lrcType="-1"> </div>

butterfly导航栏修改方案

点击下拉查看具体内容

新建css

#nav a:hover {
  background: var(--sevene-main);
  transition: 0.3s;
}

#nav-totop:hover .totopbtn i {
  opacity: 1;
}
#nav-totop #percent {
  font-size: 12px;
  background: var(--sevene-white);
  color: var(--sevene-main);
  width: 25px;
  height: 25px;
  border-radius: 35px;
  display: flex;
  justify-content: center;
  align-items: center;
  transition: 0.3s;
}
.nav-fixed #nav-totop #percent,
.page #nav-totop #percent {
  background: var(--font-color);
  color: var(--card-bg);
}

#nav-totop {
  width: 35px;
}
#page-header:not(.is-top-bar) #percent {
  transition: 0.3s;
}
#page-header:not(.is-top-bar) #nav-totop {
  width: 0;
  opacity: 0;
  transition: width 0.3s, opacity 0.2s;
  margin-left: 0 !important;
}
#nav-totop #percent {
  font-weight: 700;
}
#nav-totop:hover #percent {
  opacity: 0;
  transform: scale(1.5);
  font-weight: 700;
}
.nav-fixed #nav-totop #percent,
.page #nav-totop #percent {
  font-size: 13px;
}
#page-header #nav #nav-right div {
  margin-left: 0.5rem;
  padding: 0;
}

#nav-totop {
  display: flex;
  align-items: center;
  justify-content: center;
  transition: 0.3s;
}
.nav-button {
  cursor: pointer;
}
div#menus {
  display: flex;
  align-items: center;
}
#page-header #nav .nav-button a {
  height: 35px;
  width: 35px;
  display: flex;
  align-items: center;
  justify-content: center;
}

#nav .site-page {
  padding-bottom: 0px;
}
#nav *::after {
  background-color: transparent !important;
}

/* 顶栏修改 */
#nav .menus_items .menus_item .menus_item_child li:hover a {
  color: white !important;
}

#nav .menus_items .menus_item .menus_item_child li {
  margin: 6px;
  border-radius: 5px !important;
  transition: all 0.3s;
}

#site-name,
.shuoshuo {
  white-space: nowrap;
  overflow: hidden;
}
#site-name {
  padding: 0 8px;
  position: relative;
}
#site-name *:not(i):hover {
  display: none !important;
}
#blog_name #site-name:hover::after {
  opacity: 1;
  transform: scale(1.01);
}
#blog_name #site-name::after {
  opacity: 0;
  background-color: var(--lyx-theme) !important;
  border-radius: 8px;
  -webkit-border-radius: 8px;
  -moz-border-radius: 8px;
  -ms-border-radius: 8px;
  -o-border-radius: 8px;
  transition: 0.3s;
  -webkit-transition: 0.3s;
  -moz-transition: 0.3s;
  -ms-transition: 0.3s;
  -o-transition: 0.3s;
  position: absolute;
  top: 0;
  right: 0;
  width: 100%;
  height: 100%;
  content: '\f015';
  box-shadow: 0 0 5px var(--lyx-theme);
  font-family: 'Font Awesome 6 Free';
  text-align: center;
  color: white;
}
#site-name i {
  position: absolute;
  top: 50%;
  left: 50% !important;
  transform: translate(-50%, -50%);
  left: 0;
  opacity: 0;
}
#site-name:hover i {
  opacity: 1;
}

/* 横向排布子菜单 */
#nav .menus_items .menus_item .menus_item_child li {
  display: inline-block;
}
/* 圆角隐藏 */
ul.menus_item_child {
  overflow: hidden;
  border-radius: 5px;
}

/* 一级菜单居中 */
#nav .menus_items {
  position: absolute;
  width: fit-content;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  height: 60px;
}

#nav .menus_items .menus_item:hover .menus_item_child {
  display: block;
  transform: translateX(-50%);
  right: auto;
  left: auto !important;
}
#nav .menus_items .menus_item:hover {
  padding: 0 5px 27px 5px !important;
  margin-bottom: -15px !important;
}
#nav .menus_items .menus_item .menus_item_child {
  top: 44px;
}

@media screen and (min-width: 768px) {
  .page .menus_item:hover > a.site-page {
    color: var(--sevene-white) !important;
    background: var(--sevene-main);
    transition: 0.3s;
    box-shadow: var(--sevene-shadow-main);
  }
}

#nav .menus_items .menus_item:hover .menus_item_child {
  padding: 6px 4px;
  box-sizing: content-box;
  line-height: 35px;
}

#nav .menus_items .menus_item .menus_item_child li {
  margin: 0 3px;
}
#nav .menus_items .menus_item .menus_item_child li a {
  padding: 0px 16px;
}

.nav-fixed #nav {
  transform: translateY(58px) !important;
  -webkit-transform: translateY(58px) !important;
  -moz-transform: translateY(58px) !important;
  -ms-transform: translateY(58px) !important;
  -o-transform: translateY(58px) !important;
}
#nav {
  padding: 0 calc((100% - 1420px) / 2);
  transition: 0.3s;
  background: var(--sevene-maskbgdeep);
  backdrop-filter: saturate(180%) blur(20px);
  transition: none !important;
  -webkit-transition: none !important;
  -moz-transition: none !important;
  -ms-transition: none !important;
  -o-transition: none !important;
}

#nav a {
  border-radius: 8px;
  color: var(--font-color);
}
.page #nav a:hover {
  color: var(--sevene-white) !important;
  background: var(--sevene-main);
  transition: 0.3s;
  box-shadow: var(--sevene-shadow-main);
}

#menus > div.menus_items > div > a {
  letter-spacing: 0.3rem;
  font-weight: 700;
  padding: 0em 0.3em 0em 0.5em;
  height: 35px;
}
#nav .menus_items .menus_item {
  padding: 0 5px;
  display: flex;
  flex-direction: column;
  margin: auto;
  align-items: center;
}

#menus > div.menus_items > div > a {
  line-height: 35px;
}

#page-header #nav a:hover,
#page-header.nav-fixed #nav a:hover,
#page-header.nav-fixed #nav #site-name:hover,
#page-header.nav-fixed #nav #toggle-menu:hover {
  color: var(--sevene-white);
  font-weight: bold;
}
#page-header.nav-fixed #nav a, #page-header.nav-fixed #nav #site-name, #page-header.nav-fixed #nav #toggle-menu {
  font-weight: bold;
}
#nav-totop .totopbtn i {
  position: absolute;
  display: flex;
  opacity: 0;
}
#page-name::before {
  font-size: 18px;
  position: absolute;
  width: 100%;
  height: 100%;
  border-radius: 8px;
  color: white !important;
  top: 0;
  left: 0;
  content: '回到顶部';
  background-color: var(--lyx-theme);
  transition: all 0.3s;
  -webkit-transition: all 0.3s;
  -moz-transition: all 0.3s;
  -ms-transition: all 0.3s;
  -o-transition: all 0.3s;
  opacity: 0;
  box-shadow: 0 0 3px var(--lyx-theme);
  line-height: 45px; /*如果垂直位置不居中可以微调此值,也可以删了*/
}
#page-name:hover:before {
  opacity: 1;
}
#name-container {
  transition: all 0.3s;
  -webkit-transition: all 0.3s;
  -moz-transition: all 0.3s;
  -ms-transition: all 0.3s;
  -o-transition: all 0.3s;
}
#name-container:hover {
  transform: translateX(-50%) scale(1.03);
}
#page-name {
  position: relative;
  padding: 10px 30px;
}

center#name-container {
  position: absolute;
  width: 100%;
  left: 50%;
  transform: translateX(-50%);
  font-family: 'ZhuZiAYuanJWD';
}
.nav-fixed.nav-visible #name-container {
  top: 60px;
  transition: 0.3s;
}
.nav-fixed.nav-visible #menus .menus_items {
  bottom: -0px;
  transition: 0.3s;
  line-height: 60px;
}
.nav-fixed #menus .menus_items {
  bottom: 60px;
  transition: 0.3s;
}
.nav-fixed #name-container {
  top: 15%;
  transition: 0.3s;
}
#name-container {
  bottom: 60px;
}

.mask-name-container {
  width: 1200px;
  height: 100%;
  position: absolute;
  overflow: hidden;
  left: 50%;
  transform: translateX(-50%);
}

@media screen and (max-width: 768px) {
  .mask-name-container {
    width: 600px;
  }
}
@media screen and (max-width: 500px) {
  .mask-name-container {
    display: none;
  }
}
#sidebar #sidebar-menus .menus_items .site-page:hover {
  color: var(--sevene-white);
  border-radius: var(--sevene-border-radius);
}
#nav .menus_items .menus_item > a > i:last-child {
  display: none;
}
#nav #search-button {
  font-size: 1.3em;
}

#page-header.not-top-img #nav .back-home-button {
  color: var(--sevene-fontcolor);
}
@media screen and (min-width: 900px) {
  #nav .back-home-button:hover {
    box-shadow: var(--sevene-shadow-main);
  }
}

.back-home-button:hover {
  background: var(--sevene-main);
  color: var(--sevene-white) !important;
}
.back-home-button {
  display: flex;
  width: 35px;
  height: 35px;
  padding: 0 !important;
  align-items: center;
  justify-content: center;
  margin-right: 4px;
  transition: 0.3s;
  border-radius: 8px;
  color: var(--sevene-white);
}

.back-home-button:hover .back-menu-list-groups {
  display: flex;
  opacity: 1;
  transition: 0.3s;
  top: 55px;
  pointer-events: auto;
  left: 0;
}
.back-home-button .back-menu-list-groups {
  position: absolute;
  top: 65px;
  left: 0;
  background: var(--sevene-card-bg);
  border-radius: 12px;
  border: var(--style-border);
  flex-direction: column;
  font-size: 12px;
  color: var(--sevene-secondtext);
  box-shadow: var(--sevene-shadow-border);
  transition: 0s;
  opacity: 0;
  pointer-events: none;
}

.back-home-button .back-menu-list-group {
  display: flex;
  flex-direction: column;
}
.back-home-button .back-menu-list-group .back-menu-list-title {
  margin: 8px 0 0 16px;
  transition: 0.3s;
}
.back-home-button .back-menu-list {
  display: flex;
  flex-direction: column;
}
.back-home-button .back-menu-list::before {
  position: absolute;
  top: -22px;
  left: 0px;
  width: 100%;
  height: 25px;
  content: '';
}

.back-home-button .back-menu-list-group:hover .back-menu-list-title {
  color: var(--sevene-main);
}
.back-home-button .back-menu-list-groups:hover {
  border: var(--style-border-hover);
}
.back-home-button .back-menu-list .back-menu-item {
  display: flex;
  align-items: center;
  margin: 4px 8px;
  padding: 4px 8px !important;
  transition: 0.3s;
  border-radius: 8px;
}
.back-home-button .back-menu-list .back-menu-item .back-menu-item-text {
  font-size: var(--global-font-size);
  margin-left: 0.5rem;
  color: var(--sevene-fontcolor);
  white-space: nowrap;
}
#nav #blog_name {
  flex-wrap: nowrap;
  height: 60px;
  display: flex;
  align-items: center;
  /* z-index: 102; */
  transition: 0.3s;
}
.back-home-button .back-menu-list .back-menu-item .back-menu-item-icon {
  width: 24px;
  height: 24px;
  border-radius: 24px;
  background: var(--sevene-secondbg);
}
#page-header #nav .back-home-button {
  color: var(--sevene-fontcolor);
  cursor: pointer;
  position: relative;
}

.page #nav a:hover {
  color: var(--sevene-white) !important;
  background: var(--sevene-main);
  transition: 0.3s;
  box-shadow: var(--sevene-shadow-main);
}
@media screen and (min-width: 1300px) {
  #nav a:hover {
    transform: scale(1.03);
  }
}
.back-home-button .back-menu-list .back-menu-item:hover .back-menu-item-text {
  color: var(--sevene-white);
}
.back-menu-item-icon.loading img {
  width: 25px;
}
[data-theme="light"]
.back-home-button .back-menu-list-groups{
  /*控制左上角的菜单的颜色背景*/
  --sevene-card-bg: rgb(255,255,255,0.8);
}
[data-theme="dark"]
.back-home-button .back-menu-list-groups{
  /*控制左上角的菜单的颜色背景*/
  --sevene-card-bg: rgb(1,1,1,0.8);
}
[data-theme="light"]
#rightMenu .rightMenu-group .rightMenu-item{
  color: rgb(1, 1, 1);
}
[data-theme="dark"]
#rightMenu .rightMenu-group .rightMenu-item{
  color: white;
}
:root{
  --lyx-theme:#00FA9A; /*我的主题色*/
  /*控制左上角的菜单的颜色字体*/
  --sevene-white:rgb(255, 255, 255);
  /*控制左上角的菜单的选择时颜色背景*/
  --sevene-main:rgb(0, 250, 154);
  --sevene-shadow-main:rgb(31, 95, 158);
  --sevene-maskbgdeep:rgb(255, 9, 9);
  --sevene-border-radius:30px;
}

新建js

// 返回顶部 显示网页阅读进度
window.onscroll = percent;// 执行函数
// 页面百分比
function percent() {
    let a = document.documentElement.scrollTop || window.pageYOffset, // 卷去高度
        b = Math.max(document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight) - document.documentElement.clientHeight, // 整个网页高度 减去 可视高度
        result = Math.round(a / b * 100), // 计算百分比
        btn = document.querySelector("#percent"); // 获取图标
        result<=99||(result=99),btn.innerHTML=result
}
document.getElementById("page-name").innerText=document.title.split(" | 七鳄の学习格")[0];

修改 themes/butterfly/source/js/main.js

  window.scrollCollect = () => {
        return btf.throttle(function (e) {
          const currentTop = window.scrollY || document.documentElement.scrollTop
          const isDown = scrollDirection(currentTop)
          if (currentTop > 56) {
+           $header.classList.add('is-top-bar')
            if (isDown) {
              if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible')
              if (isChatBtnShow && isChatShow === true) {
                chatBtnHide()
                isChatShow = false
              }
            } else {
              if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible')
              if (isChatBtnHide && isChatShow === false) {
                chatBtnShow()
                isChatShow = true
              }
            }
            $header.classList.add('nav-fixed')
            if (window.getComputedStyle($rightside).getPropertyValue('opacity') === '0') {
              $rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)'
            }
          } else {
            if (currentTop === 0) {
-             $header.classList.remove('nav-fixed', 'nav-visible')
+             $header.classList.remove('is-top-bar')
            }
            $rightside.style.cssText = "opacity: ''; transform: ''"
          }

          if (document.body.scrollHeight <= innerHeight) {
            $rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)'
          }
        }, 200)()
      }

修改 themes/butterfly/layout/includes/header/index.pug

其中nav-visible可以控制默认显示的是站点标题还是导航栏菜单。

  if top_img !== false
    - var imgSource = top_img && top_img.indexOf('/') !== -1 ? `background-image: url('${url_for(top_img)}')` : `background: ${top_img}`
    - var bg_img = top_img ? imgSource : ''
    - var site_title = page.title || page.tag || page.category || config.title
-   - var isHomeClass = is_home() ? 'full_page' : 'not-home-page'
+   - var isHomeClass = is_home() ? 'full_page nav-fixed nav-visible' : 'not-home-page'
    - is_post() ? isHomeClass = 'post-bg' : isHomeClass
  else
    - var isHomeClass = 'not-top-img'

nav.pug

替换themes/butterfly/layout/includes/header/nav.pug, 改动太多了,懒的对比了 🤡,直接替换好啦

- const { darkmode } = theme
nav#nav
  span#blog_name
    .back-home-button(tabindex='-1')
      i.back-home-button-icon.fas.fa-grip-vertical
      .back-menu-list-groups
        .back-menu-list-group
          .back-menu-list-title 网页
          .back-menu-list
            a.back-menu-item(href='/', title='前往博客主页', target='_blank', one-link-mark='yes')
              img.back-menu-item-icon(src='https://image.anzhiy.cn/adminuploads/1/2022/09/05/6315ec9737ac4.png')
              span.back-menu-item-text 博客
            a.back-menu-item(href='https://www.cloud.anzhiy.cn/', rel='external nofollow', title='前往云盘主页', target='_blank', one-link-mark='yes')
              img.back-menu-item-icon(src='https://image.anzhiy.cn/adminuploads/1/2022/09/15/63232b7d91d22.jpg')
              span.back-menu-item-text 云盘主页
            a.back-menu-item(href='https://cloud.anzhiy.cn/', rel='external nofollow', title='前往安知鱼云盘', target='_blank', one-link-mark='yes')
              img.back-menu-item-icon(src='https://image.anzhiy.cn/adminuploads/1/2022/04/27/6268e7d9de532.png')
              span.back-menu-item-text 安知鱼云盘
        .back-menu-list-group
          .back-menu-list-title 项目
          .back-menu-list
            a.back-menu-item(href='http://blgou.net/#/main/home', title='查看德信官网', target='_blank', rel='noopener nofollow', one-link-mark='yes')
              img.back-menu-item-icon.entered.exited(src='https://image.anzhiy.cn/adminuploads/1/2022/09/15/6322cd942dbd9.png')
              span.back-menu-item-text 德信官网
    a#site-name(href=url_for('/')) #[=config.title]
  div.mask-name-container
    center(id="name-container")
      a(id="page-name" href="javascript:rmf.scrollToTop()") PAGE_NAME
  #menus
    if (theme.algolia_search.enable || theme.local_search.enable)
      div.nav-button#search-button
        a.site-page.social-icon.search
          i.fas.fa-search.fa-fw
          span=' '+_p('search.title')
    if darkmode.enable && darkmode.button
      div.nav-button#darkmode_navswitch
        a.darkmode_switchbutton(type="button" title=_p('rightside.night_mode_title') onclick="rmf.switchDarkMode()")
          i.fas.fa-adjust
    div.nav-button#nav-totop
      a.totopbtn
        i.fas.fa-arrow-up
        span#percent(onclick="btf.scrollToDest(0,500)") 0
    !=partial('includes/header/menu_item', {}, {cache: true})
    #toggle-menu
      a.site-page
        i.fas.fa-bars.fa-fw

在分类页面和archives页面添加统计图

点击下拉查看具体内容


1.安装npm(npm install hexo-butterfly-charts —save)插件

npm install hexo-butterfly-charts --save

2.修改 Butterfly config 配置

在您的_config.butterfly.yml中添加如下字段

#see https://www.npmjs.com/package/hexo-butterfly-charts
charts:
  enable: true
  postsChart:
    title: 文章發佈統計 
    interval: 1
  tagsChart:
    title: Top 10 tags 
    interval: 1 
  postsCalendar_Title: 文章發佈日曆
  categoriesChart_Title: 分類統計
  categoriesRadar_Title: 分類雷達

3.针对分类页面进行添加

在主题目录中: .\themes\Butterfly\layout\page.pug

如果信息差不多可以直接复制

extends includes/layout.pug

block content
  #page
    if top_img === false
      h1.page-title= page.title
    case page.type
      when 'tags'
        include includes/page/tags.pug
      when 'link'
        include includes/page/flink.pug
      when 'categories'
+        #categories-chart
+        #categories-radar
        include includes/page/categories.pug
      when 'notice'
        include includes/page/notice.pug
      default
        include includes/page/default-page.pug
    if page.comments !== false && theme.comments && theme.comments.use
      - var commentsJsLoad = true
      !=partial('includes/third-party/comments/index', {}, {cache: true})

4.针对archives页面进行添加

在主题目录中 .\themes\Butterfly\layout\archive.pug,

extends includes/layout.pug

block content
  include ./includes/mixins/article-sort.pug
  #archive
+    #posts-chart
+    #posts-calendar
    - const archiveLength = findArchiveLength(fragment_cache)
    .article-sort-title= _p('page.articles') + ' - ' + archiveLength
    +articleSort(page.posts)
    include includes/pagination.pug

这里写了一些比较nice的魔改教程,也参考了好多博主的教程

给博客/网站顶部加上加载进度条

点击下拉查看具体内容

这里就直接上效果比较Nice一种方式咯

这种方式适合加载比较缓慢的,能够看出效果来,会消耗用户的硬件资源,影响体验

引入css文件

在/themes/butterfly/source/css/`新建一个css文件,名字自定义,这里我就以loading-bar.css命名的

.pace {
    -webkit-pointer-events: none;
    pointer-events: none;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
    z-index: 2000;
    position: fixed;
    margin: auto;
    top: 4px;
    left: 0;
    right: 0;
    height: 8px;
    border-radius: 8px;
    width: 4rem;
    background: #eaecf2;
    border: 1px #e3e8f7;
    overflow: hidden
}

.pace-inactive .pace-progress {
    opacity: 0;
    transition: .3s ease-in
}

.pace .pace-progress {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    -ms-box-sizing: border-box;
    -o-box-sizing: border-box;
    box-sizing: border-box;
    -webkit-transform: translate3d(0, 0, 0);
    -moz-transform: translate3d(0, 0, 0);
    -ms-transform: translate3d(0, 0, 0);
    -o-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
    max-width: 200px;
    position: absolute;
    z-index: 2000;
    display: block;
    top: 0;
    right: 100%;
    height: 100%;
    width: 100%;
    background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
    animation: gradient 1.5s ease infinite;
    background-size: 200%
}

.pace.pace-inactive {
    opacity: 0;
    transition: .3s;
    top: -8px
}
@keyframes gradient {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}

关于进度条的颜色修改主要修改如下即可

background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);

渐变网站推荐:

Grabient

uiGradients - Beautiful colored gradients

关于js文件可以直接引用,这里防止挂了,做个备份吧

这里如果想直接引用,可以跳过此步骤
/*!
 * pace.js v1.2.4
 * https://github.com/CodeByZach/pace/
 * Licensed MIT © HubSpot, Inc.
 */
!
function() {
    function o(t, e) {
        return function() {
            return t.apply(e, arguments)
        }
    }
    var u, c, i, s, n, y, t, l, v, r, a, p, e, h, w, b, f, g, d, m, k, S, q, L, x, P, T, R, j, O, E, M, A, C, N, _, F, U, W, X, D, H, I, z, G, B, J = [].slice,
    K = {}.hasOwnProperty,
    Q = function(t, e) {
        for (var n in e) K.call(e, n) && (t[n] = e[n]);
        function r() {
            this.constructor = t
        }
        return r.prototype = e.prototype,
        t.prototype = new r,
        t.__super__ = e.prototype,
        t
    },
    V = [].indexOf ||
    function(t) {
        for (var e = 0,
        n = this.length; e < n; e++) if (e in this && this[e] === t) return e;
        return - 1
    };
    function Y() {}
    for (g = {
        className: "",
        catchupTime: 100,
        initialRate: .03,
        minTime: 250,
        ghostTime: 100,
        maxProgressPerFrame: 20,
        easeFactor: 1.25,
        startOnPageLoad: !0,
        restartOnPushState: !0,
        restartOnRequestAfter: 500,
        target: "body",
        elements: {
            checkInterval: 100,
            selectors: ["body"]
        },
        eventLag: {
            minSamples: 10,
            sampleCount: 3,
            lagThreshold: 3
        },
        ajax: {
            trackMethods: ["GET"],
            trackWebSockets: !0,
            ignoreURLs: []
        }
    },
    P = function() {
        var t;
        return null != (t = "undefined" != typeof performance && null !== performance && "function" == typeof performance.now ? performance.now() : void 0) ? t: +new Date
    },
    R = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame, f = window.cancelAnimationFrame || window.mozCancelAnimationFrame, p = function(t, e, n) {
        if ("function" == typeof t.addEventListener) return t.addEventListener(e, n, !1);
        var r;
        "function" != typeof t["on" + e] || "object" != typeof t["on" + e].eventListeners ? (r = new s, "function" == typeof t["on" + e] && r.on(e, t["on" + e]), t["on" + e] = function(t) {
            return r.trigger(e, t)
        },
        t["on" + e].eventListeners = r) : r = t["on" + e].eventListeners,
        r.on(e, n)
    },
    null == R && (R = function(t) {
        return setTimeout(t, 50)
    },
    f = function(t) {
        return clearTimeout(t)
    }), O = function(e) {
        var n = P(),
        r = function() {
            var t = P() - n;
            return 33 <= t ? (n = P(), e(t,
            function() {
                return R(r)
            })) : setTimeout(r, 33 - t)
        };
        return r()
    },
    j = function() {
        var t = arguments[0],
        e = arguments[1],
        n = 3 <= arguments.length ? J.call(arguments, 2) : [];
        return "function" == typeof t[e] ? t[e].apply(t, n) : t[e]
    },
    d = function() {
        for (var t, e, n, r = arguments[0], s = 2 <= arguments.length ? J.call(arguments, 1) : [], o = 0, i = s.length; o < i; o++) if (e = s[o]) for (t in e) K.call(e, t) && (n = e[t], null != r[t] && "object" == typeof r[t] && null != n && "object" == typeof n ? d(r[t], n) : r[t] = n);
        return r
    },
    h = function(t) {
        for (var e, n, r = e = 0,
        s = 0,
        o = t.length; s < o; s++) n = t[s],
        r += Math.abs(n),
        e++;
        return r / e
    },
    k = function(t, e) {
        var n, r;
        if (null == t && (t = "options"), null == e && (e = !0), r = document.querySelector("[data-pace-" + t + "]")) {
            if (n = r.getAttribute("data-pace-" + t), !e) return n;
            try {
                return JSON.parse(n)
            } catch(t) {
                return "undefined" != typeof console && null !== console ? console.error("Error parsing inline pace options", t) : void 0
            }
        }
    },
    Y.prototype.on = function(t, e, n, r) {
        var s;
        return null == r && (r = !1),
        null == this.bindings && (this.bindings = {}),
        null == (s = this.bindings)[t] && (s[t] = []),
        this.bindings[t].push({
            handler: e,
            ctx: n,
            once: r
        })
    },
    Y.prototype.once = function(t, e, n) {
        return this.on(t, e, n, !0)
    },
    Y.prototype.off = function(t, e) {
        var n, r, s;
        if (null != (null != (r = this.bindings) ? r[t] : void 0)) {
            if (null == e) return delete this.bindings[t];
            for (n = 0, s = []; n < this.bindings[t].length;) this.bindings[t][n].handler === e ? s.push(this.bindings[t].splice(n, 1)) : s.push(n++);
            return s
        }
    },
    Y.prototype.trigger = function() {
        var t, e, n, r, s, o, i = arguments[0],
        a = 2 <= arguments.length ? J.call(arguments, 1) : [];
        if (null != (r = this.bindings) && r[i]) {
            for (n = 0, o = []; n < this.bindings[i].length;) e = (s = this.bindings[i][n]).handler,
            t = s.ctx,
            s = s.once,
            e.apply(null != t ? t: this, a),
            s ? o.push(this.bindings[i].splice(n, 1)) : o.push(n++);
            return o
        }
    },
    B = Y, y = window.Pace || {},
    window.Pace = y, d(y, B.prototype), T = y.options = d({},
    g, window.paceOptions, k()), X = 0, H = (z = ["ajax", "document", "eventLag", "elements"]).length; X < H; X++) ! 0 === T[C = z[X]] && (T[C] = g[C]);
    function Z() {
        return Z.__super__.constructor.apply(this, arguments)
    }
    function $() {
        this.progress = 0
    }
    function tt() {
        this.bindings = {}
    }
    function et() {
        var e, o = this;
        et.__super__.constructor.apply(this, arguments),
        e = function(r) {
            var s = r.open;
            return r.open = function(t, e, n) {
                return A(t) && o.trigger("request", {
                    type: t,
                    url: e,
                    request: r
                }),
                s.apply(r, arguments)
            }
        },
        window.XMLHttpRequest = function(t) {
            t = new W(t);
            return e(t),
            t
        };
        try {
            m(window.XMLHttpRequest, W)
        } catch(t) {}
        if (null != U) {
            window.XDomainRequest = function() {
                var t = new U;
                return e(t),
                t
            };
            try {
                m(window.XDomainRequest, U)
            } catch(t) {}
        }
        if (null != F && T.ajax.trackWebSockets) {
            window.WebSocket = function(t, e) {
                var n = null != e ? new F(t, e) : new F(t);
                return A("socket") && o.trigger("request", {
                    type: "socket",
                    url: t,
                    protocols: e,
                    request: n
                }),
                n
            };
            try {
                m(window.WebSocket, F)
            } catch(t) {}
        }
    }
    function nt() {
        this.complete = o(this.complete, this);
        var t = this;
        this.elements = [],
        S().on("request",
        function() {
            return t.watch.apply(t, arguments)
        })
    }
    function rt(t) {
        var e, n, r, s;
        for (null == t && (t = {}), this.complete = o(this.complete, this), this.elements = [], null == t.selectors && (t.selectors = []), n = 0, r = (s = t.selectors).length; n < r; n++) e = s[n],
        this.elements.push(new i(e, this.complete))
    }
    function st(t, e) {
        this.selector = t,
        this.completeCallback = e,
        this.progress = 0,
        this.check()
    }
    function ot() {
        var t, e, n = this;
        this.progress = null != (e = this.states[document.readyState]) ? e: 100,
        t = document.onreadystatechange,
        document.onreadystatechange = function() {
            return null != n.states[document.readyState] && (n.progress = n.states[document.readyState]),
            "function" == typeof t ? t.apply(null, arguments) : void 0
        }
    }
    function it(t) {
        this.source = t,
        this.last = this.sinceLastUpdate = 0,
        this.rate = T.initialRate,
        this.catchup = 0,
        this.progress = this.lastProgress = 0,
        null != this.source && (this.progress = j(this.source, "progress"))
    }
    B = Error,
    Q(Z, B),
    n = Z,
    $.prototype.getElement = function() {
        var t;
        if (null == this.el) {
            if (! (t = document.querySelector(T.target))) throw new n;
            this.el = document.createElement("div"),
            this.el.className = "pace pace-active",
            document.body.className = document.body.className.replace(/(pace-done )|/, "pace-running ");
            var e = "" !== T.className ? " " + T.className: "";
            this.el.innerHTML = '<div class="pace-progress' + e + '">\n  <div class="pace-progress-inner"></div>\n</div>\n<div class="pace-activity"></div>',
            null != t.firstChild ? t.insertBefore(this.el, t.firstChild) : t.appendChild(this.el)
        }
        return this.el
    },
    $.prototype.finish = function() {
        var t = this.getElement();
        return t.className = t.className.replace("pace-active", "pace-inactive"),
        document.body.className = document.body.className.replace("pace-running ", "pace-done ")
    },
    $.prototype.update = function(t) {
        return this.progress = t,
        y.trigger("progress", t),
        this.render()
    },
    $.prototype.destroy = function() {
        try {
            this.getElement().parentNode.removeChild(this.getElement())
        } catch(t) {
            n = t
        }
        return this.el = void 0
    },
    $.prototype.render = function() {
        var t, e, n, r, s, o, i;
        if (null == document.querySelector(T.target)) return ! 1;
        for (t = this.getElement(), r = "translate3d(" + this.progress + "%, 0, 0)", s = 0, o = (i = ["webkitTransform", "msTransform", "transform"]).length; s < o; s++) e = i[s],
        t.children[0].style[e] = r;
        return (!this.lastRenderedProgress || this.lastRenderedProgress | 0 !== this.progress | 0) && (t.children[0].setAttribute("data-progress-text", (0 | this.progress) + "%"), 100 <= this.progress ? n = "99": (n = this.progress < 10 ? "0": "", n += 0 | this.progress), t.children[0].setAttribute("data-progress", "" + n)),
        y.trigger("change", this.progress),
        this.lastRenderedProgress = this.progress
    },
    $.prototype.done = function() {
        return 100 <= this.progress
    },
    c = $,
    tt.prototype.trigger = function(t, e) {
        var n, r, s, o, i;
        if (null != this.bindings[t]) {
            for (i = [], r = 0, s = (o = this.bindings[t]).length; r < s; r++) n = o[r],
            i.push(n.call(this, e));
            return i
        }
    },
    tt.prototype.on = function(t, e) {
        var n;
        return null == (n = this.bindings)[t] && (n[t] = []),
        this.bindings[t].push(e)
    },
    s = tt,
    W = window.XMLHttpRequest,
    U = window.XDomainRequest,
    F = window.WebSocket,
    m = function(t, e) {
        var n, r = [];
        for (n in e.prototype) try {
            null == t[n] && "function" != typeof e[n] ? "function" == typeof Object.defineProperty ? r.push(Object.defineProperty(t, n, {
                get: function(t) {
                    return function() {
                        return e.prototype[t]
                    }
                } (n),
                configurable: !0,
                enumerable: !0
            })) : r.push(t[n] = e.prototype[n]) : r.push(void 0)
        } catch(t) {
            0
        }
        return r
    },
    L = [],
    y.ignore = function() {
        var t = arguments[0],
        e = 2 <= arguments.length ? J.call(arguments, 1) : [];
        return L.unshift("ignore"),
        e = t.apply(null, e),
        L.shift(),
        e
    },
    y.track = function() {
        var t = arguments[0],
        e = 2 <= arguments.length ? J.call(arguments, 1) : [];
        return L.unshift("track"),
        e = t.apply(null, e),
        L.shift(),
        e
    },
    A = function(t) {
        if (null == t && (t = "GET"), "track" === L[0]) return "force";
        if (!L.length && T.ajax) {
            if ("socket" === t && T.ajax.trackWebSockets) return ! 0;
            if (t = t.toUpperCase(), 0 <= V.call(T.ajax.trackMethods, t)) return ! 0
        }
        return ! 1
    },
    Q(et, s),
    t = et,
    D = null,
    M = function(t) {
        for (var e, n = T.ajax.ignoreURLs,
        r = 0,
        s = n.length; r < s; r++) if ("string" == typeof(e = n[r])) {
            if ( - 1 !== t.indexOf(e)) return ! 0
        } else if (e.test(t)) return ! 0;
        return ! 1
    },
    (S = function() {
        return D = null == D ? new t: D
    })().on("request",
    function(t) {
        var o, i = t.type,
        a = t.request,
        e = t.url;
        if (!M(e)) return y.running || !1 === T.restartOnRequestAfter && "force" !== A(i) ? void 0 : (o = arguments, "boolean" == typeof(e = T.restartOnRequestAfter || 0) && (e = 0), setTimeout(function() {
            var t, e, n, r, s = "socket" === i ? a.readyState < 1 : 0 < (s = a.readyState) && s < 4;
            if (s) {
                for (y.restart(), r = [], t = 0, e = (n = y.sources).length; t < e; t++) {
                    if ((C = n[t]) instanceof u) {
                        C.watch.apply(C, o);
                        break
                    }
                    r.push(void 0)
                }
                return r
            }
        },
        e))
    }),
    nt.prototype.watch = function(t) {
        var e = t.type,
        n = t.request,
        t = t.url;
        if (!M(t)) return n = new("socket" === e ? r: a)(n, this.complete),
        this.elements.push(n)
    },
    nt.prototype.complete = function(e) {
        return this.elements = this.elements.filter(function(t) {
            return t !== e
        })
    },
    u = nt,
    a = function(e, n) {
        var t, r, s, o, i = this;
        if (this.progress = 0, null != window.ProgressEvent) for (p(e, "progress",
        function(t) {
            return t.lengthComputable ? i.progress = 100 * t.loaded / t.total: i.progress = i.progress + (100 - i.progress) / 2
        }), t = 0, r = (o = ["load", "abort", "timeout", "error"]).length; t < r; t++) p(e, o[t],
        function() {
            return n(i),
            i.progress = 100
        });
        else s = e.onreadystatechange,
        e.onreadystatechange = function() {
            var t;
            return 0 === (t = e.readyState) || 4 === t ? (n(i), i.progress = 100) : 3 === e.readyState && (i.progress = 50),
            "function" == typeof s ? s.apply(null, arguments) : void 0
        }
    },
    r = function(t, e) {
        for (var n, r = this,
        s = this.progress = 0,
        o = (n = ["error", "open"]).length; s < o; s++) p(t, n[s],
        function() {
            return e(r),
            r.progress = 100
        })
    },
    rt.prototype.complete = function(e) {
        return this.elements = this.elements.filter(function(t) {
            return t !== e
        })
    },
    k = rt,
    st.prototype.check = function() {
        var t = this;
        return document.querySelector(this.selector) ? this.done() : setTimeout(function() {
            return t.check()
        },
        T.elements.checkInterval)
    },
    st.prototype.done = function() {
        return this.completeCallback(this),
        this.completeCallback = null,
        this.progress = 100
    },
    i = st,
    ot.prototype.states = {
        loading: 0,
        interactive: 50,
        complete: 100
    },
    B = ot,
    Q = function() {
        var e, n, r, s, o, i = this;
        this.progress = 0,
        o = [],
        s = 0,
        r = P(),
        n = setInterval(function() {
            var t = P() - r - 50;
            return r = P(),
            o.push(t),
            o.length > T.eventLag.sampleCount && o.shift(),
            e = h(o),
            ++s >= T.eventLag.minSamples && e < T.eventLag.lagThreshold ? (i.progress = 100, clearInterval(n)) : i.progress = 3 / (e + 3) * 100
        },
        50)
    },
    it.prototype.tick = function(t, e) {
        return 100 <= (e = null == e ? j(this.source, "progress") : e) && (this.done = !0),
        e === this.last ? this.sinceLastUpdate += t: (this.sinceLastUpdate && (this.rate = (e - this.last) / this.sinceLastUpdate), this.catchup = (e - this.progress) / T.catchupTime, this.sinceLastUpdate = 0, this.last = e),
        e > this.progress && (this.progress += this.catchup * t),
        e = 1 - Math.pow(this.progress / 100, T.easeFactor),
        this.progress += e * this.rate * t,
        this.progress = Math.min(this.lastProgress + T.maxProgressPerFrame, this.progress),
        this.progress = Math.max(0, this.progress),
        this.progress = Math.min(100, this.progress),
        this.lastProgress = this.progress,
        this.progress
    },
    v = it,
    b = e = _ = w = E = N = null,
    y.running = !1,
    q = function() {
        if (T.restartOnPushState) return y.restart()
    },
    null != window.history.pushState && (I = window.history.pushState, window.history.pushState = function() {
        return q(),
        I.apply(window.history, arguments)
    }),
    null != window.history.replaceState && (G = window.history.replaceState, window.history.replaceState = function() {
        return q(),
        G.apply(window.history, arguments)
    }),
    l = {
        ajax: u,
        elements: k,
        document: B,
        eventLag: Q
    },
    (x = function() {
        var t, e, n, r, s, o, i, a;
        for (y.sources = N = [], e = 0, r = (o = ["ajax", "elements", "document", "eventLag"]).length; e < r; e++) ! 1 !== T[t = o[e]] && N.push(new l[t](T[t]));
        for (n = 0, s = (a = null != (i = T.extraSources) ? i: []).length; n < s; n++) C = a[n],
        N.push(new C(T));
        return y.bar = w = new c,
        E = [],
        _ = new v
    })(),
    y.stop = function() {
        return y.trigger("stop"),
        y.running = !1,
        w.destroy(),
        b = !0,
        null != e && ("function" == typeof f && f(e), e = null),
        x()
    },
    y.restart = function() {
        return y.trigger("restart"),
        y.stop(),
        y.start()
    },
    y.go = function() {
        var m;
        return y.running = !0,
        w.render(),
        m = P(),
        b = !1,
        e = O(function(t, e) {
            w.progress;
            for (var n, r, s, o, i, a, u, c, l, p, h = a = 0,
            f = !0,
            g = u = 0,
            d = N.length; u < d; g = ++u) for (C = N[g], i = null != E[g] ? E[g] : E[g] = [], s = c = 0, l = (r = null != (p = C.elements) ? p: [C]).length; c < l; s = ++c) o = r[s],
            f &= (o = null != i[s] ? i[s] : i[s] = new v(o)).done,
            o.done || (h++, a += o.tick(t));
            return n = a / h,
            w.update(_.tick(t, n)),
            w.done() || f || b ? (w.update(100), y.trigger("done"), setTimeout(function() {
                return w.finish(),
                y.running = !1,
                y.trigger("hide")
            },
            Math.max(T.ghostTime, Math.max(T.minTime - (P() - m), 0)))) : e()
        })
    },
    y.start = function(t) {
        d(T, t),
        y.running = !0;
        try {
            w.render()
        } catch(t) {
            n = t
        }
        return document.querySelector(".pace") ? (y.trigger("start"), y.go()) : setTimeout(y.start, 50)
    },
    "function" == typeof define && define.amd ? define(function() {
        return y
    }) : "object" == typeof exports ? module.exports = y: T.startOnPageLoad && y.start()
}.call(this);

_config.butterfly.yml主题文件中加入

inject:
  head:
      - <script src="https://npm.elemecdn.com/pace-js@latest/pace.min.js"></script>
      - <link rel="stylesheet" href="/css/load.css">

网站标题部分的增强版

点击下拉查看具体内容

看到洪哥他们的有一个非常高大上的动画,一直没有实现,看到博主LYXの小破站 (yisous.xyz)的教程实现了,就整了一下

引入css,然后根据自己需要进行修改颜色,尺寸即可

#site-name::before{
    opacity: 0;
    background-color: var(--lyx-theme)!important;
    border-radius: 8px;
    -webkit-border-radius: 8px;
    -moz-border-radius: 8px;
    -ms-border-radius: 8px;
    -o-border-radius: 8px;
    transition: .3s;
    -webkit-transition: .3s;
    -moz-transition: .3s;
    -ms-transition: .3s;
    -o-transition: .3s;
    position:absolute;
    top:0!important;
    right:0!important;
    width:100%;
    height:100%;
    content: "\f015";
    box-shadow: 0 0 5px var(--lyx-theme);
    font-family: "Font Awesome 6 Free";
    text-align: center;
    color:white;
    line-height:34px;/*如果有溢出或者垂直不居中的现象微调一下这个参数*/
    font-size: 20px;/*根据个人喜好*/
}
#site-name:hover::before{
    opacity: 1;
    scale:1.03;
}
#site-name{
    position: relative;
    font-size: 22px; /*一定要把字体调大点,否则效果惨不忍睹!*/
}
:root{
    --lyx-theme:#8600FF /*我的主题色*/
}



菜单栏居中

点击下拉查看具体内容

这个直接引入css文件即可

.layout{
    max-width:1400px;
}
.aside-content{
    max-width:312px;
}
/* @media screen and (max-width: 900px){
    .card-widget:not(#card-toc){
        display:none!important;
    }
} */
@media screen and (max-width: 900px){
    .aside-content{
        max-width:none!important;
    }
}
#archive,#page,#category,#tag{
    width:100%;
}
.page:not(.page.home) .aside-content{
    display: none;
}
@media screen and (min-width: 1300px) {
    #recent-posts{
        margin-top:-1rem;  /*头部为空时抵消间隔,若有磁贴或日历请注释掉该行*/
        align-content:flex-start;
        display: flex;
        flex-wrap: wrap; /*规定灵活的项目在必要的时候拆行或拆列。*/
        justify-content: space-between; /*。*/
    }
    #recent-posts > .recent-post-item {
      /*max-height:324px;*/  /*文章容器最大高度*/
      margin-top: 1rem; /*最小间距*/
      display: inline-block;
      height:auto; /*高度自动*/
      width:49%;/*文章容器容器宽度*/
    }
    #recent-posts > .recent-post-item .post_cover {
      width: 100%; /*图片封面宽度*/
        height: 200px;/*图片封面高度*/
    }
    #recent-posts > .recent-post-item .post_cover img.post_bg {
      width: 100%;/*图片宽度*/
      height: 100%;/*图片高度*/
    }
    #recent-posts > .recent-post-item {
    
      -webkit-flex-direction: column; /*容器内部纵向排列*/
      -ms-flex-direction: column; /*容器内部纵向排列*/
      flex-direction: column; /*容器内部纵向排列*/
    
    }
    #recent-posts > .recent-post-item .left_radius {
        border-radius: 8px 8px 0 0;/*圆角修改*/
    }
    #recent-posts > .recent-post-item .right_radius {
        border-radius: 8px 8px 0 0;/*圆角修改*/
    }
    .recent-post-item{
        height:auto !important;/*容器高度自动*/
    }
    
    .recent-post-info {
      
      padding: 0 40px;/*容器内部文字左右间距*/
      margin-top: 1em;/*容器内部文字上间距*/
      width: 100%!important;/*容器宽度*/
    }
    #recent-posts > .recent-post-item > .recent-post-info > .article-title {
        -webkit-line-clamp: 1;/*控制标题的行数*/
        margin-top: 0.3rem; /*控制标题的上间距*/
        margin-bottom: 0.3rem;/*控制标题的下间距*/
        color: var(--text-highlight-color);
        font-size: 1.2em; /*控制标题的字体大小*/
        line-height: 1.4;/*控制标题的行高*/
     
    }
    #recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap {
        margin-bottom: 1rem;/*控制标题meta信息的底部间距*/
    }
}

#nav-right{
    flex:1 1 auto;
    justify-content: flex-end;
    margin-left: auto;
    display: flex;
    flex-wrap:nowrap;
}

_config.butterfly.yml主题文件中加入

记得在_config.butterfly.yml引入哦

Categories Magnet【磁贴】

点击下拉查看具体内容

由于某种原因,这个并未采用,这个请移步 Akilarの糖果屋相关教程

Categories Magnet | Akilarの糖果屋

最新文章标志

点击下拉查看具体内容

此部分参考添加最新文章标志 | Jayhrn - 分享科技与热爱生活

非修改源码方案

  • 1.新建 [BlogSource]/themes/butterfly/source/js/custom/newest_post.js 文件:
// 旧版,本站采用
// 确保其他页面第一个不添加
if (location.pathname == '/') newPost();

// 最新文章
function newPost() {
    // 获取此类名而不是获取recent-post-item是因为一些插件也会使用recent-post-item类。
    // 所以获取recent-post-info可以确保每一篇都是文章。
    let ls = document.querySelectorAll('.recent-post-info')
    for (let i = 0; i < ls.length; i++) {
        // 如果是置顶则跳过,所以如果你最新文章置顶的话就无法添加标志,只会给到置顶下面最新的文章。
        // 不过一般来说置顶文章都会是早期文章,实在不行置顶之后再写一篇😂
        if (ls[i].querySelector('.sticky')) continue;
        let className = '';
        // 封面在右则在左边添加,否则在右边
        // 其实你也可以直接放在左边,我之所以这样弄是为了避免和分类图标冲突
        if (ls[i].previousSibling.classList.contains('right')) className = 'newPost-left';
        else className = 'newPost-right';
        ls[i].innerHTML += '<span class="' + className + '">最 新</span>';
        return
    }
}
// 新代码,利用创建时间来判断
// 确保其他页面第一个不添加
if (location.pathname == '/') newPost();

// 最新文章
function newPost() {
    let ls = document.querySelectorAll('.recent-post-info')
    // 先让时间和索引值都等于第一个的
    let time = new Date(ls[0].querySelector('.post-meta-date-created').getAttribute('datetime')).getTime();
    let index = 0
    // 遍历数组,如果有时间比time大的则替换
    ls.forEach((i, num) => {
        let t = new Date(i.querySelector('.post-meta-date-created').getAttribute('datetime')).getTime()
        if (t > time) {
            time = t;
            index = num
        }
    })
    // 单数在右,双数在左
    let className = index % 2 == 0 ? 'newPost-right' : 'newPost-left'
    ls[index].innerHTML += '<span class="' + className + '">最 新</span>';
    // 如果你不想让其一左一右,可以注释上面的启用下面的
    // ls[index].innerHTML += '<span class="newPost-left">最 新</span>';
}
  • 2.新建 [BlogSource]/themes/butterfly/source/css/custom/newest_post.css 文件:
.newPost-left,
.newPost-right::before {
    content: "new";
    width: 3rem;
    height: 2rem;
    border-radius: 8px;
    text-align: center;
    line-height: 2rem;
    color: #fff;
    position: absolute;
    top: 8px;
    left: 8px;
    background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
    background-size: 400% 400%;
    animation: gradient 15s ease infinite;
}
  • 3.引入css和js
inject:
  head:
    - <link rel="stylesheet" href="/css/custom_mg/newest_post.css">
  bottom:
    # 引入自定义js,判断最新文章[加上 data-pjax 是为了由于开启 pjax 引起切换页面后失效]
    - <script defer="" src="/js/custom/newest_post.js" data-pjax=""></script>

Hexo 白昼切换

点击下拉查看具体内容
白天黑夜转换动画

看惯了Hexo Butterfly默认的黑夜/白天效果,正好看到 Jayhrnの糖衣阁大佬的黑白切换效果超级nice,所以也是第一时间换上了,下面告诉大家一下相关配置,相关文件大家也是可以在Gitee上找到的,链接我放底下了哦

(1)在themes\butterfly\layout\includes\custom\下新建一个sun_moon.pug【如果includes\下没有custom,记得自己创建哦】

主要用途:通过 js 操作它的旋转显隐,淡入淡出实现动画效果

svg(aria-hidden='true', style='position:absolute; overflow:hidden; width:0; height:0')
  symbol#icon-sun(viewBox='0 0 1024 1024')
    path(d='M960 512l-128 128v192h-192l-128 128-128-128H192v-192l-128-128 128-128V192h192l128-128 128 128h192v192z', fill='#FFD878', p-id='8420')
    path(d='M736 512a224 224 0 1 0-448 0 224 224 0 1 0 448 0z', fill='#FFE4A9', p-id='8421')
    path(d='M512 109.248L626.752 224H800v173.248L914.752 512 800 626.752V800h-173.248L512 914.752 397.248 800H224v-173.248L109.248 512 224 397.248V224h173.248L512 109.248M512 64l-128 128H192v192l-128 128 128 128v192h192l128 128 128-128h192v-192l128-128-128-128V192h-192l-128-128z', fill='#4D5152', p-id='8422')
    path(d='M512 320c105.888 0 192 86.112 192 192s-86.112 192-192 192-192-86.112-192-192 86.112-192 192-192m0-32a224 224 0 1 0 0 448 224 224 0 0 0 0-448z', fill='#4D5152', p-id='8423')
  symbol#icon-moon(viewBox='0 0 1024 1024')
    path(d='M611.370667 167.082667a445.013333 445.013333 0 0 1-38.4 161.834666 477.824 477.824 0 0 1-244.736 244.394667 445.141333 445.141333 0 0 1-161.109334 38.058667 85.077333 85.077333 0 0 0-65.066666 135.722666A462.08 462.08 0 1 0 747.093333 102.058667a85.077333 85.077333 0 0 0-135.722666 65.024z', fill='#FFB531', p-id='11345')
    path(d='M329.728 274.133333l35.157333-35.157333a21.333333 21.333333 0 1 0-30.165333-30.165333l-35.157333 35.157333-35.114667-35.157333a21.333333 21.333333 0 0 0-30.165333 30.165333l35.114666 35.157333-35.114666 35.157334a21.333333 21.333333 0 1 0 30.165333 30.165333l35.114667-35.157333 35.157333 35.157333a21.333333 21.333333 01030.165333-30.165333z', fill='#030835', p-id='11346')

(2)themes\butterfly\source\css_layout\文件夹中新建一个sun_moon.styl

.Cuteen_DarkSky,
.Cuteen_DarkSky:before
  content ''
  position fixed
  left 0
  right 0
  top 0
  bottom 0
  z-index 88888888

.Cuteen_DarkSky
  background linear-gradient(#feb8b0, #fef9db)
  &:before
    transition 2s ease all
    opacity 0
    background linear-gradient(#4c3f6d, #6c62bb, #93b1ed)

.DarkMode
  .Cuteen_DarkSky
    &:before
      opacity 1

.Cuteen_DarkPlanet
  z-index 99999999
  position fixed
  left -50%
  top -50%
  width 200%
  height 200%
  -webkit-animation CuteenPlanetMove 2s cubic-bezier(0.7, 0, 0, 1)
  animation CuteenPlanetMove 2s cubic-bezier(0.7, 0, 0, 1)
  transform-origin center bottom


@-webkit-keyframes CuteenPlanetMove {
  0% {
    transform: rotate(0);
  }
  to {
    transform: rotate(360deg);
  }
}
@keyframes CuteenPlanetMove {
  0% {
    transform: rotate(0);
  }
  to {
    transform: rotate(360deg);
  }
}
.Cuteen_DarkPlanet
  &:after
    position absolute
    left 35%
    top 40%
    width 9.375rem
    height 9.375rem
    border-radius 50%
    content ''
    background linear-gradient(#fefefe, #fffbe8)

.search
  span
    display none

.menus_item
  a
    text-decoration none!important
//按钮相关,对侧栏按钮做过魔改的可以调整这里的数值
.icon-V
  padding 5px

(3)在\themes\butterfly\source\js\custom\下新建sun_moon.js【如果js\下没有custom,记得自己创建哦】

function switchNightMode() {
    document.querySelector('body').insertAdjacentHTML('beforeend', '<div class="Cuteen_DarkSky"><div class="Cuteen_DarkPlanet"></div></div>'),
        setTimeout(function() {
            document.querySelector('body').classList.contains('DarkMode') ? (document.querySelector('body').classList.remove('DarkMode'), localStorage.setItem('isDark', '0'), document.getElementById('modeicon').setAttribute('xlink:href', '#icon-moon')) : (document.querySelector('body').classList.add('DarkMode'), localStorage.setItem('isDark', '1'), document.getElementById('modeicon').setAttribute('xlink:href', '#icon-sun')),
                setTimeout(function() {
                    document.getElementsByClassName('Cuteen_DarkSky')[0].style.transition = 'opacity 3s';
                    document.getElementsByClassName('Cuteen_DarkSky')[0].style.opacity = '0';
                    setTimeout(function() {
                        document.getElementsByClassName('Cuteen_DarkSky')[0].remove();
                    }, 1e3);
                }, 2e3)
        })
    const nowMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
    if (nowMode === 'light') {
        activateDarkMode()
        saveToLocal.set('theme', 'dark', 2)
        GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night)
        document.getElementById('modeicon').setAttribute('xlink:href', '#icon-sun')
    } else {
        activateLightMode()
        saveToLocal.set('theme', 'light', 2)
        document.querySelector('body').classList.add('DarkMode'), document.getElementById('modeicon').setAttribute('xlink:href', '#icon-moon')
    }
    // handle some cases
    typeof utterancesTheme === 'function' && utterancesTheme()
    typeof FB === 'object' && window.loadFBComment()
    window.DISQUS && document.getElementById('disqus_thread').children.length && setTimeout(() => window.disqusReset(), 200)
}

(4)修改 [Blogroot]\themes\butterfly\layout\includes\head.pug

//- global config
!=partial('includes/head/config', {}, {cache: true})

include ./head/config_site.pug
include ./head/noscript.pug
include ./custom/sun_moon.pug【添加上这句】

!=fragment_cache('injectHeadJs', function(){return inject_head_js()})

!=fragment_cache('injectHead', function(){return injectHtml(theme.inject.head)})

(5)修改 [Blogroot]\themes\butterfly\layout\includes\rightside.pug, 把原本的昼夜切换按钮替换掉

when 'translate'
  if translate.enable
    button#translateLink(type="button" title=_p('rightside.translate_title'))= translate.default
when 'darkmode'
  if darkmode.enable && darkmode.button
    button#darkmode(type="button" title=_p('rightside.night_mode_title')) 【这句删除掉】
      i.fas.fa-adjust 【这句删除掉】
    a.icon-V.hidden(onclick='switchNightMode()',  title=_p('rightside.night_mode_title'))【添加上这句】
      svg(width='25', height='25', viewBox='0 0 1024 1024')【添加上这句】
        use#modeicon(xlink:href='#icon-moon')【添加上这句】

(6)修改 [Blogroot]_config.butterfly.yml, 引入一下 js

inject:
  head:
  bottom:
    - <script src="/js/custom/sun_moon.js" async></script>

下面就是老规矩,把用到的文件放到gitee上了哦,记得点img