进行主题修改前必看
博客魔改有风险,请务必备份你的原代码
因为.pug
和.styl
以及.yml
等对缩进要求较为严格,请尽量不要使用记事本等无法提供语法高亮的文本编辑器进行修改。
本文涉及修改内容会以diff代码块进行标识,复制时请不要忘记删除前面的+,-
符号
本帖基于Anzhiyu主题
进行修改方案编写,因此请读者优先掌握Anzhiyu主题官方文档的内容后再来进行魔改。
本文实现效果的样式定义与部分源码来自于Heo博客,感谢优秀的设计令人赏心悦目。
为了方便写魔改总集缓解字数繁多显得杂乱的情况,特地抽出来一篇最近写的设计实现样式,也就是本文所写的–Tooltip
拓展信息框,方便各位参考以实现相同的设计样式。
📍特别提醒 本文涉及修改内容较多,请务必备份源代码以方便回滚
实现方式
在 anzhiyu\layout\includes\layout.pug
里添加如下内容,以确保页面能调用Tooltip
1 2
| //- 全局 Tooltip 容器(供 Js 动态控制) div.custom-tooltip
|
添加gb-tooltip.js
并引用,内容如下,当然也可以自定义文件名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
| function initTooltip() { const tooltip = document.querySelector(".custom-tooltip"); if (!tooltip) return;
let hideTimer = null; const hasHover = matchMedia("(hover: hover)").matches;
tooltip.style.maxWidth ||= "200px"; tooltip.style.whiteSpace ||= "pre-wrap"; tooltip.style.overflowWrap ||= "break-word"; tooltip.style.opacity ||= "0";
let activeTarget = null; let frozenPos = { top: null, left: null };
function computePosition(el) { tooltip.style.top = "-9999px"; tooltip.style.left = "-9999px"; tooltip.classList.remove("bottom"); void tooltip.offsetHeight;
const rect = el.getBoundingClientRect(); const ttRect = tooltip.getBoundingClientRect(); const offset = 10;
let top = rect.top - ttRect.height - offset; if (rect.top <= ttRect.height + offset) { tooltip.classList.add("bottom"); top = rect.bottom + offset; }
let left = rect.left + rect.width / 2 - ttRect.width / 2; const minPad = 8; left = Math.max(minPad, Math.min(left, window.innerWidth - ttRect.width - minPad));
return { top: Math.round(top), left: Math.round(left) }; }
function applyFrozen() { if (frozenPos.top == null || frozenPos.left == null) return; tooltip.style.top = `${frozenPos.top}px`; tooltip.style.left = `${frozenPos.left}px`; }
function showTooltip(el, text) { clearTimeout(hideTimer); activeTarget = el; tooltip.textContent = text; tooltip.style.opacity = "1";
frozenPos = computePosition(el); applyFrozen(); }
function hideTooltip() { hideTimer = setTimeout(() => { tooltip.style.opacity = "0"; tooltip.classList.remove("bottom"); activeTarget = null; frozenPos = { top: null, left: null }; }, 80); }
function bindTargets(root = document) { root.querySelectorAll("[gbtip], [data-tooltip]").forEach(el => { if (el.dataset.tooltipBound) return; el.dataset.tooltipBound = "true";
const tipText = el.getAttribute("gbtip") || el.getAttribute("data-tooltip"); if (!tipText) return;
if (hasHover) { el.addEventListener("mouseenter", () => showTooltip(el, tipText)); el.addEventListener("mouseleave", hideTooltip); } else { el.addEventListener("touchstart", () => { showTooltip(el, tipText); clearTimeout(hideTimer); hideTimer = setTimeout(hideTooltip, 1500); }, { passive: true });
el.addEventListener("touchend", hideTooltip, { passive: true }); } }); }
function onViewportChange() { if (!activeTarget || tooltip.style.opacity === "0" || !activeTarget.isConnected) return;
const rect = activeTarget.getBoundingClientRect(); const style = window.getComputedStyle(activeTarget); const isFixedOrSticky = style.position === "fixed" || style.position === "sticky";
const inViewport = rect.bottom > 0 && rect.right > 0 && rect.top < window.innerHeight && rect.left < window.innerWidth;
if (isFixedOrSticky || inViewport) { applyFrozen(); } else { hideTooltip(); } }
bindTargets();
window.addEventListener("scroll", onViewportChange, { passive: true }); window.addEventListener("resize", onViewportChange, { passive: true });
window.addEventListener("pjax:send", hideTooltip); window.addEventListener("pjax:success", () => { bindTargets(document); }); }
document.addEventListener("DOMContentLoaded", initTooltip);
|
样式定义,加入CSS,可加入到Custom.css
或自建文件进行调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| .custom-tooltip { position: fixed; background: rgba(255, 255, 255, 0.85); border: var(--style-border-always); backdrop-filter: blur(6px); color: var(--anzhiyu-fontcolor); padding: 8px 12px; border-radius: 12px; font-size: 14px; z-index: 9999; pointer-events: none; opacity: 0; transition: opacity .15s; box-shadow: var(--anzhiyu-shadow-border); max-width: 200px; white-space: pre-wrap; word-wrap: break-word; line-height: 1.3; text-align: center; }
[data-theme="dark"] .custom-tooltip { background: rgba(0, 0, 0, 0.7); color: var(--anzhiyu-white); }
.custom-tooltip.bottom { }
@media (hover: none) and (pointer: coarse) { .custom-tooltip { font-size: 16px; padding: 10px 14px; max-width: 80vw; line-height: 1.4; } }
|
做完以上内容的添加,以后只要在元素上写 gbtip="xxx"
,JS 就会自动处理,添加上tooltip
拓展框。
注: gbtip
可以换为自己的定义,tip
,heotip
皆可,以下内容均以我自己的定义进行删改
关于实现方面,我的修改
如果你是跟着我的魔改修改下来的,以下会有部分内容与我的魔改主题相关,
以下为我的修改内容,你可以参考大部分样式。
📍特别提醒 以下涉及修改内容较多,请务必备份源代码以方便回滚
主页大体修改
footer.pug
部分(路径: anzhiyu\layout\includes\footer.pug
)
备案组
(相关文字添加gbtip
可以参考后续关于仿Heo页脚添加备案组与页脚站点状态检测
这篇文章,目前先占位
1
| a.footer-bar-link.cc(href=url_for(theme.footer.footerBar.cc.link) title="cc协议" gbtip="网站采用 署名-非商业性使用-禁止演绎 4.0 国际 标准")
|
1
| a.random-friends-btn#footer-random-friends-btn(href="javascript:addFriendLinksInFooter();" title="换一批友情链接" gbtip="换一批友情链接")
|
站点头像
(相关内容可以参考后续关于仿Solitude页脚站点名附带头像
,目前先占位
1
| a.footer-bar-link(href=url_for(authorLink) target="_blank" gbtip="前往我的主页")
|
其中两处相同的均需要修改
1
| img.footer_mini_logo(title="返回顶部", alt="返回顶部" gbtip="返回顶部" onclick="anzhiyu.scrollToDest(0, 500)", src=centerImg, size="50px")
|
1 2 3 4 5 6
| a.footer-bar-link.badge( href=theme.footer.footerBar.badge.link title=theme.footer.footerBar.badge.title + gbtip="加入无聊湾吧🥱" target="_blank" style="margin-left:8px"
|
1 2
| a.github-badge(target='_blank' href=item.link style='margin-inline:5px' data-title=item.message title=item.message gbtip=item.message)
|
- 变量名
#footer_deal
(迷你logo旁边的社交媒体
1
| a.deal_link(href=url_for(item.link) title=item.title gbtip=item.title)
|
本步也有两处相同的内容需要一起修改
top.pug
部分(路径:anzhiyu\layout\includes\top\top.pug
)
1 2 3 4
| .banner-button-group .banner-button(gbtip="查看更多推荐文章" onclick='event.stopPropagation();event.preventDefault();anzhiyu.hideTodayCard();') i.anzhiyufont.anzhiyu-icon-arrow-circle-right span.banner-button-text 更多推荐
|
nav.pug
部分(路径anzhiyu\layout\includes\header\nav.pug
)
1
| label.widget(for="center-console" title=_p("中控台") gbtip="显示中控台" onclick="anzhiyu.switchConsole();")
|
1
| a.site-page.social-icon.search(href='javascript:void(0);', title='搜索🔍' gbtip="本站搜索🔍" accesskey="s")
|
1 2
| a.totopbtn(href='javascript:void(0);' gbtip="返回顶部⬆️")
|
1
| a.site-page(onclick='toRandomPost()', title='随机前往一个文章', gbtip="随机前往一个文章" href='javascript:void(0);')
|
1
| a#site-name(href=url_for('/') gbtip="返回博客主页" accesskey="h")
|
social.pug
部分(路径:anzhiyu\layout\includes\header\social.pug
)
1
| a.social-icon.faa-parent.animated-hover(href=url_for(trim(value.split('||')[0])) target="_blank" title=title === undefined ? '' : trim(title) gbtip=title)
|
bbTimeList.pug
部分(路径: anzhiyu\layout\includes\bbTimeList.pug
)
1 2 3
| i.anzhiyufont.anzhiyu-icon-jike.bber-logo.fontbold(onclick=onclick_value, title="即刻短文" gbtip="即刻短文", href=href_value, aria-hidden="true") ----- a.bber-gotobb.anzhiyufont.anzhiyu-icon-circle-arrow-right( onclick=onclick_value, href=href_value, title="查看全文" gbtip="查看全文")
|
categoryGroup.pug
部分(路径: anzhiyu\layout\includes\categoryGroup.pug
)
此处内容有进行大幅度修改,填补了分类条部分的空缺位置(主要我很少给分类
完成此部分的修改会有几处BUG:
具体大致是由于修改了.catalog-list-item
的内容作为了固定项
,导致与anzhiyu主题自带的category.pug
布局有冲突,因为此处的后续我有对分类条进行修改布局,所以如果你有兴趣,可以修改完以下的内容,点击跳转至拓展-首页分类条的布局修改(占位)进行下一步的修改以完善分类条的布局
你可以直接替换(categoryGroup.pug
)
1 2 3 4 5 6 7 8 9 10 11 12
| #categoryBar #category-bar.category-bar #catalog-bar #catalog-list .catalog-list-item(id='首页') a(href="/" gbtip="查看所有精选文章") 精选 .catalog-list-item(id='隧道') a(href="/archives/" gbtip="查看所有文章") 全部文章 !=catalog_list("categories") .category-bar-next#category-bar-next(onclick="anzhiyu.scrollCategoryBarToRight()" gbtip="分类条翻页") i.anzhiyufont.anzhiyu-icon-angle-double-right a.catalog-more(href="/categories/" gbtip="查看所有分类")!= '更多'
|
补充剩余没有添加tooltip
的部分
路径anzhiyu\scripts\helpers\catalog_list.js
1 2 3 4 5 6 7 8 9 10 11 12 13
| hexo.extend.helper.register("catalog_list", function (type) { let html = ``; hexo.locals.get(type).map(function (item) { html += ` <div class="catalog-list-item" id="/${item.path}"> <a href="/${item.path}" gbtip="前往 ${item.name} 分类的文章"> ${item.name} </a> </div> `; }); return html; });
|
修改完以上内容,至此主页部分结束,以下内容为文章页修改
文章页大体修改
post-info.pug
部分(路径: anzhiyu\layout\includes\header\post-info.pug
)
此处内容有进行大幅度修改,为了对应拓展信息框的修改,故将部分文字删去,显得简洁且不多余
1
| span.post-meta-position(title="作者IP属地为" + location gbtip="作者IP属地为" + location)
|
1 2 3 4 5
| span.post-meta-wordcount(gbtip="这篇文章有" + wordcount(page.content) + "字") if theme.wordcount.post_wordcount i.anzhiyufont.anzhiyu-icon-file-word.post-meta-icon span.word-count= wordcount(page.content) if theme.wordcount.min2read
|
1 2 3 4
| span.post-meta-readtime(gbtip="这篇文章预计需要" + min2read(page.content,{cn: 350, en: 160}) + _p('post.min2read_unit') + "来阅读") if theme.wordcount.min2read i.anzhiyufont.anzhiyu-icon-clock.post-meta-icon span=min2read(page.content,{cn: 350, en: 160}) + _p('post.min2read_unit')
|
阅读量
(我将此处修改为热度,毕竟小博客阅读量少显得太寒碜了
1 2 3 4 5 6 7
| mixin pvBlock(parent_id,parent_class,parent_title) span.post-meta-separator span(class=parent_class id=parent_id data-flag-title=page.title gbtip="热度") i.anzhiyufont.anzhiyu-icon-fire.post-meta-icon span.post-meta-label if block block
|
下方的Waline
,Twikoo
,Artalk
的title
也需要对应修改为热度
1 2 3 4 5 6
| mixin countBlock span.post-meta-separator span.post-meta-commentcount(gbtip="评论数") i.anzhiyufont.anzhiyu-icon-comments.post-meta-icon if block block
|
文章创建时间
与更新时间
(此处有大改,可自行对比源码)
主要进行了拆分变量,原创建时间
与更新时间
是同一个变量.post-meta-date
,我在此进行了拆分,并添加了新变量.post-meta-update
对应更新时间
1 2 3 4 5 6 7 8 9 10 11
| if (theme.post_meta.post.date_type) if (theme.post_meta.post.date_type === 'both') span.post-meta-date(gbtip="本篇文章" + _p('post.created') + date(page.date)) i.anzhiyufont.anzhiyu-icon-calendar-days.post-meta-icon span.post-meta-label= _p('post.created') time.post-meta-date-created(itemprop="dateCreated datePublished" datetime=date_xml(page.date) title=_p('post.created') + ' ' + full_date(page.date))=date(page.date, config.date_format) span.post-meta-separator span.post-meta-update(gbtip="本篇文章" + _p('post.updated') + date(page.updated)) i.anzhiyufont.anzhiyu-icon-history.post-meta-icon span.post-meta-label= _p('post.updated') time.post-meta-date-updated(itemprop="dateCreated datePublished" datetime=date_xml(page.updated) title=_p('post.updated') + ' ' + full_date(page.updated))=date(page.updated, config.date_format)
|
此处有进行原创与转载判定的修改,具体可以参考本站的anzhiyu 主题文章板块中关于原创与判定的实现逻辑问题,此处是对于当前修改的补充修改,未修改的请自行参考修改和源码几乎一模一样)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| if page.copyright === true a.post-meta-original(href="/reprint/" gbtip="该文章为转载或翻译文章,版权归原作者所有") 转载或翻译 else a.post-meta-original(href="/copyright/" gbtip="该文章为原创文章,注意版权协议") 原创 if (theme.post_meta.post.categories && page.categories && page.categories.data.length > 0) span.post-meta-categories if (theme.post_meta.post.date_type) span.post-meta-separator
each item, index in page.categories.data i.anzhiyufont.anzhiyu-icon-inbox.post-meta-icon a(href=url_for(item.path) itemprop="url" gbtip="查看更多 " + item.name + " 分类的文章").post-meta-categories #[=item.name] if (index < page.categories.data.length - 1) i.anzhiyufont.anzhiyu-icon-angle-right.post-meta-separator if (theme.post_meta.page.tags) span.article-meta.tags each item, index in page.tags.data a(href=url_for(item.path) tabindex="-1" itemprop="url" gbtip="查看更多 " + item.name + " 标签的文章").article-meta__tags span i.anzhiyufont.anzhiyu-icon-hashtag =item.name
|
为了协同修改,可以将链接修改的后续部分(anzhiyu\layout\includes\post\post-copyright.pug
)一起修改,可以参考以下内容
post-copyright.pug
部分(anzhiyu\layout\includes\post\post-copyright.pug
)
1 2 3 4
| if page.copyright a.post-copyright__reprint(title="该文章为转载文章,注意版权协议" gbtip="该文章为转载或翻译文章,版权归原作者所有,点击跳转原文" href=url_for(url)) 转载或翻译 else a.post-copyright__original(title="该文章为原创文章,注意版权协议" gbtip="该文章为原创文章,注意版权协议,点击跳转版权协议" href="/copyright/") 原创
|
1 2 3
| a.post-copyright__author_img(href=url_for(copyright_author_link) title='关于博主' gbtip="关于博主") img.post-copyright__author_img_back(src=url_for(copyright_author_img_back) title='关于博主' alt='头像') img.post-copyright__author_img_front(src=url_for(copyright_author_img_front) title="关于博主" alt='头像')
|
页面评论
部分(路径: anzhiyu\layout\includes\third-party\comments\index.pug
)
1 2 3
| .comment-randomInfo a(gbtip="匿名身份评论将无法收到回复" onclick="anzhiyu.addRandomCommentInfo()" href="javascript:void(0)" style=theme.visitorMail.enable ? "" : "display: none") 匿名评论 a(gbtip="查看本站的隐私政策" href=url_for('/privacy') style="margin-left: 4px") 隐私政策
|
根据以上的修改,大体上你就可以实现基本的样式了,大体上只要你找出元素,就可以添加,和添加标题的逻辑是相同的。
(好像不知不觉挖了好多新坑