前言
鸽了几万年的楠终于开始重构自己的屎山博客了,此贴来记录楠是用了什么东西堆成新的 屎山
部署
- 由
GitHub
储存 - 由
Vercel
托管部署 - 更换
vercel.cdn.yt-blog.top
节点加快国内访问速度 - 版本:
hexo: 6.3.0
butterfly: 4.7.0
整理配置文件
- 将主题配置文件复制出来,方便更改
- 将配置文件注释汉化
图床
本来想搞个 cdn 来加速 GitHub
仓库当图床的,结果 https 要证书,就开始了艰辛的坐牢一日。
证书
- 安装
wsl
,在微软商店下载了个Ubuntu 2204
版本。 - 启动的时候出错了,一直报错
0x8004032d
。上网查找之后使用下面的命令安装并初始化(前提是已经开启Hype-v
适用于Linux的Windows子系统
虚拟机平台
)。cmd wsl --install
- 就是正常配置用户名密码啥的,成功进入 wsl。并使用 sudo 命令设置 root 密码。
sh sudo passwd root
- 安装
acme.sh
的时候又出问题了,没有代理连接不上Github
。解决方法来自博客园的一篇文章 传送门。 省流: 就是在Windows中的C:\Users\<your_username>
目录下创建一个.wslconfig 文件,并写入以下代码。config [experimental] autoMemoryReclaim=gradual networkingMode=mirrored dnsTunneling=true firewall=true autoProxy=true
再使用终端重启 wsl。shell wsl --shutdown
注意,每次开关梯子都要重新启动 wsl - 成功安装
acme.sh
后便开始手动生成证书- 第一次要先使用
sh ~/.acme.sh/acme.sh --register-account -m <你的邮箱>
来注册账户 - 注册成功后使用
sh ~/.acme.sh/acme.sh --issue -d <域名> --dns dns-01
生成证书 - 按照要求在域名服务商添加
TXT
解析,等候片刻再次运行命令就生成证书了
- 第一次要先使用
- 生成的证书在/root 目录,这里又出现个问题,无法访问,显示没有权限。
解决方法:
sh cd / sudo nano /etc/wsl.conf
在wsl.cong
里面添加conf [user] default=root
让默认账户是 root 就解决了
配置 cdn
自己搞半天没成功,最后问了一下 煮雪话河山 大佬,并跟着大佬一步一步走才成功
- 绑定的加速网站:要加速的网站
- 源站:加速网站绑定的源站,如
vercel
绑定域名的时候的cname.vercel-dns.com
或者是cf page
绑定域名时候的xxx.pages.dev
- https 证书:证书
外挂标签
使用的是店长的 Tag Plugins Plus
用的是源码部署,站外卡片的样式因为看到 June 的样式很喜欢,所以就也去洪哥的帖子 cv 了一个下来,略微改改。
文章版权卡片美化
使用的是 Fomalhaut 和 店长 的样式,并自己修改了一点 css。
修改过的 css:
beautify() headStyle(fontsize) padding-left: unit(fontsize + 12, 'px') &:before margin-left: unit((-(fontsize + 6)), 'px') font-size: unit(fontsize, 'px') &:hover padding-left: unit(fontsize + 18, 'px') h1, h2, h3, h4, h5, h6 transition: all .2s ease-out &:before position: absolute top: calc(50% - 7px) color: $title-prefix-icon-color content: $title-prefix-icon line-height: 1 transition: all .2s ease-out @extend .fontawesomeIcon &:hover &:before color: $light-blue h1 headStyle(20) h2 headStyle(18) h3 headStyle(16) h4 headStyle(14) h5 headStyle(12) h6 headStyle(12) ol, ul p margin: 0 0 8px li &::marker color: $light-blue font-weight: 600 font-size: 1.05em &:hover &::marker color: var(--pseudo-hover) ul > li list-style-type: circle #article-container word-wrap: break-word overflow-wrap: break-word a color: $theme-link-color &:hover text-decoration: underline img display: block margin: 0 auto 20px max-width: 100% transition: filter 375ms ease-in .2s p margin: 0 0 16px iframe margin: 0 0 20px if hexo-config('anchor') a.headerlink &:after @extend .fontawesomeIcon float: right color: var(--headline-presudo) content: '\f0c1' font-size: .95em opacity: 0 transition: all .3s &:hover &:after color: var(--pseudo-hover) h1, h2, h3, h4, h5, h6 &:hover a.headerlink &:after opacity: 1 ol, ul ol, ul padding-left: 20px li margin: 4px 0 p margin: 0 0 8px if hexo-config('beautify.enable') if hexo-config('beautify.field') == 'site' beautify() else if hexo-config('beautify.field') == 'post' &.post-content beautify() > :last-child margin-bottom: 0 !important #post .tag_share .post-meta &__tag-list display: inline-block &__tags display: inline-block margin: 8px 8px 8px 0 padding: 0 12px width: fit-content border: 1px solid $light-blue border-radius: 12px color: $light-blue font-size: .85em transition: all .2s ease-in-out &:hover background: $light-blue color: var(--white) .post_share display: inline-block float: right margin: 8px 0 width: fit-content .social-share font-size: .85em .social-share-icon margin: 0 4px width: w = 1.85em height: w font-size: 1.2em line-height: w .post-copyright position: relative margin: 40px 0 10px padding: 10px 16px border: 1px solid var(--light-grey) transition: box-shadow .3s ease-in-out overflow: hidden border-radius: 12px!important background: none; &:before background var(--heo-post-blockquote-bg) position absolute right -26px top -120px content '\f25e' font-size 200px font-family 'Font Awesome 5 Brands' opacity .2 &:hover box-shadow: 0px 0px 8px 1px #e5e5e5 .post-copyright &-meta color: $light-blue font-weight: bold &-info padding-left: 6px a text-decoration: none word-break: break-word &:hover text-decoration: none .post-copyright-cc-info color: $theme-color; .post-outdate-notice position: relative margin: 0 0 20px padding: .5em 1.2em border-radius: 3px background-color: $noticeOutdate-bg color: $noticeOutdate-color if hexo-config('noticeOutdate.style') == 'flat' padding: .5em 1em .5em 2.6em border-left: 5px solid $noticeOutdate-border &:before @extend .fontawesomeIcon position: absolute top: 50% left: .9em color: $noticeOutdate-border content: '\f071' transform: translateY(-50%) .ads-wrap margin: 40px 0 .post-copyright-m-info .post-copyright-a, .post-copyright-c, .post-copyright-u display inline-block width fit-content padding 2px 5px [data-theme="dark"] #post .post-copyright background #07080a text-shadow #bfbeb8 0 0 2px border 1px solid rgb(19 18 18 / 35%) animation flashlight 1s linear infinite alternate .post-copyright-info color #e0e0e4 #post .post-copyright__title font-size 22px .post-copyright__notice font-size 15px
返回顶部显示网页阅读进度
虽然 Buttrtfly 4.6 版本 就加入了内置了这个功能,可以在配置文件开启,但是内置的的滑动没有 Leonus 的丝滑,所以还是选择自己动手。
用了 Leonus 的教程,但是发现 Leonus 大佬的 js 在我这里有点小问题,所以也自己修改了一下。
这是我修改过的 js(把 childNodes
改成了 children
)
window.onscroll = percent; // 执行函数 // 页面百分比 function percent() { let a = document.documentElement.scrollTop || window.pageYOffset; // 卷去高度 let b = Math.max( document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight ) - document.documentElement.clientHeight; // 整个网页高度 let result = Math.round((a / b) * 100); // 计算百分比 let up = document.querySelector("#go-up"); // 获取按钮 percentSpan = document.querySelector("#percent"); // 获取显示的按钮 if (result <= 95) { up.children[0].style.display = "none"; up.children[1].style.display = "block"; percentSpan.children[0].innerHTML = result; } else { up.children[1].style.display = "none"; up.children[0].style.display = "block"; } }
打开控制台和复制提醒
按键防抖:
// 按键防抖 let TT = null; // 防抖全局计时器 /** * 防抖函数 * @param {逻辑} fn * @param {防抖时间} time */ function debounce(fn, time) { if (TT !== null) clearTimeout(TT); TT = setTimeout(fn, time); } // 按键防抖 end -- // 检测事件并弹窗 document.onkeydown = function (e) { // 复制 if (e.ctrlKey && e.key === "c") { debounce(function () { Snackbar.show({ text: "复制成功啦🌞若要转载最好保留原文链接!", pos: "top-right", actionText: "版权声明", actionTextColor: "#FF8599", onActionClick() { location.assign("/privacy"); }, }); }, 300); } // 打开控制台 if ( e.keyCode == 123 || (e.ctrlKey && e.shiftKey && (e.keyCode === 74 || e.keyCode === 73 || e.keyCode === 67)) || (e.ctrlKey && e.keyCode === 85) ) { debounce(function () { Snackbar.show({ text: "开发者模式已打开🍟记住要遵循GPL协议吖!", pos: "top-right", showAction: false, }); }, 300); } }; // 检测事件并弹窗 end --
/* Snackbar弹窗 */ .snackbar-container { border-radius: 15px; } /* Snackbar弹窗 end */
Heo 加载动画
博客宽屏适配
文章双栏
在店长的教程上做了一点自己的修改
替换 [themes]\butterfly\layout\includes\mixins\post-ui.pug
为下面代码(用的是店长的,删减了一些东西)
mixin postUI(posts) each article , index in page.posts.data .recent-post-item - let link = article.link || article.path let title = article.title || _p('no_title') const position = theme.cover.position let leftOrRight = position === 'both' ? index%2 == 0 ? 'left' : 'right' : position === 'left' ? 'left' : 'right' let post_cover = article.cover let no_cover = article.cover === false || !theme.cover.index_enable ? 'no-cover' : '' - .recent-post-content(class=leftOrRight) .recent-post-cover img.article-cover(src=url_for(post_cover) onerror=`this.onerror=null;this.src='`+ url_for(theme.error_img.post_page) + `'` alt=title) .recent-post-info a.article-title(href=url_for(link) title=title) .article-title-link= title .recent-post-meta .article-meta-wrap if (is_home() && (article.top || article.sticky > 0)) span.article-meta i.fas.fa-thumbtack.sticky span.sticky= _p('sticky') span.article-meta-separator | if (theme.post_meta.page.date_type) span.post-meta-date if (theme.post_meta.page.date_type === 'both') i.far.fa-calendar-alt span.article-meta-label=_p('post.created') time.post-meta-date-created(datetime=date_xml(article.date) title=_p('post.created') + ' ' + full_date(article.date))=date(article.date, config.date_format) span.article-meta-separator | i.fas.fa-history span.article-meta-label=_p('post.updated') time.post-meta-date-updated(datetime=date_xml(article.updated) title=_p('post.updated') + ' ' + full_date(article.updated))=date(article.updated, config.date_format) else - let data_type_updated = theme.post_meta.page.date_type === 'updated' - let date_type = data_type_updated ? 'updated' : 'date' - let date_icon = data_type_updated ? 'fas fa-history' :'far fa-calendar-alt' - let date_title = data_type_updated ? _p('post.updated') : _p('post.created') i(class=date_icon) span.article-meta-label=date_title time(datetime=date_xml(article[date_type]) title=date_title + ' ' + full_date(article[date_type]))=date(article[date_type], config.date_format) if (theme.post_meta.page.categories && article.categories.data.length > 0) span.article-meta span.article-meta-separator | i.fas.fa-inbox each item, index in article.categories.data a(href=url_for(item.path)).article-meta__categories #[=item.name] if (index < article.categories.data.length - 1) i.fas.fa-angle-right.article-meta-link if (theme.post_meta.page.tags && article.tags.data.length > 0) span.article-meta.tags span.article-meta-separator | i.fas.fa-tag each item, index in article.tags.data a(href=url_for(item.path)).article-meta__tags #[=item.name] if (index < article.tags.data.length - 1) span.article-meta-link #[='•'] mixin countBlockInIndex - needLoadCountJs = true span.article-meta span.article-meta-separator | i.fas.fa-comments if block block span.article-meta-label= ' ' + _p('card_post_count') if theme.comments.card_post_count case theme.comments.use[0] when 'Disqus' +countBlockInIndex a(href=full_url_for(link) + '#disqus_thread') i.fa-solid.fa-spinner.fa-spin when 'Disqusjs' +countBlockInIndex a(href=full_url_for(link) + '#disqusjs') span.disqus-comment-count(data-disqus-url=full_url_for(link)) i.fa-solid.fa-spinner.fa-spin when 'Valine' +countBlockInIndex a(href=url_for(link) + '#post-comment') span.valine-comment-count(data-xid=url_for(link)) i.fa-solid.fa-spinner.fa-spin when 'Waline' +countBlockInIndex a(href=url_for(link) + '#post-comment') span.waline-comment-count(id=url_for(link)) i.fa-solid.fa-spinner.fa-spin when 'Twikoo' +countBlockInIndex a.twikoo-count(href=url_for(link) + '#post-comment') i.fa-solid.fa-spinner.fa-spin when 'Facebook Comments' +countBlockInIndex a(href=url_for(link) + '#post-comment') span.fb-comments-count(data-href=urlNoIndex(article.permalink)) when 'Remark42' +countBlockInIndex a(href=url_for(link) + '#post-comment') span.remark42__counter(data-url=urlNoIndex(article.permalink)) i.fa-solid.fa-spinner.fa-spin when 'Artalk' +countBlockInIndex a(href=url_for(link) + '#post-comment') span.artalk-count(data-page-key=url_for(link)) i.fa-solid.fa-spinner.fa-spin a.article-content(href=url_for(link) title=title) if theme.ad && theme.ad.index if (index + 1) % 3 == 0 .recent-post-item.ads-wrap!=theme.ad.index
用的是 模式二 并且将三栏修改成双栏,加上自己的一些修改
// 默认的首页卡片容器布局 .recent-posts padding 0 15px 0 15px height fit-content .recent-post-item margin-bottom 15px background var(--recent-post-bgcolor) overflow hidden border-radius 15px .recent-post-content display flex background var(--recent-post-bgcolor) position relative .recent-post-cover display flex background transparent .recent-post-info display flex background transparent flex-direction column justify-content center align-items center .article-title height 50% display: flex text-align: center align-items: center justify-content: flex-end flex-direction: column .article-title-link color: var(--text-highlight-color) font-size: 20px -webkit-line-clamp: 2 line-height: 30px margin-top: 0 font-weight: 700 margin-bottom: 0 width: 100% -webkit-transition: .3s -moz-transition: .3s -o-transition: .3s -ms-transition: .3s transition: .3s display: -webkit-box overflow: hidden -webkit-box-orient: vertical &:hover color: $text-hover .recent-post-meta height 50% display: flex text-align: center flex-direction: row align-items: center .article-meta-wrap color #969797 display: -webkit-box; -webkit-box-orient: vertical overflow: hidden a color: var(--text-highlight-color) transition: all .2s ease-in-out color #969797 &:hover color: $text-hover .article-content display flex text-align: center flex-direction row align-items center justify-content center .article-content-text display -webkit-box -webkit-box-orient vertical text-overflow: ellipsis overflow hidden color #fff text-shadow 1px 2px 3px #000 &.ads-wrap display: block !important height: auto !important nav#pagination width: 100% // 卡片单元布局样式 .recent-posts padding 0 15px 0 15px display flex flex-direction row flex-wrap wrap justify-content: space-between .recent-post-item border-radius 15px overflow hidden .recent-post-content flex-direction column flex-wrap nowrap align-items center max-height 400px height: auto width 100% .recent-post-cover width 100% height 200px // clip-path polygon(0 130px,0 0,100% 0,100% 130px,50% 100%) img height 200px width 100% object-fit cover .recent-post-info height 150px width 100% padding 0px 25px 5px 25px .article-title margin: 0px 40px font-size 18px .article-title-link -webkit-line-clamp: 2; .recent-post-meta .article-meta-wrap font-size 95% -webkit-line-clamp: 3; .article-content position absolute height 200px width 100% .article-content-text -webkit-line-clamp 3 font-size 16px margin 0px 25px 30px 25px &::before content "❝" font-size 20px &::after content "❞" font-size 20px // 双栏布局卡片自适应适配 @media screen and (min-width:572px) .recent-posts .recent-post-item width 49% border 2px solid var(--recent-post-borderColor) box-shadow: var(--card-box-shadow) transition: .5s &:hover box-shadow: var(--card-hover-box-shadow) border 2px solid var(--recent-post-hover-borderColor) // 单栏布局卡片自适应适配 @media screen and (max-width:572px) .recent-posts .recent-post-item width 100% transition: .5s
.article-meta-separator, .article-meta-wrap i, .article-meta-link { margin: 0 6px; }
信息卡片头像状态
Nav 导航栏修改
原本的样式有问题,无法居中,扒了一下鱼佬的导航栏,重新改了一版
部分来自于
- 分离搜索栏与菜单栏
- 子菜单横向布局
- 网站标题部分的增强版 (自己修改了一些)
- 显示标题 (自己修改了上下滑动动画和去除 jq 依赖)
上下滑动动画
修改 [themes]\butterfly\layout\includes\header\nav.pug
: (注意缩进)
nav#nav + #navBox span#blog-info a(href=url_for('/') title=config.title) if theme.nav.logo img.site-icon(src=url_for(theme.nav.logo)) if theme.nav.display_title span.site-name=config.title #menus !=partial('includes/header/menu_item', {}, {cache: true}) + #menuTitleBox + center(id="name-container") + a(id="page-name" href="javascript:scrollToTop()") PAGE_NAME #nav-right if (theme.algolia_search.enable || theme.local_search.enable) #search-button a.site-page.social-icon.search i.fas.fa-search.fa-fw #toggle-menu a.site-page i.fas.fa-bars.fa-fw
添加 nav.js
document.addEventListener("pjax:complete", tonav); document.addEventListener("DOMContentLoaded", tonav); function tonav() { function up() { document.querySelector("#name-container").style.transform = "translate(-50%, 60px)"; document.querySelector("#nav .menus_items").style.transform = "translateY(0)"; document.querySelector("#menuTitleBox").style.zIndex = "-1"; } function scrollToTop() { btf.scrollToDest(0, 500); } function updatePageName() { const pageNameElement = document.getElementById("page-name"); if (pageNameElement) { pageNameElement.innerText = document.title.split(" | 鹊楠の小窝")[0]; } else { // 使用 MutationObserver 监听 DOM 变化,确保元素加载后更新标题 const observer = new MutationObserver((mutations, observer) => { const pageNameElement = document.getElementById("page-name"); if (pageNameElement) { pageNameElement.innerText = document.title.split(" | 鹊楠の小窝")[0]; observer.disconnect(); // 元素找到后停止观察 } }); // 开始观察整个文档 observer.observe(document.body, { childList: true, subtree: true }); } } up(); let position = window.scrollY; window.addEventListener("scroll", function () { let scroll = window.scrollY; if (scroll > position) { document.querySelector("#name-container").style.transform = "translate(-50%, 0)"; document.querySelector("#nav .menus_items").style.transform = "translateY(-60px)"; document.querySelector("#menuTitleBox").style.zIndex = "1"; } else { up(); } position = scroll; }); document .querySelector("#name-container") .addEventListener("click", function () { scrollToTop(); }); updatePageName(); // 调用更新页面标题的函数 }
完整 css (我也挑不出来了,混在一起)
/* Nav导航栏 */ #nav #navBox { width: 100%; height: 60px; position: relative; display: flex; align-items: center; } #nav .site-page:not(.child):after { display: none; } .nav-fixed #nav { backdrop-filter: blur(5px) saturate(150%); } .menus_item_child li:not(#sidebar-menus li) { float: left; border-radius: 6px !important; -webkit-border-radius: 6px !important; -moz-border-radius: 6px !important; -ms-border-radius: 6px !important; -o-border-radius: 6px !important; } .menus_item_child:not(#sidebar-menus ul) { /* left:calc(-150%)!important;这是估算值,为了保持元素居中的,如果不合适可以自己调 改为:*/ left: 50%; translate: -50%; } #nav #blog-info { overflow: visible; flex: none; z-index: 100; } #nav #blog-info a { position: relative; font-size: 1.2em; } #nav #blog-info a::before { opacity: 0; background-color: var(--theme-color) !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; transform: translate(-50%, -50%); top: 55%; left: 50%; width: 120%; height: 120%; content: "\f015"; box-shadow: 0 0 5px var(--theme-color); font-family: "Font Awesome 6 Free"; text-align: center; color: white; line-height: 34px; font-size: 18px; font-weight: 900; } #nav #blog-info a:hover::before { opacity: 1; scale: 1.03; } #nav.hide-menu .menus_items { display: inline-block; transition: 0.3s; } #nav .menus_items .menus_item, #nav .site-page.social-icon.search { padding: 0 10px; margin: 0 5px; border-radius: 10px; transition: 0.5s; } #nav .menus_items .menus_item:hover, #nav .site-page.social-icon.search:hover { background: var(--theme-color); box-shadow: 0 0 5px var(--theme-color); } #nav .menus_items .menus_item:hover a { color: #fff; } #page-header.nav-fixed #nav .menus_items .menus_item:hover a, #page-header.nav-fixed #nav .site-page.social-icon.search:hover { color: #fff; } #menuTitleBox { position: absolute; z-index: -1; width: 100%; height: 100%; top: 0; left: 0; overflow: hidden; } #menuTitleBox #name-container { height: 100%; line-height: 60px; position: absolute; left: 50%; transform: translateX(-50%); transition: 0.3s; } #menuTitleBox #name-container::before { opacity: 0; background-color: var(--theme-color) !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; transform: translate(-50%, -50%); top: 50%; left: 50%; width: 100%; height: 60%; content: "回到顶部"; box-shadow: 0 0 5px var(--theme-color); text-align: center; color: white; line-height: 36px; font-size: 18px; font-weight: 900; } #menuTitleBox #name-container:hover::before { opacity: 1; scale: 1.03; cursor: pointer; } #nav.hide-menu #toggle-menu { display: none !important; } #nav #nav-right { z-index: 100; position: absolute; right: 0; } #nav a.site-page { padding-bottom: 6px; display: inline-block; } #nav a.site-page span { padding-left: 4px; } #nav a.site-page::before { display: none; } #nav #menus { position: absolute; display: flex; width: 100%; align-items: center; justify-content: center; } #nav #menus .menus_items { transition: 0.3s; } #nav .menus_items .menus_item .menus_item_child { padding: 5px; border-radius: 15px; } #nav .menus_items .menus_item .menus_item_child li { transition: 0.3s; border-radius: 10px !important; margin: 0 2px; } #nav .menus_items .menus_item .menus_item_child li:hover { background: var(--theme-color); } #nav .menus_items .menus_item .menus_item_child li:hover a { color: #fff !important; } @media screen and (max-width: 768px) { /* 菜单修复 */ #nav.hide-menu #toggle-menu { display: inline-block !important; } #nav #menus, #nav #menuTitleBox { display: none; } #nav #blog-info a { font-size: 1em; } } /* Nav导航栏 */
旧版本
修改 [themes]\butterfly\layout\includes\header\nav.pug
#menus !=partial('includes/header/menu_item', {}, {cache: true}) + #menuTitleBox + center(id="name-container") + a(id="page-name" href="javascript:scrollToTop()") PAGE_NAME ...
在 js 文件夹新建并引用这段代码
document.addEventListener("pjax:complete", tonav); document.addEventListener("DOMContentLoaded", tonav); function up() { document.querySelector("#name-container").style.top = "60px"; document.querySelector("#nav.hide-menu .menus_items").style.transform = "translateY(0)"; document.querySelector("#menuTitleBox").style.zIndex = "-1"; } function scrollToTop() { btf.scrollToDest(0, 500); } function tonav() { up(); let position = window.scrollY; window.addEventListener("scroll", function () { let scroll = window.scrollY; if (scroll > position) { document.querySelector("#name-container").style.top = "0"; document.querySelector("#nav.hide-menu .menus_items").style.transform = "translateY(-60px)"; document.querySelector("#menuTitleBox").style.zIndex = "1"; } else { up(); } position = scroll; }); document .querySelector("#name-container") .addEventListener("click", function () { scrollToTop(); }); document.getElementById("page-name").innerText = document.title.split(" | 鹊楠の小窝")[0]; }
最后是 css 部分 (仅实现这个功能)
#nav #blog-info { overflow: visible; flex: none; z-index: 99; } #menuTitleBox { position: absolute; z-index: -1; width: 100%; height: 100%; top: 0; left: 0; overflow: hidden; } #menuTitleBox #name-container { height: 100%; line-height: 60px; position: absolute; left: 50%; transform: translateX(-50%); transition: 0.5s; } #nav.hide-menu #toggle-menu { display: none !important; } #nav #nav-right { z-index: 99; } @media screen and (max-width: 572px) { /* 菜单修复 */ #nav.hide-menu #toggle-menu { display: inline-block !important; } #menus { display: none; } #nav #blog-info a { font-size: 1em; } }
完整 css
/* Nav导航栏 */ #nav { justify-content: space-between; user-select: none; } #nav .site-page:not(.child):after { display: none; } .nav-fixed #nav { backdrop-filter: blur(5px) saturate(150%); } .menus_item_child li:not(#sidebar-menus li) { float: left; border-radius: 6px !important; -webkit-border-radius: 6px !important; -moz-border-radius: 6px !important; -ms-border-radius: 6px !important; -o-border-radius: 6px !important; } .menus_item_child:not(#sidebar-menus ul) { /* left:calc(-150%)!important;这是估算值,为了保持元素居中的,如果不合适可以自己调 改为:*/ left: 50%; translate: -50%; } #nav #blog-info { overflow: visible; flex: none; z-index: 99; } #nav #blog-info a { position: relative; font-size: 1.2em; } #nav #blog-info a::before { opacity: 0; background-color: var(--theme-color) !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; transform: translate(-50%, -50%); top: 55%; left: 50%; width: 120%; height: 120%; content: "\f015"; box-shadow: 0 0 5px var(--theme-color); font-family: "Font Awesome 6 Free"; text-align: center; color: white; line-height: 34px; font-size: 18px; font-weight: 900; } #nav #blog-info a:hover::before { opacity: 1; scale: 1.03; } #nav.hide-menu .menus_items { display: inline-block; transition: 0.3s; } #nav .menus_items .menus_item, #nav .site-page.social-icon.search { padding: 0 10px; margin: 0 5px; border-radius: 10px; transition: 0.5s; } #nav .menus_items .menus_item:hover, #nav .site-page.social-icon.search:hover { background: var(--theme-color); box-shadow: 0 0 5px var(--theme-color); } #nav .menus_items .menus_item:hover a { color: #fff; } #page-header.nav-fixed #nav .menus_items .menus_item:hover a, #page-header.nav-fixed #nav .site-page.social-icon.search:hover { color: #fff; } #menuTitleBox { position: absolute; z-index: -1; width: 100%; height: 100%; top: 0; left: 0; overflow: hidden; } #menuTitleBox #name-container { height: 100%; line-height: 60px; position: absolute; left: 50%; transform: translateX(-50%); transition: 0.3s; } #menuTitleBox #name-container::before { opacity: 0; background-color: var(--theme-color) !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; transform: translate(-50%, -50%); top: 50%; left: 50%; width: 100%; height: 60%; content: "回到顶部"; box-shadow: 0 0 5px var(--theme-color); text-align: center; color: white; line-height: 36px; font-size: 18px; font-weight: 900; } #menuTitleBox #name-container:hover::before { opacity: 1; scale: 1.03; } #nav.hide-menu #toggle-menu { display: none !important; } #nav #nav-right { z-index: 99; } #nav a.site-page { padding-bottom: 6px; display: inline-block; } #nav a.site-page span { padding-left: 4px; } #nav a.site-page::before { display: none; } #nav .menus_items .menus_item .menus_item_child { padding: 5px; border-radius: 15px; } #nav .menus_items .menus_item .menus_item_child li { transition: 0.3s; border-radius: 10px !important; margin: 0 2px; } #nav .menus_items .menus_item .menus_item_child li:hover a { color: #fff !important; } @media screen and (max-width: 768px) { /* 菜单修复 */ #nav.hide-menu #toggle-menu { display: inline-block !important; } #menus { display: none; } #nav #blog-info a { font-size: 1em; } } /* Nav导航栏 */
首页分类磁贴
使用的是小冰大佬的插件
其中深色模式适配我是用了 css 变量
# 小冰分类磁贴 color_setting: text_color: var(--fl-text) text_hover_color: var(--fl-hover-text) background_color: var(--fl-bg) background_hover_color: var(--theme-color)
:root { /* 首页分类磁贴 */ --fl-bg: #e5e5e5; --fl-text: #000; --fl-hover-text: #fff; } [data-theme="dark"] { /* 首页分类磁贴 */ --fl-bg: #222; --fl-text: #fff; }
首页置顶轮播
参考
再加上自己微调
/* 首页轮播图 */ #swiper_container .blog-slider__content { height: 250px; } #swiper_container a.blog-slider__title { font-weight: bold; } #swiper_container .blog-slider__text { font-size: 1em; } #swiper_container .swiper-button-next:after, #swiper_container .swiper-button-prev:after { color: var(--theme-color); } /* 首页轮播图 */
归档、分类、标签页美化
参考
自己修改的 css:
归档
/* 归档、标签、分类页 */ #archive, #tag, #category { padding: 25px 10px; } .article-sort-title { margin-top: 30px; margin-bottom: 20px; } .article-sort-item::before, .article-sort-title::before, .article-sort-title::after { content: none; } .article-sort .year { width: 100% !important; border-bottom: dashed 5px var(--theme-color); font-size: 26px; margin-top: 20px; } .article-sort { border: none; display: flex; flex-wrap: wrap; margin: 20px 20px; padding: 0; } .article-sort-item:not(.year) { padding: 8px 10px; width: calc(50% - 0.8rem); margin: 0.4rem; border: 2px solid var(--theme-color); border-radius: 15px; background: var(--card-bg); transition: 0.5s; height: 120px; } .article-sort-item-a { position: absolute; width: 100%; height: 100%; } .article-sort-item-img { transition: 0.5s; height: 90px; width: 140px; } .article-sort-item > a > img { border-radius: 15px; } .article-sort-item-title { font-size: 22px; padding-left: 10px; margin: 10px 0; line-height: 25px; text-overflow: ellipsis; } .article-sort-item-title:hover { transform: none; } .article-sort-meta { height: max-content; position: relative; } .article-sort-meta > .article-meta-wrap { float: left; } .article-sort-meta > .article-sort-item-time { float: right; } .article-sort-item-categories, .article-sort-item-tags { margin: 0 3px; padding: 5px 8px; border-radius: 25px; border: var(--archives-categories-border); font-size: 12px; transition: 0.5s; } .article-sort-item-info > div:not(.article-sort-meta) { display: flex; align-items: center; justify-content: space-between; } .article-sort-item > i { position: absolute; right: 10px; color: var(--archives-hover-font); } .article-sort-description, .article-sort-item > i { width: 0; opacity: 0; overflow: hidden; transition: 0.5s; } .article-sort-description { width: 0; height: 59px; line-height: 59px; vertical-align: middle; margin: 5px 10px 0 15px; text-overflow: ellipsis; } .article-sort-item:hover:not(.year) { background-color: var(--theme-color); box-shadow: 0 0 10px var(--theme-color); } .article-sort-item:hover:not(.year) { background-color: var(--theme-color); box-shadow: 0 0 10px var(--theme-color); } .article-sort-item:hover:not(.year) .article-sort-description, .article-sort-item:hover:not(.year) > i { width: auto; opacity: 1; } .article-sort-item:hover:not(.year) .article-sort-description { width: auto; } .article-sort-item:hover:not(.year) .article-sort-item-img { transition: 0.5s; width: 0; } .article-sort-item:hover:not(.year) .article-sort-item-title { color: var(--archives-hover-font) !important; } .article-sort-item:hover:not(.year) .article-meta-wrap a, .article-sort-item:hover:not(.year) .article-sort-description, .article-sort-item:hover:not(.year) .article-sort-item-time { color: var(--archives-hover-timeColor) !important; } .article-sort-item:hover:not(.year) .article-sort-item-categories { border: var(--archives-categories-border); } .article-sort-item:hover:not(.year) .article-sort-item-tags { border: var(--archives-categories-border); } #pagination .page-number { border-radius: 6px; } @media screen and (max-width: 768px) { .article-sort-item:not(.year) { width: 100%; } .article-sort-meta > .article-meta-wrap { display: none; } .article-sort-item-title { font-size: 16px; } .article-sort-item-img { width: 90px; } } /* 归档、标签、分类页 end */
踩了个坑,归档页显示标签(tags)要在配置文件开启,浪费了我好多时间 😭😭
分类
只参考了一下 meuicat 大佬的页面,css 是自己手搓的 {% psw 绝对不是因为懒得改变量 (确信) %}
/* 分类 */ .category-lists ul li:before { content: "\f550"; font-weight: 900; cursor: pointer; font-family: "Font Awesome 6 Free"; position: static; border: none; font-size: 20px; width: auto; height: auto; } .category-lists .category-list .category-list-count:before, .category-lists .category-list .category-list-count:after { display: none; } .category-lists ul { padding: 0; margin: 20px 0; display: flex; justify-content: center; flex-direction: row; flex-wrap: wrap; } .category-lists ul li { padding: 0.5em; border: 1px solid #cacaca; border-radius: 15px; margin: 10px; padding: 10px; box-shadow: 0 0 8px 6px #2c2d300c; display: flex; justify-content: center; align-items: center; transition: 0.5s; } .category-lists ul li:hover { box-shadow: 0 0 8px 5px var(--theme-color); background: var(--theme-color); border-color: var(--theme-color); transform: scale(1.1); } .category-lists ul li:hover a { color: #fff; } .category-lists ul li a:hover { color: #fff !important; } .category-lists .category-list a { font-size: 1.2em; margin: 0 10px; } .category-lists .category-list .category-list-count { color: #858585; background: #e5e5e5; padding: 2px 15px; margin: 0; border-radius: 10px; }
标签
如果标签页的标签没有数字的话看这里
修改 [themes]\butterfly\scripts\helpers\page.js
const length = sizes.length - 1 source.sort(orderby, order).forEach(tag => { const ratio = length ? sizes.indexOf(tag.length) / length : 0 const size = minfontsize + ((maxfontsize - minfontsize) * ratio) let style = `font-size: ${parseFloat(size.toFixed(2))}${unit};` const color = 'rgb(' + Math.floor(Math.random() * 201) + ', ' + Math.floor(Math.random() * 201) + ', ' + Math.floor(Math.random() * 201) + ')' // 0,0,0 -> 200,200,200 style += ` color: ${color}` - result += `<a href="${env.url_for(tag.path)}" style="${style}">${tag.name}</a>` + result += `<a href="${env.url_for(tag.path)}" style="${style}">${tag.name}<span>${tag.length}</span></a>` }) return result
/* 标签 */ .tag-cloud-list.is-center { display: flex; justify-content: center; flex-direction: row; flex-wrap: wrap; } .tag-cloud-list a { color: var(--font-color) !important; padding: 0.5em; border: 1px solid #cacaca; border-radius: 15px; margin: 10px; padding: 10px; box-shadow: 0 0 8px 6px #2c2d300c; display: flex; justify-content: center; align-items: center; transition: 0.3s; } .tag-cloud-list a:hover { color: #fff !important; box-shadow: 0 0 8px 5px var(--theme-color); background: var(--theme-color); border-color: var(--theme-color); transform: scale(1.1); } .tag-cloud-list a span { margin-left: 10px; color: #858585; background: #e5e5e5; padding: 2px 15px; border-radius: 10px; } .tag-cloud-list a:before { content: "\f02b"; color: var(--tag-icon-color); font-weight: 900; cursor: pointer; font-family: "Font Awesome 6 Free"; position: static; border: none; font-size: 20px; width: auto; height: auto; margin-right: 10px; }
右下角菜单修改
添加直达底部
修改 [themes]\butterfly\layout\includes\rightside.pug
, 在最下面添加代码 (注意缩进)
button#go-down(type="button" title="直达底部" onclick="btf.scrollToDest(document.body.scrollHeight, 500);") i.fas.fa-arrow-down
样式美化
/* 右下角菜单 */ #rightside #rightside-config-show > button, #rightside #rightside-config-hide > button { border-radius: 50%; } /* 右下角菜单 end */
持久化 url
安装 hexo-abbrlink2
插件
npm install hexo-abbrlink2 --save
修改 _config.yml
的 permalink
为
permalink: posts/:abbrlink/ # 永久链接格式
在 _config.yml
添加配置
# hexo-abbrlink2 # 持久化url abbrlink: start: 0 # 启起始文章id,默认为0 ,可以自定义,比如100
Foot 页脚
参考
我的 footer.pug
和 footer.styl
#footer-wrap .wordcount - let allword = totalcount(site) span= '楠居然写了 ' + allword + ' 字' br if isNaN(allword) - allword= Number(allword.replace('k', '')) if allword< 50 span= "还在努力更新中.. 咕咕咕" else if allword< 70 span= "好像写完一本 埃克苏佩里 的 《小王子》 了啊" else if allword< 90 span= "好像写完一本 鲁迅 的 《呐喊》 了啊" else if allword< 100 span= "好像写完一本 林海音 的 《城南旧事》 了啊" else if allword< 110 span= "好像写完一本 马克·吐温 的 《王子与乞丐》了! 了啊" else if allword< 120 span= "好像写完一本 鲁迅 的 《彷徨》 了啊" else if allword< 130 span= "好像写完一本 余华 的 《活着》 了啊" else if allword< 140 span= "好像写完一本 曹禺 的 《雷雨》 了啊" else if allword< 150 span= "好像写完一本 史铁生 的 《宿命的写作》 了啊" else if allword< 160 span= "好像写完一本 伯内特 的 《秘密花园》 了啊" else if allword< 170 span= "好像写完一本 曹禺 的 《日出》 了啊" else if allword< 180 span= "好像写完一本 马克·吐温 的 《汤姆·索亚历险记》 了啊" else if allword< 190 span= "好像写完一本 沈从文 的 《边城》 了啊" else if allword< 200 span= "好像写完一本 亚米契斯 的 《爱的教育》 了啊" else if allword< 210 span= "好像写完一本 巴金 的 《寒夜》 了啊" else if allword< 220 span= "好像写完一本 东野圭吾 的 《解忧杂货店》 了啊" else if allword< 230 span= "好像写完一本 莫泊桑 的 《一生》 了啊" else if allword< 250 span= "好像写完一本 简·奥斯汀 的 《傲慢与偏见》 了啊" else if allword< 280 span= "好像写完一本 钱钟书 的 《围城》 了啊" else if allword< 300 span= "好像写完一本 张炜 的 《古船》 了啊" else if allword< 310 span= "好像写完一本 茅盾 的 《子夜》 了啊" else if allword< 320 span= "好像写完一本 阿来 的 《尘埃落定》 了啊" else if allword< 340 span= "好像写完一本 艾米莉·勃朗特 的 《呼啸山庄》 了啊" else if allword< 350 span= "好像写完一本 雨果 的 《巴黎圣母院》 了啊" else if allword< 360 span= "好像写完一本 东野圭吾 的 《白夜行》 了啊" else span= "好像写完一本我国著名的 四大名著 了!!!" else span= "还在努力更新中.. 咕咕咕" .footer-content div(style="font-size: 0.7rem") span#timeDate= '载入天数...' span= ' ' span#times= '载入时分秒...' script(src="/static/js/duration.js") if theme.footer.owner.enable - var now = new Date() - var nowYear = now.getFullYear() if theme.footer.owner.since && theme.footer.owner.since != nowYear .copyright!= `©${theme.footer.owner.since} - ${nowYear} By ${config.author}` else .copyright!= `©${nowYear} By ${config.author}` if theme.footer.copyright .framework-info span= _p('footer.framework') + ' ' a(href='https://hexo.io')= 'Hexo' span.footer-separator | span= _p('footer.theme') + ' ' a(href='https://github.com/jerryc127/hexo-theme-butterfly')= 'Butterfly' if theme.footer.custom_text .footer_custom_text!=`${theme.footer.custom_text}`
#footer position: relative .wordcount text-align: center font-family: 'Noto Serif SC', -apple-system,BlinkMacSystemFont,Roboto,Segoe UI,Helvetica,Arial,serif font-size: large padding: 2rem 0 0 0 &::before display: none #footer-wrap position: relative padding: 40px 20px color: var(--font-color) text-align: center a color: var(--light-grey) margin: 0 5px &:hover text-decoration: underline img max-height: 20px &>div margin: 10px 0 .footer-separator margin: 0 4px .icp-icon padding: 0 4px max-height: 1.4em width: auto vertical-align: text-bottom
首页封面样式
/* 首页修改 */ body { background: var(--qn-body-bg); /* 确保伪元素相对于容器定位 */ } @media screen and (min-width: 768px) { .page { position: relative; } .page::before { content: ""; position: absolute; top: 0; left: 0; right: 0; bottom: 0; z-index: -1; /* 确保伪元素在内容的下方 */ background: var(--qn-body-bg); background-attachment: local; background-position: center; background-repeat: initial; background-image: var(--qn-bg-img); will-change: opacity, transform, filter; opacity: calc(1 - var(--process) * 1) !important; filter: blur(calc(var(--process) * 10px)); transform: scale(calc(1 + var(--process) * 0.1)); /* 可选,增加平滑过渡效果 */ } [data-theme="dark"] .page.home::before { height: 100vh; } [data-theme="dark"] .page::before { width: 100%; height: 400px; background: var(--qn-body-bg); background-attachment: local; background-position: center; background-repeat: no-repeat; background-size: cover; /* 保持背景图片的原始尺寸 */ background-image: var(--qn-bg-img); } } @media screen and (max-width: 768px) { .page::before { content: ""; position: absolute; top: 0; left: 0; right: 0; bottom: 0; z-index: -1; /* 确保伪元素在内容的下方 */ background: var(--qn-body-bg); background-attachment: local; background-position: center; background-repeat: initial; background-image: var(--qn-bg-img); } [data-theme="dark"] .page::before { width: 100%; height: 100vh; background: var(--qn-body-bg); background-attachment: local; background-position: center; background-repeat: no-repeat; background-size: cover; position: fixed; background-image: var(--qn-bg-img); } } .article-meta-separator, .article-meta-wrap i, .article-meta-link { margin: 0 6px; } .home #page-header:not(.not-top-img):before, .page #page-header::before { display: none; } #page-header { background: none; } /* 导航栏 */ /* 封面标题 */ /* 封面副标题 */ /* 手机端Icon */ #nav a, #page-header #site-title, #page-header #site-subtitle, #page-header #site_social_icons .social-icon { color: var(--header-font-color); } /* 首页修改 end */
// 首页封面样式 window.addEventListener("scroll", function () { // 获取当前页面滚动的高度 const scrollTop = window.scrollY || document.documentElement.scrollTop; // 获取90%视口高度,即页面90vh对应的像素值 const thresholdHeight = window.innerHeight * 0.8; // 计算scrollTop占thresholdHeight的比例,并限制在0-1之间 let scrollPercentage = scrollTop / thresholdHeight; if (scrollPercentage > 1) { scrollPercentage = 1; } else if (scrollPercentage < 0) { scrollPercentage = 0; } // 输出或使用这个scrollPercentage值 console.log(scrollPercentage); // 将这个值应用于其他操作,例如CSS变量 document.documentElement.style.setProperty("--process", scrollPercentage); }); // 首页封面样式 end --
文章页样式
/* 文章页 */ /* 顶部封面 */ .post-bg { position: relative; } #page-header:not(.not-top-img):before { position: absolute; width: 100%; height: 100%; background-color: var(--mark-bg); content: ""; backdrop-filter: blur(8px) brightness(0.5); } .post #page-header { background-position: center center; background-size: cover; background-repeat: no-repeat; } /* 导航栏 */ .post #page-header #nav a { color: var(--post-header-font-color); } .post #page-header.nav-fixed #nav a { color: var(--post-fixed-nav-font-color); } /* 目录 */ #aside-content #card-toc .toc-content .toc-link.active { border-radius: 5px; } /* 文章页 end */
波浪线
参考
搜索时滚动条消失恢复
我发现在打开搜索弹窗的时候会禁止滚动页面,并且滚动条会消失,造成页面宽度变化,很丑,所以就找办法给他干掉了
修改 [themes]\butterfly\source\js\search\local-search.js
大约第 7 行
window.addEventListener('load', () => { let loadFlag = false let dataObj = [] const $searchMask = document.getElementById('search-mask') const openSearch = () => { - const bodyStyle = document.body.style - bodyStyle.width = '100%' - bodyStyle.overflow = 'hidden' btf.animateIn($searchMask, 'to_show 0.5s') btf.animateIn(document.querySelector('#local-search .search-dialog'), 'titleScale 0.5s') setTimeout(() => { document.querySelector('#local-search-input input').focus() }, 100) if (!loadFlag) { search() loadFlag = true } ...
修改网站 cdn
优化一下加载速度
cdn 大部分来自 Heo 佬
Butterfly CDN链接更改指南,替换jsdelivr提升访问速度
我的 option
option: countup_js: /static/js/countup.js # main_css: # main: # utils: translate: https://cdn.jsdmirror.com/npm/js-heo@1.0.6/translate/tw_cn.js # local_search: algolia_js: https://cdn.jsdmirror.com/npm/js-heo@1.0.11/algolia/algolia.js algolia_search_v4: https://cdn.staticfile.org/algoliasearch/4.14.3/algoliasearch-lite.umd.min.js instantsearch_v4: https://cdn.staticfile.org/instantsearch.js/4.49.2/instantsearch.production.min.js # docsearch_js: # docsearch_css: pjax: https://lib.baomitu.com/pjax/0.2.8/pjax.min.js gitalk: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/gitalk/1.7.2/gitalk.min.js gitalk_css: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/gitalk/1.7.2/gitalk.min.css # blueimp_md5: valine: https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/valine/1.4.16/Valine.min.js disqusjs: https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/disqusjs/1.3.0/disqus.js disqusjs_css: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/disqusjs/1.3.0/disqusjs.css twikoo: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/twikoo/1.4.18/twikoo.all.min.js # waline_js: # waline_css: sharejs: https://lib.baomitu.com/social-share.js/1.0.16/js/social-share.min.js sharejs_css: https://lib.baomitu.com/social-share.js/1.0.16/css/share.min.css # mathjax: # katex: # katex_copytex: # mermaid: # canvas_ribbon: # canvas_fluttering_ribbon: # canvas_nest: lazyload: https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/vanilla-lazyload/17.3.1/lazyload.iife.min.js instantpage: https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/instant.page/5.1.0/instantpage.min.js typed: https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/typed.js/2.0.12/typed.min.js # pangu: fancybox_css_v4: https://cdn.staticfile.org/fancyapps-ui/4.0.31/fancybox.min.css fancybox_v4: https://cdn.staticfile.org/fancyapps-ui/4.0.31/fancybox.umd.min.js medium_zoom: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/medium-zoom/1.0.6/medium-zoom.min.js snackbar_css: https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/node-snackbar/0.1.16/snackbar.min.css snackbar: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/node-snackbar/0.1.16/snackbar.min.js # activate_power_mode: # fireworks: # click_heart: # ClickShowText: fontawesomeV6: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/font-awesome/6.0.0/css/all.min.css # flickr_justified_gallery_js: # flickr_justified_gallery_css: aplayer_css: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/aplayer/1.10.1/APlayer.min.css aplayer_js: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/aplayer/1.10.1/APlayer.min.js meting_js: https://cdn.jsdmirror.com/npm/js-heo@1.0.12/metingjs/Meting.min.js prismjs_js: https://cdn.jsdmirror.com/npm/prismjs@1.1.0/prism.js prismjs_lineNumber_js: https://cdn.jsdmirror.com/npm/prismjs/plugins/line-numbers/prism-line-numbers.min.js prismjs_autoloader: https://cdn.jsdmirror.com/npm/prismjs/plugins/autoloader/prism-autoloader.min.js # artalk_js: # artalk_css: busuanzi: //npm.elemecdn.com/penndu@1.0.0/bsz.js
那年今日
基于 butterfly 主题的历史上的今天 2.0 重置版
点击文章卡片进入文章页
参考
子级a标签href避免触发父级onclick的方法,子元素阻止冒泡
看不懂的点这里
修改 [themes]\butterfly\layout\includes\mixins\post-ui.pug
:
mixin postUI(posts) each article , index in page.posts.data + - let link = article.link || article.path + .recent-post-item(onclick=`pjax.loadUrl('${url_for(link)}')`) - .recent-post-item - - let link = article.link || article.path let title = article.title || _p('no_title') const position = theme.cover.position let leftOrRight = position === 'both' ? index%2 == 0 ? 'left' : 'right' : position === 'left' ? 'left' : 'right' let post_cover = article.cover let no_cover = article.cover === false || !theme.cover.index_enable ? 'no-cover' : '' -
往下翻找到 .article-meta__categories
和 .article-meta__tags
, 在 a
标签后的括号内添加 onclick="window.event.cancelBubble=true;"
(注意,要加个空格)
if (theme.post_meta.page.categories && article.categories.data.length > 0) span.article-meta span.article-meta-separator | i.fas.fa-inbox each item, index in article.categories.data + a(href=url_for(item.path) onclick="window.event.cancelBubble=true;").article-meta__categories #[=item.name] if (index < article.categories.data.length - 1) i.fas.fa-angle-right.article-meta-link if (theme.post_meta.page.tags && article.tags.data.length > 0) span.article-meta.tags span.article-meta-separator | i.fas.fa-tag each item, index in article.tags.data + a(href=url_for(item.path) onclick="window.event.cancelBubble=true;").article-meta__tags #[=item.name] if (index < article.tags.data.length - 1) span.article-meta-link #[='•']
外挂标签之折叠栏
店长的外挂标签里的折叠栏不是很喜欢,因为用的是 details
元素实现的,没有过渡动画,所以就自己重写了一下源码和样式
示例代码 (其实和店长的没啥区别,就是少了个颜色的选项)
{% folding, 展示 %} {% folding open, 默认打开 %} 内容 {% endfolding %} {% folding, 默认关闭 %} 内容 {% endfolding %} {% endfolding %}
在 [themes]\butterfly\scripts\tag
目录下新建 folding.js
文件
"use strict"; function postFolding(args, content) { args = args.join(" ").split(","); let style = ""; let title = ""; if (args.length > 1) { style = args[0].trim(); title = args[1].trim(); } else if (args.length > 0) { title = args[0].trim(); } if (style != undefined) { return `<div class="details" ${style}> <div class="collapsible"> ${title} </div> <div class="content"> ${hexo.render .renderSync({ text: content, engine: "markdown" }) .split("\n") .join("")} </div> </div>`; } else { return `<div class="details"> <div class="collapsible"> ${title} </div> <div class="content"> ${hexo.render .renderSync({ text: content, engine: "markdown" }) .split("\n") .join("")} </div> </div>`; } } hexo.extend.tag.register("folding", postFolding, { ends: true });
在 [themes]\butterfly\source\css\_tags
目录下新建 folding.styl
文件
Tips:如果需要修改颜色,改颜色变量就好了
.details margin: 1em 0 border: 1px solid transparent border-radius: 10px transition: all 0.3s .content padding: 0 20px height: 0 overflow: hidden transition: all 0.3s .collapsible background-color: var(--linkDiv-bgColor) color: white cursor: pointer padding: 8px text-align: left outline: none font-size: 15px border-radius: 10px transition: all 0.3s color: var(--linkDiv-titleColor) display: flex align-items: center position: relative user-select: none &:hover cursor: pointer background-color: var(--theme-color) color: var(--linkDiv-hoverColor) &:after opacity: 1 color: var(--linkDiv-hoverColor) &:before color: var(--linkDiv-hoverColor) &:before content: "\f0da" font-weight: 900 font-family: "Font Awesome 6 Free" font-size: 1.3em color: var(--theme-color) margin-right: 10px transition: all 0.3s &:after content: '\002B' color: var(--linkDiv-titleColor) opacity: 0 font-weight: bold float: right position: absolute right: 15px transition: 0.3s .details[open]>.collapsible:after content: "\2212" .details[open]>.collapsible border-radius: 9px 9px 0 0 background-color: var(--theme-color) color: var(--linkDiv-hoverColor) margin-bottom: 20px .details[open]>.collapsible:after opacity: 1 color: var(--linkDiv-hoverColor) .details[open]>.collapsible:before transform: rotate(90deg) color: var(--linkDiv-hoverColor) .details[open]>.content border-radius: 0 0 10px 10px .details[open] border: 1px solid var(--theme-color)
在自己的 js 文件夹下新建 foldMain.js
文件 (名字随意的啦) 并引用
document.querySelectorAll(".collapsible").forEach((button) => { let heightTimeOut; button.addEventListener("click", function () { const details = this.parentElement; const content = details.querySelector(".content"); const contentTranTime = Number.parseFloat(window.getComputedStyle(content).transitionDuration) * 1000; // 切换 open 属性 if (details.hasAttribute("open")) { if (heightTimeOut) { clearTimeout(heightTimeOut); } content.style.height = content.scrollHeight + "px"; setTimeout(() => { details.removeAttribute("open"); content.style.height = 0 + "px"; // 收起时,重置 max-height }, 1); } else { details.setAttribute("open", ""); content.style.height = content.scrollHeight + "px"; // 展开时,设置 max-height 为内容高度 heightTimeOut = setTimeout(() => { content.style.height = "auto"; }, contentTranTime); } }); }); // 页面加载时,为已展开的内容设置 max-height document.querySelectorAll(".details[open]").forEach((details) => { const content = details.querySelector(".content"); content.style.height = "auto"; });
引入 foldMain.js
并适配 Pjax
- <script data-pjax src="/static/js/foldMain.js?1"></script> # 外挂标签-折叠栏
说说
因为我没有服务器 😭,所以使用的是本地静态的说说,正好浮杨大佬新开发了一个说说,我就试试水
浮杨佬说说的项目地址
正常插件安装版
没有自定义需求的直接 npm 安装就好了
npm install hexo-butterfly-statictalk
鹊楠魔改免安装版
这个是我自己改给自己用的,舍弃掉了自动生成时间,可能不是那么好看和好用,可以自己改改
2024/9/2 更新
修复 bug
function arrangeItems() { let container = document.querySelector("#talk-container"); let items = document.querySelectorAll(".talk-wrapper"); if (container && items) { let containerWidth = container.clientWidth; let columns = 3; // 默认列数 if (containerWidth <= 768) { columns = 1; // 窗口宽度 <= 768px 时为单列布局 } else if (containerWidth <= 1000) { columns = 2; // 窗口宽度 <= 1000px 时为双列布局 } let columnHeights = new Array(columns).fill(0); // 初始化每列高度为0 let columnWidth = containerWidth / columns; // 计算每列宽度 let margin = 20; // 间隔 // 从后往前遍历 items for (let i = items.length - 1; i >= 0; i--) { let item = items[i]; let itemHeight = item.offsetHeight; let minHeight = Math.min(...columnHeights); // 获取最短列的高度 let minIndex = columnHeights.indexOf(minHeight); // 获取最短列的索引 let translateX = minIndex * columnWidth; let translateY = minHeight; let isLastColumn = minIndex === columns - 1; item.style.transform = `translate(${translateX}px, ${translateY}px)`; item.style.width = isLastColumn ? `${columnWidth}px` : `${columnWidth - margin}px`; columnHeights[minIndex] += itemHeight + margin; } container.style.height = `${Math.max(...columnHeights)}px`; } else { } } function todo() { if (location.pathname.startsWith("/talk")) { arrangeItems(); window.addEventListener("scroll", arrangeItems); window.addEventListener("resize", arrangeItems); } } document.addEventListener("pjax:complete", todo); document.addEventListener("DOMContentLoaded", todo);
新建 talk
页面
hexo new page talk
打开 source\talk\index.md
添加
--- title: 说说 date: 2024-08-10 23:25:34 type: talk ---
修改 [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' include includes/page/categories.pug + when 'talk' + include includes/page/talk.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})
在 [themes]\butterfly\layout\includes\page
文件夹下新建 talk.pug
文件,写入
if site.data.talk #talk-container each i in site.data.talk - let content = markdown(i.content) - let time = i.time - content = content.replace(/<img src="(.*?)"[^>]*>/g, '<a href="$1" data-fancybox="gallery" data-caption="" data-thumb="$1">$&</a>') div.talk-wrapper div.talk-content!= content div.talk-footer div.talk-time= time
在 [themes]\butterfly\source\css\_page
文件夹下新建 talk.styl
文件,写入
#talk-container width 100% position relative .talk-wrapper width 30% position absolute /* 默认宽度,适用于三列布局 */ box-sizing border-box padding 1em border-radius 10px transform translate(0, 0) /* 初始位置 */ transition all 0.3s box-shadow var(--card-box-shadow) border 1px solid var(--talk-time-bg) .talk-content img display: block margin: 0 auto 20px max-width: 100% -webkit-transition: filter 375ms ease-in 0.2s -moz-transition: filter 375ms ease-in 0.2s -o-transition: filter 375ms ease-in 0.2s -ms-transition: filter 375ms ease-in 0.2s transition: filter 375ms ease-in 0.2s .talk-wrapper:hover box-shadow var(--card-hover-box-shadow) border-color var(--theme-color) .talk-content h1, .talk-content h2, .talk-content h3, .talk-content h4, .talk-content h5, .talk-content h6 color var(--font-color) .talk-footer border-top 2px dotted var(--talk-time-bg) padding 5px display flex justify-content flex-end .talk-time padding 3px 7px background var(--talk-time-bg) font-size .7rem border-radius 25px margin-top 5px .talk-time::before content "\f017" font-weight 900 font-family "Font Awesome 6 Free" margin-right 5px @media (max-width: 768px) .talk-wrapper width 100% !important /* 单列布局 */
在自己的 js
文件夹下新建 talk.js
写入
function arrangeItems() { let container = document.querySelector("#talk-container"); let items = document.querySelectorAll(".talk-wrapper"); if (container && items) { let columns = 3; // 默认列数 let containerWidth = container.clientWidth; if (containerWidth <= 768) { columns = 1; // 窗口宽度 <= 768px 时为单列布局 } else if (containerWidth <= 1000) { columns = 2; // 窗口宽度 <= 1000px 时为双列布局 } let columnHeights = new Array(columns).fill(0); // 初始化每列高度为0 let columnWidth = containerWidth / columns; // 计算每列宽度 let margin = 20; // 间隔 items.forEach((item, index) => { // 获取当前元素的高度 let itemHeight = item.offsetHeight; let minHeight = Math.min(...columnHeights); // 获取最短列的高度 let minIndex = columnHeights.indexOf(minHeight); // 获取最短列的索引 // 计算transform位置 let translateX = minIndex * columnWidth; let translateY = minHeight; // 判断是否为最后一列 let isLastColumn = minIndex === columns - 1; // 设置transform位置 item.style.transform = `translate(${translateX}px, ${translateY}px)`; item.style.width = isLastColumn ? `${columnWidth}px` : `${columnWidth - margin}px`; // 最后一列不减去间隔 // 更新列高度 columnHeights[minIndex] += itemHeight + margin; // 加上底部间距 }); // 更新容器的高度以适应所有列 container.style.height = `${Math.max(...columnHeights)}px`; } else { } } if (location.pathname.startsWith("/talk")) { window.onload = arrangeItems(); // 滚动后重新布局 window.addEventListener("scroll", arrangeItems); // 当窗口大小改变时重新布局 window.addEventListener("resize", arrangeItems); }
并在配置文件引入该 js
bottom: - <script data-pjax src="/static/js/talk.js?1"></script> # 说说
最后在 source\_data
文件夹下新建 talk.yml
参考写法
- content: | 1 test # test1   time: 2024-09-01 - content: | 2 # test1 time: 2024-09-01
关于我
直接从鱼那里搬过来的关于页面,做了一点点自己的修改
- 删除捐赠
楠的破烂博客还敢开捐赠?! - 修改 51LA 的统计数据为 Hexo 自带数据
统计数据部分
#statistic div span 文章数量 span= site.posts.length div span 运行时间 span#runtimeshow(data-publishDate=date_xml(theme.runtimeshow.publish_date)) div span 访客数量 span#busuanzi_value_site_uv div span 总访问量 span#busuanzi_value_site_pv div span 最近更新 span#last-push-date(data-lastPushDate=date_xml(Date.now()))
修改国内不蒜子统计平台
来自杜老师的教程
压缩静态资源
来自 空梦大佬
Todo
自己用 md 写的太丑辣,懒得动脑,直接拿 亦小封 佬的用
不过佬的瀑布流代码在我这里有点小问题,我就用我自己的屎山代码代替了))
外挂标签之外链卡片
参考洪哥的样式
做出了自己的修改
修改 [themes]\butterfly\scripts\tag\link.js
:
function link(args) { args = args.join(" ").split(","); let title = args[0]; let sitename = args[1]; let link = args[2]; let isLocalLink = link.startsWith("/"); let tipsText = isLocalLink ? "✅此为本站站点,可以放心食用~" : "❗这是个站外网站呢,不保证站点的可用性和安全性哟~"; let imgUrl = isLocalLink ? "https://tuchuang.voooe.cn/images/2024/01/29/logo_icon.png" : "https://api.iowen.cn/favicon/" + link.replace(/^https?:\/\//i, "") + ".png"; let targetAttr = isLocalLink ? "" : 'target="_blank"'; return `<a class="tag-Link" ${targetAttr} href="${link}"> <div class="tag-link-tips">${tipsText}</div> <div class="tag-link-bottom"> <div class="tag-link-left" style="background-image: url(${imgUrl});"></div> <div class="tag-link-right"> <div class="tag-link-title">${title}</div> <div class="tag-link-sitename">${sitename}</div> </div> <i class="fa-solid fa-angle-right"></i> </div> </a>`; } hexo.extend.tag.register("link", link, { ends: false });
修改 [themes]\butterfly\source\css\_tags\link.styl
:
#article-container .tag.link text-align center a &.link-card margin 0.25rem auto background #f6f6f6 display inline-flex align-items center cursor pointer text-align center min-width 200px max-width 361px color #444 border-radius 12px text-decoration none &:hover box-shadow 0 4px 8px 0 rgba(0, 0, 0, 0.1) div &.left width 48px height 48px margin 12px overflow hidden flex-shrink 0 position relative i font-size 32px line-height 48px margin-left 4px img display block position absolute border-radius 2px top 50% left 50% transform translate(-50%, -50%) &.right overflow hidden margin-right 12px p margin 0 &.text font-weight bold &.url flex-shrink 0 color rgba(68, 68, 68, 0.65) font-size 13px @media screen and (max-width: 425px) #article-container a &.link-card max-width 100% @media screen and (max-width: 375px) #article-container a &.link-card width 100% #article-container a.link-card div.left, #article-container a.link-card div.right pointer-events none [data-theme="dark"] #article-container a &.link-card filter brightness(0.7) img filter brightness(1)
评论样式
参考了 Ariasaka
和 店长
的一些样式
css
/* 评论 */ #twikoo .tk-admin { position: fixed !important; right: -50%; z-index: 999; } #twikoo .tk-admin.__show { left: 100% !important; transform: translateX(-100%); } .tk-input.el-textarea textarea { min-height: 120px !important; } .tk-content { border-radius: 2px 10px 10px 10px; background: #e5e5e5; padding: 5px 20px; color: #000; } .tk-content-expand { max-width: 90%; } .tk-comment .tk-submit .tk-avatar, .tk-replies .tk-avatar { width: 2.5rem !important; height: 2.5rem !important; } .tk-comment.tk-master .tk-avatar.tk-clickable.tk-has-avatar { margin: 0 0 0 1rem !important; } .tk-comment .tk-submit .tk-avatar .tk-avatar-img, .tk-replies .tk-avatar .tk-avatar-img { height: 2.5rem !important; } .tk-comment.tk-master .tk-content { border-radius: 10px 2px 10px 10px; } .tk-comment.tk-master, .tk-comment.tk-master .tk-row, .tk-comment.tk-master .tk-extras { flex-direction: row-reverse; width: 100%; } .tk-comment.tk-master .tk-main { display: flex; flex-direction: column; align-items: flex-end; } .twikoo .el-button--primary.is-disabled, .twikoo .el-button--primary.is-disabled:active, .twikoo .el-button--primary.is-disabled:focus, .twikoo .el-button--primary.is-disabled:hover { background: #fb85999e !important; } .el-button--primary { background-color: var(--theme-color) !important; border-color: var(--theme-color) !important; } .el-button--primary:focus, .el-button--primary:hover { background: #fb8599d9 !important; border-color: #fb8599d9 !important; } .twikoo .el-input__inner:focus, .twikoo .el-textarea__inner:focus, .el-button--primary:focus, .el-button--primary:hover { border-color: #fb8599d9 !important; } .tk-icon.__comments, .tk-action-icon.tk-action-icon-solid, .tk-action-icon, .tk-action-count { color: var(--theme-color) !important; } .tk-tag-green.tk-tag-green { background-color: var(--theme-color); border: none; border-radius: 5px; color: #fff; margin: 0 10px; } #article-container strong:not(strong:has(code)) { background: linear-gradient( rgba(255, 51, 184, 0.15), rgba(255, 51, 184, 0.15) ) no-repeat bottom / 100% 30%; } a.tk-ruser { color: #000; margin: 0 5px; font-weight: 900; font-size: 15px; } .tk-collapse-wrap, .tk-expand-wrap { box-shadow: 0 0 5px; margin-top: 10px; border-radius: 10px; overflow: hidden; transition: 0.3s; } .tk-collapse-wrap:hover, .tk-expand-wrap:hover { border-color: var(--theme-color); } .tk-expand { font-size: 12px; } .tk-expand-wrap .tk-expand:hover { background-color: var(--theme-color); color: #fff; } /* 设置文字内容 :nth-child(1)的作用是选择第几个 */ .el-input.el-input--small.el-input-group.el-input-group--prepend:nth-child( 1 ):before { content: "输入您的昵称🍟"; } .el-input.el-input--small.el-input-group.el-input-group--prepend:nth-child( 2 ):before { content: "收到回复将会发送到您的邮箱,使用QQ邮箱自动获取头像📧"; } .el-input.el-input--small.el-input-group.el-input-group--prepend:nth-child( 3 ):before { content: "可以通过昵称访问您的网站🔗"; } /* 当用户点击输入框时显示 */ .el-input.el-input--small.el-input-group.el-input-group--prepend:focus-within::before, .el-input.el-input--small.el-input-group.el-input-group--prepend:focus-within::after { display: block; } /* 主内容区 */ .el-input.el-input--small.el-input-group.el-input-group--prepend::before { /* 先隐藏起来 */ display: none; /* 绝对定位 */ position: absolute; /* 向上移动60像素 */ top: -60px; /* 文字强制不换行,防止left:50%导致的文字换行 */ white-space: nowrap; /* 圆角 */ border-radius: 10px; /* 距离左边50% */ left: 50%; /* 然后再向左边挪动自身的一半,即可实现居中 */ transform: translate(-50%); /* 填充 */ padding: 14px 18px; background: #444; color: #fff; } /* 小角标 */ .el-input.el-input--small.el-input-group.el-input-group--prepend::after { display: none; content: ""; position: absolute; /* 内容大小(宽高)为0且边框大小不为0的情况下,每一条边(4个边)都是一个三角形,组成一个正方形。 我们先将所有边框透明,再给其中的一条边添加颜色就可以实现小三角图标 */ border: 12px solid transparent; border-top-color: #444; left: 50%; transform: translate(-50%, -48px); } /* 评论 end */
评论区
评论加载中...