碎碎念 这个月研究了很多关于Vllm框架的内容,感觉身体被掏空,不过好在总结出来了一些架构,下个周就要开始开发咯,将部分特性移到自己的代码上,难度个人感觉还是挺高的,看看下个周哥的指导咯,得亏是两个人干,一个人的话我不敢想我的进度会多慢……
上上个周有个朋友想要我的Note外挂标签和侧边栏的个人信息页面,但是由于工作的原因一直耽误,导致没写(其实就是周六周天懒得写,给我找了个借口而已),今天闲来无事,懒得出门,那就整理一下吧!
屋里一股臭味,找了好久没有找到原因,直到某一刻发现,原来是枕头里藏了发霉的梦,和我腐烂的理想,寻摸着床底下发现了一具尸体,原来是年少的自己。
前置信息 之前有些朋友不太理解外挂标签是什么,在评论区我简单解释了一下,不过不太详细,这里引用hexo的文档详细解释一下,也能更好的理解教程~
这部分由于比较系统化,大部分由ChatGPT整理生成,纯粹是我懒得写,反正能理解就好啦~
外挂标签 Hexo 的外挂标签是一类能在Markdown中以特殊语法插入复杂内容的扩展指令。例如 {% link url text %} 可以快速生成带标题的链接,而 {% image src alt %} 则能插入带属性的图片。相比原生Markdown,外挂标签提供了更灵活的排版能力,让主题开发者和写作者能轻松加入按钮、提示框、视频、折叠内容等更丰富的组件。
除了标签,Hexo还支持在文章中注入 Script 脚本。例如使用 {% js src %} 或直接在 Markdown 中加入 <script> 标签,可以加载外部JavaScript或运行自定义逻辑。这类脚本通常用于统计、交互组件或主题扩展,但需要注意安全性与执行顺序,确保不会影响页面正常渲染。
外挂标签会直接在pug结构渲染完毕后,插入到html结构中,也就是纯静态的部分,所以不需要担心性能问题。
当然以上的示例仅供参考啦,具体使用方式还是需要看主题是否支持~
主题结构 在Butterfly主题中,整体结构通常围绕 layout、source/css 和 source/js 三个主要目录展开。其中 layout 目录负责页面的主体框架,这里写入的是页面的 html 结构,但主题使用 pug 语法进行模板编写,所以在魔改时,我们首先需要规划整体布局,并在 pug 文件中写出需要呈现的结构。layout 是整个主题的主干,所有最终渲染到前端的结构都从这里生成。
当 pug 架构确定后,样式部分会放在 source/css 中,这里使用 stylus 编写样式。通常我们会在 stylus 中针对布局进行细化调整,包括颜色、间距、响应式等内容。由于 Butterfly 本身的 stylus 架构较为清晰,一般只需要新增或覆盖部分样式即可完成魔改。
如果魔改内容包含交互行为或动态效果,则需要在 source/js 中加入对应的脚本。主题支持直接在 html 中插入 script 标签,也可以在 source/js 中编写单独的 js 文件并通过主题配置或 layout 加载。对于依赖事件、监听、动画等操作的功能,通常推荐单独写成 js 文件,便于维护和复用。
所以在进行Butterfly魔改时,通常遵循的顺序是:先设计并实现 pug 的结构,再通过 stylus 完成风格上的精调,最后根据需求在适当位置插入或加载 js 逻辑,实现完整的功能扩展。
魔改教程 外挂标签 Note Butterfly内置了一个Note外挂标签,但是我嫌他有点丑,并且参数太多了,用起来我自己都懵逼,所以我将其简化修改,并进行了美化。
魔改可能会影响到之前已有的标签渲染,导致裂开,比如此次修改的note标签,如果之前已经使用了相关标签,请自行删除或者按照新版要求修改。
首先,通过外挂标签生成最基本的HTML结构,打开以下文件,并写入以下内容:
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 'use strict' const postNote = (args, content ) => { const types = { warning : 'fa-circle-dot' , error : 'fa-circle-xmark' , question : 'fa-circle-question' , info : 'fa-circle-check' , }; const type = args[0 ] || 'info' ; const title = args.slice (1 ).join (' ' ) || '附加信息' ; const icon = types[type] || types.info ; if (!types[type]) { console .warn (`\`${type} \` 类型未定义,已自动切换为 \`info\` 类型` ); type = 'info' ; title = '附加信息' ; icon = types.info ; } return ` <div class="note note-${type} "> <div class="note-header"> <i class="note-icon fa-regular ${icon} "></i> <span class="note-title">${title} </span> </div> <div class="note-content"> ${hexo.render.renderSync({ text: content, engine: 'markdown' })} </div> </div> ` ;}; hexo.extend .tag .register ('note' , postNote, { ends : true });
有了HTML结构,就写入CSS样式,美化该标签,原来的Note标签的样式文件在:
1 blog\themes\liushen\source\css\_tags\note.styl
打开文件,覆盖以下内容:
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 .note addBorderRadius () border var (--liushen-card-border) position : relative margin : 0 0 20px padding : 15px 15px 7px 15px background-color : var (--liushen-card-bg) transition : transform 0.3s ease &:hover transform : translateY (-3px ) &.note-warning background-image : radial-gradient (circle at 4em -25em , #f0ad4e , transparent 30em ), linear-gradient (#f0ad4e -2000% , transparent) .note-header color : #f0ad4e &.note-info background-image : radial-gradient (circle at 4em -25em , #5cb85c , transparent 30em ), linear-gradient (#5cb85c -2000% , transparent) .note-header color : #5cb85c &.note-error background-image : radial-gradient (circle at 4em -25em , #d9534f , transparent 30em ), linear-gradient (#d9534f -2000% , transparent) .note-header color : #d9534f &.note-question background-image : radial-gradient (circle at 4em -25em , #5bc0de , transparent 30em ), linear-gradient (#5bc0de -2000% , transparent) .note-header color : #5bc0de .note-header display : flex align-items : center font-weight : bold margin-bottom : 10px font-size : 1.0em i .note-icon margin-right : 10px color : inherit
这样整体结构就完成了,使用方法如下:
1 2 3 {% note warning 改前须知 %} 魔改可能会影响到之前已有的标签渲染,导致裂开,比如此次修改的`note` 标签,如果之前已经使用了相关标签,请自行删除或者按照新版要求修改。 {% endnote %}
渲染效果如上“改前须知“,往上翻翻就能看到啦,除了warning还有error,question,info,下面是样式展示:
info标签
这个是内容展示,里面可以正常使用Markdown的相关渲染格式
对应文本如下:
1 2 3 {% note info 这是标题 %} 这个是内容展示,里面可以正常使用`Markdown` 的相关渲染格式 {% endnote %}
warning标签
这个是内容展示,里面可以正常使用Markdown的相关渲染格式
对应文本如下:
1 2 3 {% note warning 这是标题 %} 这个是内容展示,里面可以正常使用`Markdown` 的相关渲染格式 {% endnote %}
question标签
这个是内容展示,里面可以正常使用Markdown的相关渲染格式
对应文本如下:
1 2 3 {% note question 这是标题 %} 这个是内容展示,里面可以正常使用`Markdown` 的相关渲染格式 {% endnote %}
error标签
这个是内容展示,里面可以正常使用Markdown的相关渲染格式
对应文本如下:
1 2 3 {% note error 这是标题 %} 这个是内容展示,里面可以正常使用`Markdown` 的相关渲染格式 {% endnote %}
Note标签就完成啦!
Chat 在很久很久以前,意外捣鼓出了一个外挂标签,就是聊天记录,如下所示:
咕咕怪 你叫什么?我想请你办个事,@¥(*@¥@……&
虽然很久没用,但是我感觉还是很实用的(薛定谔的实用属于是),其实很久很久以前好像是出了个教程,但是不在博客里面,所以了解的人不算很多,如下:
由于是全新的修改,所以需要自行创建文件:
1 2 blog\themes\liushen\scripts\tag\chat.js blog\themes\liushen\source\css\_tags\chat.styl
由于有一些图片链接可能无法使用,请自行修改成个人图床。
其中第一个chat.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 "use strict" ;const avatars = [ "https://i.p-i.vip/30/20240920-66ed9a608c2cf.png" , "https://i.p-i.vip/30/20240920-66ed9b0655cba.png" , "https://i.p-i.vip/30/20240920-66ed9b18a56ee.png" , "https://i.p-i.vip/30/20240920-66ed9b2c199bf.png" , "https://i.p-i.vip/30/20240920-66ed9b3350ed1.png" , "https://i.p-i.vip/30/20240920-66ed9b5181630.png" , ]; const userAvatarMap = new Map ();let avatarIndex = 0 ;function postChatBox (args, content ) { const title = args[0 ] ? args[0 ].trim () : "群聊的聊天记录" ; const titleHtml = title ? `<div class="chatBoxTitle"><i class="fa-solid fa-angle-left"></i><span class="chatTitleText">${title} </span><div class="chatBoxIcons"><i class="fa-solid fa-user"></i><i class="fa-solid fa-bars"></i></div></div>` : "" ; const contentHtml = `<div class="chatBox">${content} </div>` return `<div class="chatContainer">${titleHtml} ${contentHtml} </div>` ; } function postChat (args ) { if (!args || args.length === 0 ) { return "" ; } args = args.join (" " ).split ("," ); let name = args[0 ] ? args[0 ].trim () : "未知" ; let content = args[1 ] ? args[1 ].trim () : "无内容" ; let qqNumber = null ; if (name.includes ("@" )) { [name, qqNumber] = name.split ("@" ); } const isMe = name.toLowerCase () === "me" ; const chatName = isMe ? hexo.config .author : name; const chatClass = isMe ? "me" : "" ; const myAvatar = "https://p.liiiu.cn/i/2024/03/29/66061417537af.png" ; let avatarUrl; if (isMe) { avatarUrl = myAvatar; } else if (qqNumber) { avatarUrl = `https://q1.qlogo.cn/g?b=qq&nk=${qqNumber} &s=100` ; } else { if (!userAvatarMap.has (name)) { userAvatarMap.set (name, avatars[avatarIndex % avatars.length ]); avatarIndex++; } avatarUrl = userAvatarMap.get (name); } let result = "" ; result += `<div class="chatItem ${chatClass} ">` ; result += `<img class="chatAvatar no-lightbox" src="${avatarUrl} ">` ; result += `<div class="chatContentWrapper">` ; result += `<b class="chatName">${chatName} </b>` ; result += `<div class="chatContent">${content} </div>` ; result += `</div>` ; result += `</div>` ; return result; } hexo.extend .tag .register ("chat" , postChat); hexo.extend .tag .register ("chatBox" , postChatBox, { ends : true });
同样,外挂标签作用为注入html,真正的灵魂属于样式文件,在chat.styl文件中写入:
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 .chatContainer background : var (--card-bg) addBorderRadius () border : var (--liushen-card-border) overflow : hidden margin : 0 0 16px width : 100% .chatBoxTitle display : flex justify-content : flex-start background : var (--default-bg-color) padding : 10px 10px color : var (--white) display : flex align-items : center justify-content : space-between i font-size : 16px margin : 0 10px .chatTitleText flex : 1 font-size : 16px white-space : nowrap; overflow : hidden; text-overflow : ellipsis; .chatBox padding : 20px 30px box-sizing : border-box max-height : 600px overflow-y : auto +maxWidth768 () padding : 20px 10px max-height : 400px .chatItem display : flex flex-direction : row justify-content : flex-start margin : 20px 0 .chatAvatar width : 40px height : 40px border-radius : 50% !important margin : 5px 10px 0 0 !important .chatContentWrapper display : flex flex-direction : column width : calc (100% - 110px ) .chatContent background : var (--liushen-card-secondbg) border : var (--liushen-card-border) padding : 10px border-radius : 0 10px 10px 10px width : fit-content max-width : 100% word-wrap : break-word &.me flex-direction : row-reverse .chatAvatar margin : 5px 0 0 10px !important .chatContentWrapper align-items : flex-end .chatContent background : var (--liushen-card-bg) border-radius : 10px 0 10px 10px
如果不出意外,就结束啦,使用方式如下:
1 2 3 4 5 6 7 8 9 {% chatBox Akilar的糖果屋 %} {% chat 咕咕怪,搞什么跳转页面 %} {% chat 咕咕怪,你说连接不安全,你自己加上去的还不安全嘛? %} {% chat 咕咕怪,这么不自信呀 %} {% chat 咕咕怪,咕咕 %} {% chat me,呜呜呜 %} {% endchatBox %}
注意自行修改头像,我懒得写了,直接放在了代码内部硬编码。
侧边栏 由于第一个栏目我自己也忘了咋搞的了,目前懒得提取出来,所以这篇文章先介绍一下欢迎来访者和每日诗词的魔改教程,至于下面的能量榜,在前面的文章总已经单独写了一篇文章,这里就不解释啦。
欢迎来访者 按照惯例,我们先实现插入HTML结构,新建PUG文件,如下:
1 blog\themes\liushen\layout\includes\widget\card_welcome.pug
写入以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 .card-widget.card-welcome .item-headline i.fa.fa-user span 欢迎来访者! .item-content p 👋🏻我是清扬,一个 span(style="font-weight: bold; color: #3498db") 热爱编程 | 的技术爱好者,喜欢分享经验。😊 p ❓有问题欢迎提问,确保内容有意义,详情请见 a(href="https://how-to-ask.liushen.fun/" target="_blank" style="font-weight: bold; color: #2980b9") 提问的智慧 | 。如需联系我,欢迎通过 a(href="mailto:01@liushen.fun" style="font-weight: bold; color: #9b59b6") 邮箱 | 联系我!📧 #welcome-info .error-message(style="height: 200px; display: flex; justify-content: center; align-items: center;") p(style="text-align: center;") span(style="font-size: 40px;") 😥 br span(style="font-size: 16px;") 由于网络问题 br span(style="font-size: 16px;") 位置API请求错误 br span(style="font-size: 16px;") 请刷新重试呀🤗~
结构实现了,下面将该结构插入到对应的位置,可以在当前目录下的index.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 #aside-content.aside-content //- post if is_post() - const tocStyle = page.toc_style_simple - const tocStyleVal = tocStyle if showToc && tocStyleVal .sticky_layout include ./card_post_toc.pug else !=partial('includes/widget/card_author', {}, {cache: true}) !=partial('includes/widget/card_poem', {}, {cache: true}) !=partial('includes/widget/card_rewards', {}, {cache: true}) !=partial('includes/widget/card_announcement', {}, {cache: true}) !=partial('includes/widget/card_top_self', {}, {cache: true}) .sticky_layout if showToc include ./card_post_toc.pug if page.series include ./card_post_series.pug !=partial('includes/widget/card_recent_post', {}, {cache: true}) !=partial('includes/widget/card_ad', {}, {cache: true}) else //- page !=partial('includes/widget/card_author', {}, {cache: true}) + !=partial('includes/widget/card_welcome', {}, {cache: true}) !=partial('includes/widget/card_poem', {}, {cache: true}) !=partial('includes/widget/card_rewards', {}, {cache: true}) !=partial('includes/widget/card_announcement', {}, {cache: true}) !=partial('includes/widget/card_top_self', {}, {cache: true}) .sticky_layout if showToc include ./card_post_toc.pug !=partial('includes/widget/card_recent_post', {}, {cache: true}) !=partial('includes/widget/card_ad', {}, {cache: true}) !=partial('includes/widget/card_newest_comment', {}, {cache: true}) !=partial('includes/widget/card_categories', {}, {cache: true}) !=partial('includes/widget/card_tags', {}, {cache: true}) !=partial('includes/widget/card_archives', {}, {cache: true}) !=partial('includes/widget/card_webinfo', {}, {cache: true}) !=partial('includes/widget/card_bottom_self', {}, {cache: true})
插入位置可以自行继续调整,这里只是做个示范。
结构实现了,还需要实现其样式,新建以下文件:
1 blog\themes\liushen\source\css\_layout\card-welcome.styl
写入以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #aside-content .card-widget .card-welcome padding : 8px .item-headline margin : 12px 16px 0 16px .item-content margin : 0 16px 10px 16px #welcome-info text-align center background-color : var (--liushen-card-bg) border-radius : 12px padding : 16px margin : 8px .ip-address filter : blur (5px ) color : var (--default-bg-color) transition : filter 0.5s &:hover filter : none
经过渲染应该就可以看到结果了。
不过由于我们的访客卡片需要调用api,所以还需要js的配合,在任意自定义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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 function showWelcome (ipLocation ) { if (!ipLocation || !ipLocation.data ) { console .error ('ipLocation data is not available.' ); return ; } let dist = getDistance (121.476 , 31.224 , ipLocation.data .lng , ipLocation.data .lat ); let pos = ipLocation.data .country ; let ip = ipLocation.ip ; let posdesc; switch (ipLocation.data .country ) { case "日本" : posdesc = "よろしく,一起去看樱花吗" ; break ; case "美国" : posdesc = "Let us live in peace!" ; break ; case "英国" : posdesc = "想同你一起夜乘伦敦眼" ; break ; case "俄罗斯" : posdesc = "干了这瓶伏特加!" ; break ; case "法国" : posdesc = "C'est La Vie" ; break ; case "德国" : posdesc = "Die Zeit verging im Fluge." ; break ; case "澳大利亚" : posdesc = "一起去大堡礁吧!" ; break ; case "加拿大" : posdesc = "拾起一片枫叶赠予你" ; break ; case "中国" : pos = ipLocation.data .prov + " " + ipLocation.data .city + " " + ipLocation.data .district ; switch (ipLocation.data .prov ) { case "北京市" : posdesc = "北——京——欢迎你~~~" ; break ; case "天津市" : posdesc = "讲段相声吧" ; break ; case "河北省" : posdesc = "山势巍巍成壁垒,天下雄关铁马金戈由此向,无限江山" ; break ; case "山西省" : posdesc = "展开坐具长三尺,已占山河五百余" ; break ; case "内蒙古自治区" : posdesc = "天苍苍,野茫茫,风吹草低见牛羊" ; break ; case "辽宁省" : posdesc = "我想吃烤鸡架!" ; break ; case "吉林省" : posdesc = "状元阁就是东北烧烤之王" ; break ; case "黑龙江省" : posdesc = "很喜欢哈尔滨大剧院" ; break ; case "上海市" : posdesc = "众所周知,中国只有两个城市" ; break ; case "江苏省" : switch (ipLocation.data .city ) { case "南京市" : posdesc = "这是我挺想去的城市啦" ; break ; case "苏州市" : posdesc = "上有天堂,下有苏杭" ; break ; default : posdesc = "散装是必须要散装的" ; break ; } break ; case "浙江省" : switch (ipLocation.data .city ) { case "杭州市" : posdesc = "东风渐绿西湖柳,雁已还人未南归" ; break ; default : posdesc = "望海楼明照曙霞,护江堤白蹋晴沙" ; break ; } break ; case "河南省" : switch (ipLocation.data .city ) { case "郑州市" : posdesc = "豫州之域,天地之中" ; break ; case "信阳市" : posdesc = "品信阳毛尖,悟人间芳华" ; break ; case "南阳市" : posdesc = "臣本布衣,躬耕于南阳此南阳非彼南阳!" ; break ; case "驻马店市" : posdesc = "峰峰有奇石,石石挟仙气嵖岈山的花很美哦!" ; break ; case "开封市" : posdesc = "刚正不阿包青天" ; break ; case "洛阳市" : posdesc = "洛阳牡丹甲天下" ; break ; default : posdesc = "可否带我品尝河南烩面啦?" ; break ; } break ; case "安徽省" : posdesc = "蚌埠住了,芜湖起飞" ; break ; case "福建省" : posdesc = "井邑白云间,岩城远带山" ; break ; case "江西省" : posdesc = "落霞与孤鹜齐飞,秋水共长天一色" ; break ; case "山东省" : posdesc = "遥望齐州九点烟,一泓海水杯中泻" ; break ; case "湖北省" : switch (ipLocation.data .city ) { case "黄冈市" : posdesc = "红安将军县!辈出将才!" ; break ; case "武汉市" : posdesc = "你想去长江游泳嘛?" ; break ; default : posdesc = "来碗热干面~" ; break ; } break ; case "湖南省" : posdesc = "74751,长沙斯塔克" ; break ; case "广东省" : switch (ipLocation.data .city ) { case "广州市" : posdesc = "看小蛮腰,喝早茶了嘛~" ; break ; case "深圳市" : posdesc = "今天你逛商场了嘛~" ; break ; case "阳江市" : posdesc = "阳春合水!博主家乡~ 欢迎来玩~" ; break ; default : posdesc = "来两斤福建人~" ; break ; } break ; case "广西壮族自治区" : posdesc = "桂林山水甲天下" ; break ; case "海南省" : posdesc = "朝观日出逐白浪,夕看云起收霞光" ; break ; case "四川省" : posdesc = "康康川妹子" ; break ; case "贵州省" : posdesc = "茅台,学生,再塞200" ; break ; case "云南省" : posdesc = "玉龙飞舞云缠绕,万仞冰川直耸天" ; break ; case "西藏自治区" : posdesc = "躺在茫茫草原上,仰望蓝天" ; break ; case "陕西省" : posdesc = "来份臊子面加馍" ; break ; case "甘肃省" : posdesc = "羌笛何须怨杨柳,春风不度玉门关" ; break ; case "青海省" : posdesc = "牛肉干和老酸奶都好好吃" ; break ; case "宁夏回族自治区" : posdesc = "大漠孤烟直,长河落日圆" ; break ; case "新疆维吾尔自治区" : posdesc = "驼铃古道丝绸路,胡马犹闻唐汉风" ; break ; case "台湾省" : posdesc = "我在这头,大陆在那头" ; break ; case "香港特别行政区" : posdesc = "永定贼有残留地鬼嚎,迎击光非岁玉" ; break ; case "澳门特别行政区" : posdesc = "性感荷官,在线发牌" ; break ; default : posdesc = "带我去你的城市逛逛吧!" ; break ; } break ; default : posdesc = "带我去你的国家逛逛吧" ; break ; } let timeChange; let date = new Date (); if (date.getHours () >= 5 && date.getHours () < 11 ) timeChange = "<span>🌤️ 早上好,快趁机多睡点懒觉!</span>" ; else if (date.getHours () >= 11 && date.getHours () < 13 ) timeChange = "<span>☀️ 中午好,记得午休喔~</span>" ; else if (date.getHours () >= 13 && date.getHours () < 17 ) timeChange = "<span>🕞 下午好,饮茶先啦!</span>" ; else if (date.getHours () >= 17 && date.getHours () < 19 ) timeChange = "<span>🚶♂️ 下班啦!主打一个不听老板话~</span>" ; else if (date.getHours () >= 19 && date.getHours () < 24 ) timeChange = "<span>🌙 晚上好,来一起熬夜吧呜😭</span>" ; else timeChange = "夜深了,早点休息,少熬夜" ; let welcomeInfoElement = document .getElementById ("welcome-info" ); if (welcomeInfoElement) { welcomeInfoElement.innerHTML = `嗷嗷!热烈欢迎🤪!来自<br><b><span style="color: var(--default-bg-color)">${pos} </span></b><br> 的铁铁,你好呀!😝<br>${posdesc} 🍂<br>你目前距博主约 <b><span style="color: var(--default-bg-color)">${dist} </span></b> 公里!<br>你的网络IP为:<b><span class="ip-address" style="font-size: 15px;">${ip} </span></b><br>${timeChange} <br>` ; } else { console .log ("Pjax无法获取元素" ); } } function isWelcomeInfoAvailable ( ) { let welcomeInfoElement = document .getElementById ("welcome-info" ); return welcomeInfoElement !== null ; } function handlePjaxComplete (ipLocation ) { if (isWelcomeInfoAvailable ()) { showWelcome (ipLocation); } } function onLoad ( ) { fetchIpLocation ().then (ipLocation => { if (isWelcomeInfoAvailable ()) { showWelcome (ipLocation); } document .addEventListener ("pjax:complete" , () => handlePjaxComplete (ipLocation)); }); } window .onload = onLoad;
欢迎来访者卡片就实现完成啦!
今日诗词 这个比较简单,主要就是以下三个文件,当然仍然需要按照上面的welcome卡片的方法注册到index.pug中,这一步就不再细讲:
1 2 3 blog\themes\liushen\source\js\jinrishici.js blog\themes\liushen\layout\includes\widget\card_poem.pug blog\themes\liushen\source\css\_layout\card-jinrishici.styl
首先是第一个jinrishici.js文件,如下:
1 !function (e ){var n,t={},o="jinrishici-token" ;function i ( ){return document .getElementById ("jinrishici-sentence" )||0 !=document .getElementsByClassName ("jinrishici-sentence" ).length }function c ( ){t.load (function (e ){var n=document .getElementById ("jinrishici-sentence" ),t=document .getElementsByClassName ("jinrishici-sentence" );if (n&&(n.innerText =e.data .content ),0 !==t.length )for (var o=0 ;o<t.length ;o++)t[o].innerText =e.data .content })}function r (e,n ){var t=new XMLHttpRequest ;t.open ("get" ,n),t.withCredentials =!0 ,t.send (),t.onreadystatechange =function (n ){if (4 ===t.readyState ){var o=JSON .parse (t.responseText );"success" ===o.status ?e (o):console .error ("今日诗词API加载失败,错误原因:" +o.errMessage )}}}t.load =function (n ){return e.localStorage &&e.localStorage .getItem (o)?function (e,n ){return r (e,"https://v2.jinrishici.com/one.json?client=browser-sdk/1.2&X-User-Token=" +encodeURIComponent (n))}(n,e.localStorage .getItem (o)):function (n ){return r (function (t ){e.localStorage .setItem (o,t.token ),n (t)},"https://v2.jinrishici.com/one.json?client=browser-sdk/1.2" )}(n)},e.jinrishici =t,i ()?c ():(n=function ( ){i ()&&c ()},"loading" !=document .readyState ?n ():document .addEventListener ?document .addEventListener ("DOMContentLoaded" ,n):document .attachEvent ("onreadystatechange" ,function ( ){"complete" ==document .readyState &&n ()}))}(window );
下面是card_poem.pug,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #card-poem.card-widget #poem_sentence #poem_info #poem_dynasty #poem_author script(src='/js/jinrishici.js', charset='utf-8') script(type='text/javascript'). jinrishici.load(function(result) { var sentence = document.querySelector("#poem_sentence") var author = document.querySelector("#poem_author") var dynasty = document.querySelector("#poem_dynasty") var sentenceText = result.data.content sentenceText = sentenceText.substr(0, sentenceText.length - 1); sentence.innerHTML = sentenceText dynasty.innerHTML = result.data.origin.dynasty author.innerHTML = result.data.origin.author + '《' + result.data.origin.title + '》' });
注意创建了card_poem.pug文件后,自行修改目录下的index.pug实现注入。
下面是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 #card-poem display : flex flex-direction : column padding : 0.5rem !important div#poem_sentence text-align : center font-family : serif, cursive line-height : 1.4 margin-bottom : 0.5rem padding : 1rem border-radius : 8px background : var (--liushen-card-bg) min-height : 62px div#poem_info display : flex color : var (--liushen-secondtext) font-size : 0.5rem justify-content : center flex-wrap : wrap div#poem_author order : 1 padding : 2px margin-left : 8px div#poem_dynasty order : 0 padding : 2px 4px 2px 6px background : var (--liushen-button-bg) color : var (--liushen-text) border-radius : 8px
最终应该就可以实现效果啦,文章就不展示效果了,可以直接在侧边栏观看哦~
总结 魔改博客的记忆,像雾气般渐渐消散。彼时,那些灵光一现的改动,曾在我心底刻下清晰的印记。然而,随着时间的洪流向前,我迈入了繁忙的职场,那些曾经认为有趣至极的事物,便被工作中的琐碎与疑惑所取代,日益淡漠。修整博客本是一件多么令人愉悦的事情,如今却无暇顾及。周末,除了在床上虚度光阴,再无一丝活力。一想到两天后的工作,眉头便开始紧锁。或许,面部表情的转变,正是我们成长的方式吧——直到有一天,你的笑容被一丝严肃所取代,那份严肃里,带着岁月的痕迹,便意味着,你真正长大了。
后面我会尽量整理所有魔改的教程,尽量不要让自己淡忘这一部分,希望还能整理出来一些,不至于全部丢了。
门前一阵清风,吹散了积压多时的雾气,待到这一刻拂晓,方知是心底升起了崭新的月,与我未尽的诗和远方,抬眼望窗外看见一道流星,恰是醒来的灵魂。
每日一图 图片来自于哲风壁纸