给博客顶部和底部各添加一排宠物,是一种非常酷的效果,经过多方查找,终于在安知鱼主题下通过修改主题文件,进行实现,下面来看具体的操作过程。
1.顶部挂件 主要设置页面左上角随机动物挂件
1.1代码修改 仅针对安知鱼主题,其他主题自行修改,可直接替换
1 blog/themes/anzhiyu/layout/includes/bbTimeList.pug
文件中的内容,大家注意下面的代码
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 133 134 135 136 137 138 139 140 if site.data.essay each i in site.data.essay if i.home_essay - let onclick_value = theme.pjax.enable ? `pjax.loadUrl("/essay/");` : ''; - let href_value = theme.pjax.enable ? 'javascript:void(0);' : `/essay/`; #bbTimeList.bbTimeList.container i.anzhiyufont.anzhiyu-icon-jike.bber-logo.fontbold(onclick=onclick_value, title="即刻短文", href=href_value, aria-hidden="true") #bbtalk.swiper-container.swiper-no-swiping.essay_bar_swiper_container(tabindex="-1") #bber-talk.swiper-wrapper(onclick=onclick_value) each i in site.data.essay each item, index in i.essay_list if index < 10 - var contentText = item.image ? item.content + ' [图片]' : (item.video ? item.content + ' [视频]' : item.content) a.li-style.swiper-slide(href=href_value)= contentText a.bber-gotobb.anzhiyufont.anzhiyu-icon-circle-arrow-right(onclick=onclick_value, href=href_value, title="查看全文") img.con-animals.entered.loaded(id="new-con-animals" src="") script(src=url_for(theme.home_top.swiper.swiper_js)) style. #bbTimeList { position: relative; } .con-animals { display: block; position: absolute; max-width: 260px; top: -85px; z-index: 2; } @media screen and (max-width: 1200px) { .con-animals { display: none; } } script. // 将lastImageUrl移到全局作用域 window.lastImageUrl = window.lastImageUrl || ''; function setRandomImage() { const img = document.getElementById('new-con-animals'); const imageUrls = [ "https://i1.wp.com/ruom.wuaze.com/i/2024/10/18/901216.webp", "https://i1.wp.com/ruom.wuaze.com/i/2024/10/18/074167.webp", "https://i1.wp.com/ruom.wuaze.com/i/2024/10/19/759434.webp", "https://i1.wp.com/ruom.wuaze.com/i/2024/10/19/526748.webp", "https://i1.wp.com/ruom.wuaze.com/i/2024/10/18/429029.webp" ]; let randomImage; do { randomImage = imageUrls[Math.floor(Math.random() * imageUrls.length)]; } while (randomImage === window.lastImageUrl); window.lastImageUrl = randomImage; if (img) { img.src = randomImage; } } function initializeDragImage() { const img = document.getElementById('new-con-animals'); const container = document.getElementById('bbTimeList'); if (!img || !container) return; if (!window.lastImageUrl) { setRandomImage(); } else { img.src = window.lastImageUrl; } let isDragging = false, wasDragged = false, startX, startLeft; const containerWidth = container.clientWidth; const imgWidth = img.clientWidth; const maxLeft = containerWidth - imgWidth; const edgeThreshold = 20; let lastLeft = parseInt(localStorage.getItem('imgPositionLeft')) || 0; lastLeft = Math.min(maxLeft, Math.max(0, lastLeft)); img.style.left = `${lastLeft}px`; const savePosition = (left) => localStorage.setItem('imgPositionLeft', left); img.addEventListener('click', () => { if (!wasDragged) { let currentLeft = lastLeft; let newLeft; if (currentLeft <= edgeThreshold) { newLeft = Math.min(currentLeft + 200, maxLeft); } else if (currentLeft >= maxLeft - edgeThreshold) { newLeft = Math.max(currentLeft - 200, 0); } else { newLeft = currentLeft + (Math.random() < 0.5 ? -200 : 200); newLeft = Math.max(0, Math.min(newLeft, maxLeft)); } if (newLeft !== lastLeft) { lastLeft = newLeft; img.style.left = `${newLeft}px`; savePosition(newLeft); } } }); img.addEventListener('mousedown', (e) => { isDragging = true; wasDragged = false; startX = e.clientX; startLeft = lastLeft; img.style.transition = 'none'; const onMouseMove = (e) => { if (!isDragging) return; wasDragged = true; const offsetX = e.clientX - startX; lastLeft = Math.max(0, Math.min(startLeft + offsetX, maxLeft)); requestAnimationFrame(() => { img.style.left = `${lastLeft}px`; }); }; const onMouseUp = () => { isDragging = false; img.style.transition = 'left 0.5s ease-in-out'; savePosition(lastLeft); document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); }; document.addEventListener('mousemove', onMouseMove); document.addEventListener('mouseup', onMouseUp); }); } document.addEventListener('DOMContentLoaded', initializeDragImage); document.addEventListener('pjax:success', initializeDragImage);
代码修改的地方只有两处,第一处是在源文件的末尾
1 script(src=url_for(theme.home_top.swiper.swiper_js))
上面代码的上一行,也就是倒数第二行,本身就是一个空行,添加
1 img.con-animals.entered.loaded(id="new-con-animals" src="")
注意添加的这一样的缩颈,与上面的代码对齐,是如下样式
1 2 a.bber-gotobb.anzhiyufont.anzhiyu-icon-circle-arrow-right(onclick=onclick_value, href=href_value, title="查看全文") img.con-animals.entered.loaded(id="new-con-animals" src="")
pug 文件对缩进要求很高,这一点儿需要注意,然后再添加如下代码
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 style. #bbTimeList { position: relative; } .con-animals { display: block; position: absolute; max-width: 260px; top: -85px; z-index: 2; } @media screen and (max-width: 1200px) { .con-animals { display: none; } } script. // 将lastImageUrl移到全局作用域 window.lastImageUrl = window.lastImageUrl || ''; function setRandomImage() { const img = document.getElementById('new-con-animals'); const imageUrls = [ "https://i1.wp.com/ruom.wuaze.com/i/2024/10/18/901216.webp", "https://i1.wp.com/ruom.wuaze.com/i/2024/10/18/074167.webp", "https://i1.wp.com/ruom.wuaze.com/i/2024/10/19/759434.webp", "https://i1.wp.com/ruom.wuaze.com/i/2024/10/19/526748.webp", "https://i1.wp.com/ruom.wuaze.com/i/2024/10/18/429029.webp" ]; let randomImage; do { randomImage = imageUrls[Math.floor(Math.random() * imageUrls.length)]; } while (randomImage === window.lastImageUrl); window.lastImageUrl = randomImage; if (img) { img.src = randomImage; } } function initializeDragImage() { const img = document.getElementById('new-con-animals'); const container = document.getElementById('bbTimeList'); if (!img || !container) return; if (!window.lastImageUrl) { setRandomImage(); } else { img.src = window.lastImageUrl; } let isDragging = false, wasDragged = false, startX, startLeft; const containerWidth = container.clientWidth; const imgWidth = img.clientWidth; const maxLeft = containerWidth - imgWidth; const edgeThreshold = 20; let lastLeft = parseInt(localStorage.getItem('imgPositionLeft')) || 0; lastLeft = Math.min(maxLeft, Math.max(0, lastLeft)); img.style.left = `${lastLeft}px`; const savePosition = (left) => localStorage.setItem('imgPositionLeft', left); img.addEventListener('click', () => { if (!wasDragged) { let currentLeft = lastLeft; let newLeft; if (currentLeft <= edgeThreshold) { newLeft = Math.min(currentLeft + 200, maxLeft); } else if (currentLeft >= maxLeft - edgeThreshold) { newLeft = Math.max(currentLeft - 200, 0); } else { newLeft = currentLeft + (Math.random() < 0.5 ? -200 : 200); newLeft = Math.max(0, Math.min(newLeft, maxLeft)); } if (newLeft !== lastLeft) { lastLeft = newLeft; img.style.left = `${newLeft}px`; savePosition(newLeft); } } }); img.addEventListener('mousedown', (e) => { isDragging = true; wasDragged = false; startX = e.clientX; startLeft = lastLeft; img.style.transition = 'none'; const onMouseMove = (e) => { if (!isDragging) return; wasDragged = true; const offsetX = e.clientX - startX; lastLeft = Math.max(0, Math.min(startLeft + offsetX, maxLeft)); requestAnimationFrame(() => { img.style.left = `${lastLeft}px`; }); }; const onMouseUp = () => { isDragging = false; img.style.transition = 'left 0.5s ease-in-out'; savePosition(lastLeft); document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); }; document.addEventListener('mousemove', onMouseMove); document.addEventListener('mouseup', onMouseUp); }); } document.addEventListener('DOMContentLoaded', initializeDragImage); document.addEventListener('pjax:success', initializeDragImage);
1.2.两个问题 上面的代码会有两个问题,需要用下面的方法来解决
1.2.1.图片问题 上述代码保存之后,需要注意的是随机图片的设置,原文中
1 2 3 4 5 6 7 const imageUrls = [ "https://i1.wp.com/ruom.wuaze.com/i/2024/10/18/901216.webp", "https://i1.wp.com/ruom.wuaze.com/i/2024/10/18/074167.webp", "https://i1.wp.com/ruom.wuaze.com/i/2024/10/19/759434.webp", "https://i1.wp.com/ruom.wuaze.com/i/2024/10/19/526748.webp", "https://i1.wp.com/ruom.wuaze.com/i/2024/10/18/429029.webp" ];
图片代码已经失效,需要替换为自己的图片,我的建议是将替换图片放在
1 blog/themes/anzhiyu/source/img
文件夹中,这个文件夹会被 Hexo 拷贝到网站根目录。
1.2.2黑暗模式图片被遮挡 如果你发现夜间模式会被遮挡一部分可以添加下这段 css 试试,暂且不知道会不会影响其它部分
1 2 3 4 5 6 7 8 /* 小动物夜间显示优化 */ [data-theme='dark'] #page-header.nav-fixed #nav { background: var(--anzhiyu-black)!important; } [data-theme='dark'] #page-header #nav { background: 0 !important; }
将上面的代码放到
1 2 3 4 style. #bbTimeList { position: relative; }
下面就可以,不过需要调整缩进问题,修改起来问题应该不大。
1.2.3不显示问题 上述代码我只是在安知鱼主图之中进行的测试,如果你是其他主题,仅供参考。另外图片不显示,生成之后可以多刷新两次页面。我的测试只是首页显示,余下的页面貌似也不显示,不清楚问题在哪里。
1.3重新生成 需要重新生成, Hexo 三连(hexo c l && hexo g && hexo s )然后就可以看到效果。
2.页脚挂件 页脚挂件如下所示
1 2 footerBar: enable: true
存放路径为:
1 blog/themes/anzhiyu/source/js/footer-animal.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 function initFooterAnimal() { const footerBar = document.querySelector('#footer-bar'); if (!footerBar) return console.error('找不到指定元素'); const footerAnimal = document.createElement('div'); footerAnimal.id = 'footer-animal'; footerAnimal.innerHTML = ` <img class="animal entered loaded" src="https://i-blog.csdnimg.cn/img_convert/bcaf63d0b91b5d263b4e55d2e908bbdd.webp" alt="动物" /> `; footerBar.insertAdjacentElement('beforebegin', footerAnimal); const style = document.createElement('style'); style.textContent = ` #footer-animal { position: relative; } #footer-animal::before { content: ''; position: absolute; bottom: 0; width: 100%; height: 36px; background: url(https://i-blog.csdnimg.cn/img_convert/bcaf63d0b91b5d263b4e55d2e908bbdd.webp) repeat center / auto 100%; box-shadow: 0 4px 7px rgba(0,0,0,.15); } .animal { position: relative; max-width: min(974px, 100vw); margin: 0 auto; display: block; } #footer-bar { margin-top: 0 !important; } @media screen and (max-width: 1023px) { #footer-animal::before { height: 4vw; } } [data-theme=dark] #footer-animal { filter: brightness(.8); } `; document.head.appendChild(style); } document.addEventListener('DOMContentLoaded', initFooterAnimal); document.addEventListener('pjax:success', initFooterAnimal);
需要注意的一点,文件中调用的图片
1 https://i-blog.csdnimg.cn/img_convert/bcaf63d0b91b5d263b4e55d2e908bbdd.webp
不定时就会不能够访问,大家需要下载合适的图片当做背景图片,并存放在适当的文件夹中,我的建议是将图片存放在
1 blog/themes/anzhiyu/source/img
中,这个文件夹在 Hexo 博客生成过程中,里面的图片都会被拷贝到网站根目录,这样就可以直接调用。
2.3.引入自定义 js 做好上面的 JS 文件之后,在安知鱼主题的配置文件中搜索 inject ,就会找到如下代码
1 2 3 4 5 6 7 8 9 10 11 # Inject # Insert the code to head (before '</head>' tag) and the bottom (before '</body>' tag) # 插入代码到头部 </head> 之前 和 底部 </body> 之前 inject: head: # 自定义css # - <link rel="stylesheet" href="/css/custom.css" media="defer" onload="this.media='all'"> bottom: # 自定义js # - <script src="/js/xxx"></script>
在 bottom 处进行自定义 js 文件的引入工作:
1 - <script src="/js/custom/footer-animal.js" defer></script>
修改之后的代码如下
1 2 3 4 5 6 7 8 9 10 11 12 # Inject # Insert the code to head (before '</head>' tag) and the bottom (before '</body>' tag) # 插入代码到头部 </head> 之前 和 底部 </body> 之前 inject: head: # 自定义css # - <link rel="stylesheet" href="/css/custom.css" media="defer" onload="this.media='all'"> bottom: # 自定义js # - <script src="/js/xxx"></script> - <script src="/js/custom/footer-animal.js" defer></script>
3.最后总结 最后 Hexo 三连(hexo c l && hexo g && hexo s )就可以看到文章开始页面顶部的效果。