这篇博客记载了我的个人博客的搭建过程。
准备
首先需要安装git
和node.js
。
建站
使用如下命令建站:
进入项目所在的文件夹,使用以下命令安装所需依赖:
使用命令npx hexo s
预览效果。
使用butterfly主题
安装butterfly主题
以下内容详见butterfly官网
首先在博客的根目录里面克隆butterfly,命令如下:
1 git clone -b master https://github.com/jerryc127/hexo-theme-butterfly .git themes/butterfly
在hexo根目录下的_config.yml
文件中找到theme
,并将其修改为butterfly。
安装pug和stylus插件:
1 npm install hexo-renderer-pug hexo-renderer-stylus --save
在博客项目的根目录下新建文件_config.butterfly.yml
,然后将themes/butterfly/_config.yml
文件中的内容拷贝进去。
增添标签、分类等页面
首先新建一个页面:
在source/tags/index.md
中,添加一条type: 'tags'
。
1 2 3 4 5 --- title: 標簽 date: 2022-10-28 19:53:39 type: 'tags' ---
使用同样的方式添加分类和友情链接页面,只需要将tags
改为categories
和link
。
使用普通页面作为图库页面。
修改error_404
相关配置,添加404效果。
1 2 3 4 error_404: enable: true subtitle: '你仿佛来到了没有知识的荒原。' background: 'https://i.loli.net/2020/05/19/aKOcLiyPl2JQdFD.png'
配置语言、导航等
在_config.yml
文件中:
1 2 3 4 5 6 7 title: xxx subtitle: '个人博客' description: '靡不有初, 鲜克有终' keywords: author: xxx language: zh-CN timezone: 'Asia/Shanghai'
在_config.butterfly.yml
中:
1 2 3 4 5 6 7 8 9 menu: 首页: / || fas fa-home 归档: /archives/ || fas fa-archive 标签: /tags/ || fas fa-tags 分类: /categories/ || fas fa-folder-open 图库: /gallery/ || fa fa-image 书籍: /book/ || fa fa-book 友情链接: /link/ || fas fa-link 关于: /about/ || fas fa-heart
代码自动换行配置。
在_config.butterfly.yml
中配置code_word_wrap
为true并且在_config.yml
中配置prismjs
下的line_number
为false。
代码高度限制,在_config.butterfly.yml
中配置highlight_height_limit
为300 。
配置社交图标
1 2 3 4 social: fab fa-github: https://github.com/xxxxx || Github fa-brands fa-zhihu : https://zhihu.com || 知乎 fa-brands fa-bilibili: https://bilibili.com || bilibili
头像和网站图标等设置略。
配置顶部图像和文章封面
index_img
: 首页的顶部图。
default_top_img
: 缺省的顶部图。
archive_img
: 归档页面的顶部图。
tag_img
: 标签页面的顶部图。
category_img
: 分类页面的顶部图。
配置cover
下面的default_cover
,添加所有想要的图片。
配置footer-bg
为footer的背景图片地址。
并配置footer
下面的custom_text
为footer的文字内容。
配置右下角按钮
配置translate
,将enable
配置为true。
配置访问人数
将busuanzi
下面的选项都配置为true。
配置评论
首先配置comments
下面的use
为gitalk
。
接下来配置gitalk
1 2 3 4 5 6 7 8 gitalk: enable: true client_id: xxxxxxx client_secret: xxxxxxxxx repo: xxxxxxxx owner: xxxxxx admin: xxxxxxx option:
配置标题字体
首先添加字体,在themes/butterfly/source/css
文件夹下新家一个font.css
文件,添加需要的字体。
1 2 3 4 5 @font-face { font-family : '字体名称' ; font-display : swap; src : url ('字体路径' ); }
然后在inject
下面配置css,
1 2 3 inject: head: - <link rel="stylesheet" href="/css/font.css">
然后配置字体
1 2 3 blog_title_font: font_link: font-family: 方正行楷繁体, 方正行楷简体, 华文行楷, FZXKB, FZXKJW, FZYBXSJW, XingKai
配置网站副标题
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 subtitle: enable: true effect: true startDelay: 300 typeSpeed: 150 backSpeed: 50 loop: true source: false sub: - 綠樹聽鵜鴂,更那堪、鷓鴣聲住,杜鵑聲切。 - 啼到春歸無尋處,苦恨芳菲都歇。 - 算未抵、人間離別。 - 馬上琵琶關塞黑。更長門翠輦辭金闕。 - 看燕燕,送歸妾。 - 將軍百戰身名裂。向河梁、回頭萬裏,故人長絕。 - 易水蕭蕭西風冷,滿座衣冠似雪。 - 正壯士、悲歌未徹。 - 啼鳥還知如許恨,料不啼清淚長啼血。 - 誰共我,醉明月?
配置字数统计
1 2 3 4 5 wordcount: enable: true post_wordcount: true min2read: true total_wordcount: true
通用配置
添加脚注
1 npm install hexo-reference --save
配置codetabs
首先,在themes/butterfly/scripts/tag
目录下新建codetabs.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 'use strict' function codeTabs (args, content ) { let tab_name = args.length > 0 ? args[0 ] : 'tabs' ; const tabBlock = /<!--\s*tab (.*?)\s*-->\n([\w\W\s\S]*?)<!--\s*endtab\s*-->/g let match = tabBlock.exec (content); let id = 0 ; let tab_nav = '' ; let tab_content = '' ; while (match !== null ) { const code_cfg = parseArgs (match[1 ].trim ().split (' ' )); let code_content = renderCode (code_cfg, match[2 ]); id++; let tab_href = tab_name + '-' + id; const isActive = id === 1 ? ' active' : '' ; let lang = code_cfg.lang ; let icon = `<i class="iconfont icon-${lang} "></i>` ; tab_nav += `<li class="tab${isActive} "><button type="button" data-href="#${tab_href} ">${icon + lang} </button></li>` tab_content += `<div class="tab-item-content${isActive} " id="${tab_href} ">${code_content} </div>` match = tabBlock.exec (content); } return `<div class="tabs" id="${tab_name} "> <ul class="nav-tabs">${tab_nav} </ul> <div class="tab-contents">${tab_content} </div> </div>` } const rCaptionUrlTitle = /(\S[\S\s]*)\s+(https?:\/\/\S+)\s+(.+)/i ;const rCaptionUrl = /(\S[\S\s]*)\s+(https?:\/\/\S+)/i ;const rCaption = /\S[\S\s]*/ ;function parseArgs (args ) { const _else = []; const len = args.length ; let lang, line_number, wrap; let firstLine = 1 ; const mark = []; for (let i = 0 ; i < len; i++) { const colon = args[i].indexOf (':' ); if (colon === -1 ) { _else.push (args[i]); continue ; } const key = args[i].slice (0 , colon); const value = args[i].slice (colon + 1 ); switch (key) { case 'lang' : lang = value; break ; case 'line_number' : line_number = value === 'true' ; break ; case 'first_line' : if (!isNaN (value)) firstLine = +value; break ; case 'wrap' : wrap = value === 'true' ; break ; case 'mark' : { for (const cur of value.split (',' )) { const hyphen = cur.indexOf ('-' ); if (hyphen !== -1 ) { let a = +cur.substr (0 , hyphen); let b = +cur.substr (hyphen + 1 ); if (Number .isNaN (a) || Number .isNaN (b)) continue ; if (b < a) { const temp = a; a = b; b = temp; } for (; a <= b; a++) { mark.push (a); } } if (!isNaN (cur)) mark.push (+cur); } break ; } default : { _else.push (args[i]); } } } const arg = _else.join (' ' ); let match, caption = '' ; if ((match = arg.match (rCaptionUrlTitle)) != null ) { caption = `<span>${match[1 ]} </span><a href="${match[2 ]} ">${match[3 ]} </a>` ; } else if ((match = arg.match (rCaptionUrl)) != null ) { caption = `<span>${match[1 ]} </span><a href="${match[2 ]} ">link</a>` ; } else if ((match = arg.match (rCaption)) != null ) { caption = `<span>${match[0 ]} </span>` ; } return { lang, firstLine, caption, line_number, mark, wrap }; } const { escapeHTML } = require ('hexo-util' );let highlight, prismHighlight;function renderCode (cfg, content ) { const hljsCfg = hexo.config .highlight || {}; const prismjsCfg = hexo.config .prismjs || {}; if (!hljsCfg.enable && !prismjsCfg.enable ) { return `<pre><code>${escapeHTML(content)} </code></pre>` ; } const { lang, firstLine, caption, line_number, line_threshold, mark, wrap } = cfg; if (prismjsCfg.enable ) { const shouldUseLineNumbers = typeof line_number !== 'undefined' ? line_number : prismjsCfg.line_number ; let surpassesLineThreshold; if (typeof line_threshold !== 'undefined' ) { surpassesLineThreshold = content.split ('\n' ).length > line_threshold; } else { surpassesLineThreshold = content.split ('\n' ).length > (prismjsCfg.line_threshold || 0 ); } const prismjsOption = { lang, firstLine, caption, lineNumber : shouldUseLineNumbers && surpassesLineThreshold, mark, tab : prismjsCfg.tab_replace , isPreprocess : prismjsCfg.preprocess }; if (!prismHighlight) prismHighlight = require ('hexo-util' ).prismHighlight ; content = prismHighlight (content, prismjsOption); } else { const shouldUseLineNumbers = typeof line_number !== 'undefined' ? line_number : hljsCfg.line_number ; let surpassesLineThreshold; if (typeof line_threshold !== 'undefined' ) { surpassesLineThreshold = content.split ('\n' ).length > line_threshold; } else { surpassesLineThreshold = content.split ('\n' ).length > (hljsCfg.line_threshold || 0 ); } const hljsOption = { lang : typeof lang !== 'undefined' ? lang : '' , firstLine, caption, gutter : shouldUseLineNumbers && surpassesLineThreshold, hljs : hljsCfg.hljs , mark, tab : hljsCfg.tab_replace , autoDetect : hljsCfg.auto_detect , wrap : typeof wrap === 'boolean' ? wrap : hljsCfg.wrap }; if (!highlight) highlight = require ('hexo-util' ).highlight ; content = highlight (content, hljsOption); } content = content.replace (/{/g , '{' ).replace (/}/g , '}' ); content = content.slice (0 , 7 ) + ' style="margin: 0 0 0 " ' + content.slice (7 ); return content; } hexo.extend .tag .register ('codetabs' , codeTabs, { ends : true })
然后修改themes/butterfly/source/_tags/tabs.styl
文件,将第54行注释掉
1 2 3 4 5 > .tab-contents .tab-item-content position : relative display : none
最后,修改themes/butterfly/source/main.js
的第160行,
1 2 3 4 5 if (highlightHeightLimit && item.offsetHeight > highlightHeightLimit + 30 ) {if (highlightHeightLimit && item.offsetHeight > highlightHeightLimit + 30 || item.offsetHeight === 0 ) {