本博客主题基于 imaegoo/hexo-theme-icarus 二次修改,本文章的内容理论上支持4.x以后的官方分支以及 imaegoo 的分支,如果遇到问题请自行调整
基于原始分支的修改
添加预加载
themes/icarus/layout/common/scripts.jsx
中的 </Fragment>
前添加
1
| <script src={cdn('instant.page', '5.1.1', 'instantpage.min.js')} type="module"></script>
|
目录固定
themes/icarus/source/js/main.js
中的 if ($toc.length > 0)
后添加
1
| $toc.addClass('column-right is-sticky');
|
为了防止目录固定之后无法点击到较下方的项目,需要允许目录滚动
在 themes/icarus/include/style/widget.styl
添加
1 2 3
| #toc max-height: calc(100vh - 22px) overflow-y: scroll
|
右侧边栏吸底
此处参考 imaegoo 的左侧边栏吸底,可添加在 themes/icarus/source/js/main.js
末尾;如果右侧边栏有后加载内容(如友链、最近评论)则应加在完成该操作之后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| var columnRight = $('.column-right')[0];
function fixRightColumnTop() { if ($(window).width() < 769) { columnRight.style.top = null; } else { if (columnRight) { columnRight.style.top = $(window).height() - columnRight.scrollHeight - 10 + 'px'; } else { setTimeout(function () { columnRight = $('.column-right')[0]; fixRightColumnTop(); }, 500); } } } if (!($('#toc').length > 0)) { fixRightColumnTop(); $(window).resize(fixRightColumnTop); }
|
H标签美化
添加在 themes/icarus/source/css/default.styl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| .content > h1 padding: 0px 13px; border-left: 8px solid #ed515191 .content > h2 padding:0px 12px; border-left: 7px solid #BF51ED91 .content > h3 padding:0px 11px; border-left: 6px solid #6495ed91 .content > h4 padding:0px 10px; border-left: 5px solid #e2aa2b91 .content > h5 padding:0 19px; border-left: 4px solid #64c1c191
|
图片懒加载
安装并配置 hexo-image-lazyload
插件
1
| $ npm install hexo-lazyload-image --save
|
1 2 3 4 5 6
| lazyload: enable: true onlypost: false loadingImg: isSPA: false preloadRatio: 3
|
themes/icarus/source/js/main.js
添加代码以修复 lightGallery
兼容
1 2 3 4
| $(document).find('img[data-original]').each(function () { $(this).parent().attr("href", $(this).attr("data-original")); });
|
添加置顶文章标签
安装 hexo-generator-index-pin-top
然后为你需要置顶的文章添加 top
字段作为置顶权重
1
| npm install hexo-generator-index-pin-top --save
|
themes/icarus/layout/common/article.jsx
中 <div class="level-left">
下方添加
1
| {index && page.top ? <span class="level-item stick-top"> 置顶 </span> : null}
|
CSS 添加在 themes/icarus/source/css/default.styl
1 2 3 4 5 6 7 8 9 10 11
| .stick-top { background-color: rgba(64, 158, 255, 0.13); border: 1px solid rgba(64, 158, 255, 0.5); border-radius: 2px; color: #409eff; display: inline-block; padding: 0 0.5em; font-size: 0.75em; background-color: #f2f6fc; }
|
如果你需要黑夜模式的 CSS ,请添加在themes/icarus/source/css/night.styl
1 2 3 4 5 6 7 8 9 10
| .stick-top { border: none; border-radius: 2px; color: dark-font-color; display: inline-block; padding: 0 0.5em; font-size: 0.75em; background-color: dark-primary-color-hover; }
|
添加 Qexo 友链侧边栏
themes/icarus/include/schema/common/widgets.json
中 items.oneOf
添加
1 2 3
| { "$ref": "/widget/qexo_friends.json" }
|
themes/icarus/include/schema/widget/qexo_friends.json
1 2 3 4 5 6 7 8 9 10 11 12 13
| { "$schema": "http://json-schema.org/draft-07/schema#", "$id": "/widget/qexo_friends.json", "description": "Qexo friends links widget configurations", "type": "object", "properties": { "type": { "type": "string", "const": "qexo_friends" } }, "required": ["type"] }
|
themes/icarus/layout/widget/qexo_friends.jsx
注意此处修改 https://yoursite.com
为你的 Qexo 部署地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const { URL } = require('url'); const { Component } = require('inferno'); const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');
class QexoLinks extends Component { render() { const js = `loadSideBarFriends('qexo-sidebar-friends', 'https://yoursite.com');`; return ( <div class="card widget"> <div class="card-content"> <div class="menu"> <h3 class="menu-label">友情链接</h3> <ul class="menu-list qexo-sidebar-friends"></ul> </div> <script dangerouslySetInnerHTML={{ __html: js }}></script> <a class="link-more button is-light is-small size-small" href="/links/">查看更多</a> </div> </div> ); } }
module.exports = QexoLinks;
|
themes/icarus/source/js/sidebar-friends.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
| function loadSideBarFriends(id, url) { var uri = url + "/pub/friends/"; var loadStyle = '<div class="qexo_loading"><div class="qexo_part"><div style="display: flex; justify-content: center"><div class="qexo_loader"><div class="qexo_inner one"></div><div class="qexo_inner two"></div><div class="qexo_inner three"></div></div></div></div><p style="text-align: center; display: block">友链加载中...</p></div>'; for(let i=0;i<document.getElementsByClassName(id).length;i++){ document.getElementsByClassName(id)[i].innerHTML = loadStyle; } document.getElementsByClassName(id)[1] var ajax; try { ajax = new XMLHttpRequest(); } catch (e) { try { ajax = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { ajax = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { alert("糟糕,你的浏览器不能上传文件!"); return false; } } } ajax.open("get", uri, true); ajax.setRequestHeader("Content-Type", "text/plain"); ajax.onreadystatechange = function () { if (ajax.readyState == 4) { if (ajax.status == 200) { var res = JSON.parse(ajax.response); if (res["status"]) { var friends = res["data"]; for(let i=0;i<document.getElementsByClassName(id).length;i++){ document.getElementsByClassName(id)[i].innerHTML = '<ul class="menu-list">'; } for (let i = 0; i < friends.length; i++) { for(let j=0;j<document.getElementsByClassName(id).length;j++){ document.getElementsByClassName(id)[j].innerHTML += '<li><a class="level is-mobile is-mobile" href="'+friends[i]["url"]+'" target="_blank" rel="noopener"><span class="level-left"><span class="level-item">'+friends[i]["name"]+'</span></span><span class="level-right"><span class="level-item tag">'+friends[i]["url"].split('/')[2]+'</span></span></a></li>'; } } } else { console.log(res["data"]["msg"]); } } else { console.log("友链获取失败! 网络错误"); } } }; ajax.send(null); }
|
themes/icarus/layout/common/head.jsx
中 </head>
前添加
1
| <script src="/js/sidebar-friends.js"></script>
|
添加 Qexo 友链申请页面
创建一个页面,其中填写
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
| {% raw %} <article class="message is-info"> <div class="message-header"> 申请友链 </div> <div class="message-body"> <div class="form-ask-friend"> <div class="field"> <label class="label">名称</label> <div class="control has-icons-left"> <input class="input" type="text" placeholder="您的站点名" id="friend-name" required> <span class="icon is-small is-left"> <i class="fas fa-signature"></i> </span> </div> </div> <div class="field"> <label class="label">链接</label> <div class="control has-icons-left"> <input class="input" type="url" placeholder="您网站首页的链接" id="friend-link" required> <span class="icon is-small is-left"> <i class="fas fa-link"></i> </span> </div> <p class="help ">请确保站点可访问!</p> </div> <div class="field"> <label class="label">图标</label> <div class="control has-icons-left"> <input class="input" type="url" placeholder="您的网站图标(尽量为正圆形)" id="friend-icon" required> <span class="icon is-small is-left"> <i class="fas fa-image"></i> </span> </div> </div> <div class="field"> <label class="label">描述</label> <div class="control has-icons-left"> <input class="input" type="text" placeholder="请用一句话介绍您的站点" id="friend-des" required> <span class="icon is-small is-left"> <i class="fas fa-info"></i> </span> </div> </div> <div class="field"> <div class="control"> <label class="checkbox"> <input type="checkbox" id="friend-check"/> 我提交的不是无意义信息 </label> </div> </div> <div class="field is-grouped"> <div class="control"> <button class="button is-info" type="submit" onclick="askFriend(event)">申请友链</button> </div> </div> </div> </div> </article> <script src="https://recaptcha.net/recaptcha/api.js?render=你的reCpatchaV3密钥"></script> <script> function TestUrl(url) { var Expression=/http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/; var objExp=new RegExp(Expression); if(objExp.test(url) != true){ return false; } return true; } function askFriend (event) { let check = $("#friend-check").is(":checked"); let name = $("#friend-name").val(); let url = $("#friend-link").val(); let image = $("#friend-icon").val(); let des = $("#friend-des").val(); if(!check){ alert("请勾选\"我提交的不是无意义信息\""); return; } if(!(name&&url&&image&&des)){ alert("信息填写不完整! "); return; } if (!(TestUrl(url))){ alert("URL格式错误! 需要包含HTTP协议头! "); return; } if (!(TestUrl(image))){ alert("图片URL格式错误! 需要包含HTTP协议头! "); return; } event.target.classList.add('is-loading'); grecaptcha.ready(function() { grecaptcha.execute('你的reCpatchaV3密钥', {action: 'submit'}).then(function(token) { $.ajax({ type: 'get', cache: false, url: url, dataType: "jsonp", async: false, processData: false, complete: function (data) { if(data.status==200){ $.ajax({ type: 'POST', dataType: "json", data: { "name": name, "url": url, "image": image, "description": des, "verify": token, }, url: 'https://你的Qexo部署站点/pub/ask_friend/', success: function (data) { alert(data.msg); } });} else{ alert("URL无法连通!"); } event.target.classList.remove('is-loading'); } }); }); }); } </script> {% endraw %}
|
会自动验证站点可连通性并提交到 Qexo 后台。注意需要依照提示配置好 reCaptcha V3 和你的 Qexo 站点链接
接入 Qexo 页面访问统计
themes/icarus/source/js/statistic.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
| function loadStatistic(e) { var t = e + "/pub/statistic/"; function qexoInner(a,b) {if (document.getElementById(a)) document.getElementById(a).innerHTML = b;} function qexoFailed() { var j = ["qexo-site-uv","qexo-site-pv","qexo-page-pv"] for (var i = 0; i < j.length; i++) qexoInner(j[i],"请求失败"); } fetch(t, { referrerPolicy: "no-referrer-when-downgrade" }).then(function (res) { if (res.ok) { res.json().then(function (e) { if (e.status) { qexoInner("qexo-site-uv", e.site_uv); qexoInner("qexo-site-pv", e.site_pv); qexoInner("qexo-page-pv", e.page_pv); } else { console.log(e.error); qexoFailed() } }) } else { qexoFailed() } }, function (ex) { console.log('站点统计失败! 网络错误') qexoFailed() }); }
|
themes/icarus/layout/common/footer.jsx
你需要的位置添加
1 2
| <span id="busuanzi_container_site_uv" style="display: inline;">共<span id="qexo-site-uv"> Loading </span>个访客</span> <div dangerouslySetInnerHTML={{ __html: '<script src="/js/statistic.js"></script><script>loadStatistic("https://my.oplog.cn")</script>'}} />
|
themes/icarus/layout/common/article.jsx
中 {/* Visitor counter */}
下方三行改为
1
| {!index ? <span id={url_for(page.link || page.path)} class="level-item leancloud_visitors" data-flag-title={page.title} dangerouslySetInnerHTML={{__html: '<i class="far fa-eye"></i>' + _p('plugin.visit_count', ' <span id="qexo-page-pv"><i class="fa fa-spinner fa-spin"></i></span>')}}></span> : null}
|
添加 Qexo 说说侧边栏
themes/icarus/include/schema/common/widgets.json
中 items.oneOf
添加
1 2 3
| { "$ref": "/widget/qexo_talks.json" }
|
themes/icarus/include/schema/widget/qexo_talks.json
1 2 3 4 5 6 7 8 9 10 11 12 13
| { "$schema": "http://json-schema.org/draft-07/schema#", "$id": "/widget/qexo_talks.json", "description": "Qexo talks widget configurations", "type": "object", "properties": { "type": { "type": "string", "const": "qexo_talks" } }, "required": ["type"] }
|
themes/icarus/layout/widget/qexo_talks.jsx
注意此处修改 https://yoursite.com
为你的 Qexo 部署地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| const { URL } = require('url'); const { Component } = require('inferno'); const { cacheComponent } = require('hexo-component-inferno/lib/util/cache');
class QexoTalks extends Component { render() { const js = `loadSideBarTalks('qexo-sidebar-talks', 'https://yoursite.com', 5);`; return ( <div class="card widget"> <div class="card-content"> <div class="menu"> <h3 class="menu-label">最近说说</h3> <ul class="menu-list qexo-sidebar-talks"></ul> </div> <script dangerouslySetInnerHTML={{ __html: js }}></script> <a class="link-more button is-light is-small size-small" href="/talks/">查看更多</a> </div> </div> ); } }
module.exports = QexoTalks;
|
themes/icarus/source/js/sidebar-friends.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
| function loadSideBarTalks(id, url, limit) { var uri = url + "/pub/talks/?page=1&limit=" + limit; var loadStyle = '<div class="qexo_loading"><div class="qexo_part"><div style="display: flex; justify-content: center"><div class="qexo_loader"><div class="qexo_inner one"></div><div class="qexo_inner two"></div><div class="qexo_inner three"></div></div></div></div><p style="text-align: center; display: block">说说加载中...</p></div>'; for (let i = 0; i < document.getElementsByClassName(id).length; i++) { document.getElementsByClassName(id)[i].innerHTML = loadStyle; } document.getElementsByClassName(id)[1] var ajax; try { ajax = new XMLHttpRequest(); } catch (e) { try { ajax = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { ajax = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { alert("糟糕,你的浏览器不能上传文件!"); return false; } } } ajax.open("get", uri, true); ajax.setRequestHeader("Content-Type", "text/plain"); ajax.onreadystatechange = function () { if (ajax.readyState == 4) { if (ajax.status == 200) { var res = JSON.parse(ajax.response); if (res["status"]) { var talks = res["data"]; for (let i = 0; i < document.getElementsByClassName(id).length; i++) { document.getElementsByClassName(id)[i].innerHTML = ''; } for (let i = 0; i < talks.length; i++) { var item = talks[i]; var date = new Date(item.time * 1000); for (let j = 0; j < document.getElementsByClassName(id).length; j++) { document.getElementsByClassName(id)[j].innerHTML += '<article class="media"><div class="media-content">' + '<p class="title"><a href="#' + item.id + '">' + changeContent(item.content) + '</a></p>' + '<p class="date">' + item.tags.join() + ' / ' + date.getFullYear() + "-" + (date.getMonth() < 9 ? 0 : "") + (date.getMonth() + 1) + "-" + date.getDate() + '</p>' + '</div></article>'; } } } else { console.log(res["data"]["msg"]); } } else { console.log("友链获取失败! 网络错误"); } } }; ajax.send(null); }
function changeContent(content) { if (content === '') return content; content = content.replace(/<[^>]+>/g, ''); if (content.length > 150) { content = content.substring(0, 150) + '...'; } return content; }
|
基于 Imaegoo 分支的修改
跟随系统切换黑夜模式
themes/icarus/source/js/imaegoo/night.js
中将 isNight && applyNight(isNight);
注释并在后方添加,请注意本方案较温和,仅在首次访问或访问时进行了模式更改时生效
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var ifSysIsNight = window.matchMedia('(prefers-color-scheme: dark)'); if (isNight === null){ isNight = ifSysIsNight.matches ? true : false; applyNight(isNight); localStorage.setItem('night', isNight); } else{ isNight && applyNight(isNight); } ifSysIsNight.onchange = function (evt) { isNight = evt.matches ? true : false; applyNight(isNight); localStorage.setItem('night', isNight); }
|
最后
本篇文章修改较为仓促,可能存在疏漏,可以在评论区指出