这是一项大工程。。。工程量预计 $\text{40 hours+}$
目标:创建一个主要为自己 Hexo 博客的主题 $\text{hexo-theme-MeaningLessNess}$ 并记录开发过程。
大部分的内容看起来会比较枯燥。。。不知道能不能坚持做下去
主题
在创建之前,我们需要了解一个 $\text{Hexo}$ 主题 $\text{Theme}$ 文件夹的构成。
打开默认主题 $\text{\Blog\themes\landscape}$,找到四个文件夹和一个文件:
- $\text{lanauages:}$ 语言
- $\text{layout:}$ 页面布局
- $\text{script:}$ $\text{Hexo}$ 脚本
- $\text{source: }$ 主题资源文件,包括页面样式,脚本,字体等
- $\text{_config.yml:}$ 主题配置文件(由于 $\text{\Blog}$ 目录下也有一个 $\text{_config.yml}$,为了区分我们叫主题内的为主题配置文件,主目录下叫博客配置文件)
创建主题
在 $\text{\Blog\themes}$ 目录下创建一个名为 $\text{hexo-theme-example}$ 的文件夹,将上述部分先加入到主题文件夹中。
注意,后文的主题文件夹名为 $\text{hexo-theme-MeaningLessNess}$。
记得将主题配置文件中的主题改为制作的主题。
学习
学习一下 $\text{HTML},\text{CSS},\text{JavaScript}$ 等的使用,也可以边做边学。
空白主题的基本配置
我们先来简单的布置一些主站界面。
我们在 $\text{\hexo-theme-MeaningLessNess\layout}$ 路径放入三个文件:
- $\text{post.ejs:}$ 每一篇单独文章的模板。
- $\text{post_entry.ejs:}$ 主页上文章列表中每一项的模板。
- $\text{index.ejs:}$ 是唯一必不可少的,是网站主页的模板。如果少了 $\text{index.ejs}$ 会报错。
在 $\text{\layout\index.ejs}$ 中,放入如下代码:
Home
Hello World.
运行后可以得到:
对了,这里我发现不要用记事本去编辑中文内容,可能会产生乱码,于是我采用了编程软件编辑,果然能打印中文字体了。
现在我们需要使用一个 partial()
函数包含其它文件,这样能使我们更好的组织代码。
我们在 $\text{\layout}$ 目录下建立 $\text{_partial}$ 文件夹,用于存放一些部分的布局文件,这样我们可以在 $\text{\layout\index.ejs}$ 等文件中直接使用。
在 $\text{_partial}$ 文件夹中,我们可以放置如下文件:
- $\text{header.ejs:}$ 页首文件
- $\text{footer.ejs:}$ 页脚文件
- $\text{sidebar.ejs:}$ 侧边栏文件
比如我在 $\text{\layout_partial\header.eps}$ 中写入:
Welcome.
在 $\text{\layout\index.eps}$ 中稍作修改:
WyyOIer
<%- partial('_partial/header') %>
qwq
即可看到主站界面变为:
也就是在加载 $\text{indes.ejs}$ 的 <%- partial('_partial/header') %>
时,自动将 $\text{\layout_partial\header.ejs}$ 中的内容放置在代码中,对后续操作和检查十分方便,而 partial()
函数可以传参,具体操作和效果深入修改时再说。
设计
在配置主题之前,先进行一些小小的设计,让后续的编写更有目标性。
参考了一些官网的主题。 Themes | Hexo
正式制作
文章 $(\text{post})$
目录
主要希望实现显示文章的一级标题、二级标题、三级标题所组成的目录表格,并且点击后能够自动跳转到相应位置。
由于需要用到 $\text{JavaScript}$,借鉴了一下其他人的代码,但始终无效。
检查后发现,代码中有这样一句话:
var labelList = $("#article").children();
打开浏览器的检查页面,发现了如下报错信息:
百度发现后,需要引用 $\text{JavaScript}$ 的 $\text{jQuery}$ 库,可以从网上下载,也可直接使用在线文件。
再次刷新后发现已能正常显示。
代码块
在 $\text{\source\javascript}$ 目录下创建 $\text{codeBlocks}$ 文件夹,然后创建五个 $\text{javascript}$ 文件:
- $\text{codeBlockFuction.js:}$ 代码块功能依赖
- $\text{codeLang.js: }$ 代码块语言识别
- $\text{codeCopy.js:}$ 代码块一键复制
- $\text{clipboard.min.js: }$ 代码块复制引用文件
- $\text{codeShrink.js:}$ 代码块收缩功能
$\text{codeBlockFuction.js:}$
$(function () {
$('pre').wrap('');
});
$\text{codeLang.js:}$
$(function () {
var $highlight_lang = $('');
$('pre').after($highlight_lang);
$('pre').each(function () {
var code_language = $(this).attr('class');
if (!code_language) {
return true;
};
var lang_name = code_language.replace("line-numbers", "").trim().replace("language-", "").trim();
lang_name = lang_name.slice(0, 1).toUpperCase() + lang_name.slice(1);
$(this).siblings(".code_lang").text(lang_name);
});
});
$\text{codeCopy.js:}$
$(function () {
var $copyIcon = $('');
$('.code-area').prepend($copyIcon);
new ClipboardJS('.fa-copy', {
target: function (trigger) {
return trigger.nextElementSibling;
}
});
});
$\text{clipboard.min.js:}$
! function (t, e) {
"object" == typeof exports && "object" == typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define([], e) : "object" == typeof exports ? exports.ClipboardJS = e() : t.ClipboardJS = e()
}(this, function () {
return function (n) {
var o = {};
function r(t) {
if (o[t]) return o[t].exports;
var e = o[t] = {
i: t,
l: !1,
exports: {}
};
return n[t].call(e.exports, e, e.exports, r), e.l = !0, e.exports
}
return r.m = n, r.c = o, r.d = function (t, e, n) {
r.o(t, e) || Object.defineProperty(t, e, {
enumerable: !0,
get: n
})
}, r.r = function (t) {
"undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(t, Symbol.toStringTag, {
value: "Module"
}), Object.defineProperty(t, "__esModule", {
value: !0
})
}, r.t = function (e, t) {
if (1 & t && (e = r(e)), 8 & t) return e;
if (4 & t && "object" == typeof e && e && e.__esModule) return e;
var n = Object.create(null);
if (r.r(n), Object.defineProperty(n, "default", {
enumerable: !0,
value: e
}), 2 & t && "string" != typeof e)
for (var o in e) r.d(n, o, function (t) {
return e[t]
}.bind(null, o));
return n
}, r.n = function (t) {
var e = t && t.__esModule ? function () {
return t.default
} : function () {
return t
};
return r.d(e, "a", e), e
}, r.o = function (t, e) {
return Object.prototype.hasOwnProperty.call(t, e)
}, r.p = "", r(r.s = 0)
}([function (t, e, n) {
"use strict";
var r = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (t) {
return typeof t
} : function (t) {
return t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t
},
i = function () {
function o(t, e) {
for (var n = 0; n < e.length; n++) {
var o = e[n];
o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(t, o.key, o)
}
}
return function (t, e, n) {
return e && o(t.prototype, e), n && o(t, n), t
}
}(),
a = o(n(1)),
c = o(n(3)),
u = o(n(4));
function o(t) {
return t && t.__esModule ? t : {
default: t
}
}
var l = function (t) {
function o(t, e) {
! function (t, e) {
if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function")
}(this, o);
var n = function (t, e) {
if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
return !e || "object" != typeof e && "function" != typeof e ? t : e
}(this, (o.__proto__ || Object.getPrototypeOf(o)).call(this));
return n.resolveOptions(e), n.listenClick(t), n
}
return function (t, e) {
if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e);
t.prototype = Object.create(e && e.prototype, {
constructor: {
value: t,
enumerable: !1,
writable: !0,
configurable: !0
}
}), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e)
}(o, c.default), i(o, [{
key: "resolveOptions",
value: function () {
var t = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : {};
this.action = "function" == typeof t.action ? t.action : this.defaultAction, this.target = "function" == typeof t.target ? t.target : this.defaultTarget, this.text = "function" == typeof t.text ? t.text : this.defaultText, this.container = "object" === r(t.container) ? t.container : document.body
}
}, {
key: "listenClick",
value: function (t) {
var e = this;
this.listener = (0, u.default)(t, "click", function (t) {
return e.onClick(t)
})
}
}, {
key: "onClick",
value: function (t) {
var e = t.delegateTarget || t.currentTarget;
this.clipboardAction && (this.clipboardAction = null), this.clipboardAction = new a.default({
action: this.action(e),
target: this.target(e),
text: this.text(e),
container: this.container,
trigger: e,
emitter: this
})
}
}, {
key: "defaultAction",
value: function (t) {
return s("action", t)
}
}, {
key: "defaultTarget",
value: function (t) {
var e = s("target", t);
if (e) return document.querySelector(e)
}
}, {
key: "defaultText",
value: function (t) {
return s("text", t)
}
}, {
key: "destroy",
value: function () {
this.listener.destroy(), this.clipboardAction && (this.clipboardAction.destroy(), this.clipboardAction = null)
}
}], [{
key: "isSupported",
value: function () {
var t = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : ["copy", "cut"],
e = "string" == typeof t ? [t] : t,
n = !!document.queryCommandSupported;
return e.forEach(function (t) {
n = n && !!document.queryCommandSupported(t)
}), n
}
}]), o
}();
function s(t, e) {
var n = "data-clipboard-" + t;
if (e.hasAttribute(n)) return e.getAttribute(n)
}
t.exports = l
}, function (t, e, n) {
"use strict";
var o, r = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (t) {
return typeof t
} : function (t) {
return t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t
},
i = function () {
function o(t, e) {
for (var n = 0; n < e.length; n++) {
var o = e[n];
o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(t, o.key, o)
}
}
return function (t, e, n) {
return e && o(t.prototype, e), n && o(t, n), t
}
}(),
a = n(2),
c = (o = a) && o.__esModule ? o : {
default: o
};
var u = function () {
function e(t) {
! function (t, e) {
if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function")
}(this, e), this.resolveOptions(t), this.initSelection()
}
return i(e, [{
key: "resolveOptions",
value: function () {
var t = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : {};
this.action = t.action, this.container = t.container, this.emitter = t.emitter, this.target = t.target, this.text = t.text, this.trigger = t.trigger, this.selectedText = ""
}
}, {
key: "initSelection",
value: function () {
this.text ? this.selectFake() : this.target && this.selectTarget()
}
}, {
key: "selectFake",
value: function () {
var t = this,
e = "rtl" == document.documentElement.getAttribute("dir");
this.removeFake(), this.fakeHandlerCallback = function () {
return t.removeFake()
}, this.fakeHandler = this.container.addEventListener("click", this.fakeHandlerCallback) || !0, this.fakeElem = document.createElement("textarea"), this.fakeElem.style.fontSize = "12pt", this.fakeElem.style.border = "0", this.fakeElem.style.padding = "0", this.fakeElem.style.margin = "0", this.fakeElem.style.position = "absolute", this.fakeElem.style[e ? "right" : "left"] = "-9999px";
var n = window.pageYOffset || document.documentElement.scrollTop;
this.fakeElem.style.top = n + "px", this.fakeElem.setAttribute("readonly", ""), this.fakeElem.value = this.text, this.container.appendChild(this.fakeElem), this.selectedText = (0, c.default)(this.fakeElem), this.copyText()
}
}, {
key: "removeFake",
value: function () {
this.fakeHandler && (this.container.removeEventListener("click", this.fakeHandlerCallback), this.fakeHandler = null, this.fakeHandlerCallback = null), this.fakeElem && (this.container.removeChild(this.fakeElem), this.fakeElem = null)
}
}, {
key: "selectTarget",
value: function () {
this.selectedText = (0, c.default)(this.target), this.copyText()
}
}, {
key: "copyText",
value: function () {
var e = void 0;
try {
e = document.execCommand(this.action)
} catch (t) {
e = !1
}
this.handleResult(e)
}
}, {
key: "handleResult",
value: function (t) {
this.emitter.emit(t ? "success" : "error", {
action: this.action,
text: this.selectedText,
trigger: this.trigger,
clearSelection: this.clearSelection.bind(this)
})
}
}, {
key: "clearSelection",
value: function () {
this.trigger && this.trigger.focus(), window.getSelection().removeAllRanges()
}
}, {
key: "destroy",
value: function () {
this.removeFake()
}
}, {
key: "action",
set: function () {
var t = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : "copy";
if (this._action = t, "copy" !== this._action && "cut" !== this._action) throw new Error('Invalid "action" value, use either "copy" or "cut"')
},
get: function () {
return this._action
}
}, {
key: "target",
set: function (t) {
if (void 0 !== t) {
if (!t || "object" !== (void 0 === t ? "undefined" : r(t)) || 1 !== t.nodeType) throw new Error('Invalid "target" value, use a valid Element');
if ("copy" === this.action && t.hasAttribute("disabled")) throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');
if ("cut" === this.action && (t.hasAttribute("readonly") || t.hasAttribute("disabled"))) throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes');
this._target = t
}
},
get: function () {
return this._target
}
}]), e
}();
t.exports = u
}, function (t, e) {
t.exports = function (t) {
var e;
if ("SELECT" === t.nodeName) t.focus(), e = t.value;
else if ("INPUT" === t.nodeName || "TEXTAREA" === t.nodeName) {
var n = t.hasAttribute("readonly");
n || t.setAttribute("readonly", ""), t.select(), t.setSelectionRange(0, t.value.length), n || t.removeAttribute("readonly"), e = t.value
} else {
t.hasAttribute("contenteditable") && t.focus();
var o = window.getSelection(),
r = document.createRange();
r.selectNodeContents(t), o.removeAllRanges(), o.addRange(r), e = o.toString()
}
return e
}
}, function (t, e) {
function n() {}
n.prototype = {
on: function (t, e, n) {
var o = this.e || (this.e = {});
return (o[t] || (o[t] = [])).push({
fn: e,
ctx: n
}), this
},
once: function (t, e, n) {
var o = this;
function r() {
o.off(t, r), e.apply(n, arguments)
}
return r._ = e, this.on(t, r, n)
},
emit: function (t) {
for (var e = [].slice.call(arguments, 1), n = ((this.e || (this.e = {}))[t] || []).slice(), o = 0, r = n.length; o < r; o++) n[o].fn.apply(n[o].ctx, e);
return this
},
off: function (t, e) {
var n = this.e || (this.e = {}),
o = n[t],
r = [];
if (o && e)
for (var i = 0, a = o.length; i < a; i++) o[i].fn !== e && o[i].fn._ !== e && r.push(o[i]);
return r.length ? n[t] = r : delete n[t], this
}
}, t.exports = n
}, function (t, e, n) {
var d = n(5),
h = n(6);
t.exports = function (t, e, n) {
if (!t && !e && !n) throw new Error("Missing required arguments");
if (!d.string(e)) throw new TypeError("Second argument must be a String");
if (!d.fn(n)) throw new TypeError("Third argument must be a Function");
if (d.node(t)) return s = e, f = n, (l = t).addEventListener(s, f), {
destroy: function () {
l.removeEventListener(s, f)
}
};
if (d.nodeList(t)) return a = t, c = e, u = n, Array.prototype.forEach.call(a, function (t) {
t.addEventListener(c, u)
}), {
destroy: function () {
Array.prototype.forEach.call(a, function (t) {
t.removeEventListener(c, u)
})
}
};
if (d.string(t)) return o = t, r = e, i = n, h(document.body, o, r, i);
throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList");
var o, r, i, a, c, u, l, s, f
}
}, function (t, n) {
n.node = function (t) {
return void 0 !== t && t instanceof HTMLElement && 1 === t.nodeType
}, n.nodeList = function (t) {
var e = Object.prototype.toString.call(t);
return void 0 !== t && ("[object NodeList]" === e || "[object HTMLCollection]" === e) && "length" in t && (0 === t.length || n.node(t[0]))
}, n.string = function (t) {
return "string" == typeof t || t instanceof String
}, n.fn = function (t) {
return "[object Function]" === Object.prototype.toString.call(t)
}
}, function (t, e, n) {
var a = n(7);
function i(t, e, n, o, r) {
var i = function (e, n, t, o) {
return function (t) {
t.delegateTarget = a(t.target, n), t.delegateTarget && o.call(e, t)
}
}.apply(this, arguments);
return t.addEventListener(n, i, r), {
destroy: function () {
t.removeEventListener(n, i, r)
}
}
}
t.exports = function (t, e, n, o, r) {
return "function" == typeof t.addEventListener ? i.apply(null, arguments) : "function" == typeof n ? i.bind(null, document).apply(null, arguments) : ("string" == typeof t && (t = document.querySelectorAll(t)), Array.prototype.map.call(t, function (t) {
return i(t, e, n, o, r)
}))
}
}, function (t, e) {
if ("undefined" != typeof Element && !Element.prototype.matches) {
var n = Element.prototype;
n.matches = n.matchesSelector || n.mozMatchesSelector || n.msMatchesSelector || n.oMatchesSelector || n.webkitMatchesSelector
}
t.exports = function (t, e) {
for (; t && 9 !== t.nodeType;) {
if ("function" == typeof t.matches && t.matches(e)) return t;
t = t.parentNode
}
}
}])
});
$\text{codeShrink.js:}$
$(function () {
var $code_expand = $('');
$('.code-area').prepend($code_expand);
$('.code-expand').on('click', function () {
if ($(this).parent().hasClass('code-closed')) {
$(this).siblings('pre').find('code').show();
$(this).parent().removeClass('code-closed');
} else {
$(this).siblings('pre').find('code').hide();
$(this).parent().addClass('code-closed');
}
});
});
然后在 $\text{\css\main.css}$ 中,加入代码:
code {
padding: 1px 5px;
font-family: Inconsolata, Monaco, Consolas, 'Courier New', Courier, monospace;
/* font-size: 0.91rem; */
color: #e96900;
background-color: #f8f8f8;
border-radius: 2px;
}
pre code {
padding: 0;
color: #e8eaf6;
background-color: #272822;
}
pre[class*="language-"] {
padding: 1.2em;
margin: .5em 0;
}
code[class*="language-"],
pre[class*="language-"] {
color: #e8eaf6;
white-space: pre-wrap !important;
} */
.line-numbers-rows {
border-right-width: 0px !important;
}
.line-numbers {
padding: 1.5rem 1.5rem 1.5rem 3.2rem !important;
margin: 1rem 0 !important;
background: #272822;
overflow: auto;
border-radius: 0.35rem;
tab-size: 4;
}
pre {
padding: 1.5rem !important;
margin: 1rem 0 !important;
background: #272822;
overflow: auto;
border-radius: 0.35rem;
tab-size: 4;
}
pre::before {
content: "";
height: 16px;
margin-bottom: 0;
display: block;
}
pre::after {
content: " ";
position: absolute;
border-radius: 50%;
background: #ff5f56;
width: 12px;
height: 12px;
top: 0;
left: 12px;
margin-top: 12px;
-webkit-box-shadow: 20px 0 #ffbd2e, 40px 0 #27c93f;
box-shadow: 20px 0 #ffbd2e, 40px 0 #27c93f;
}
code {
padding: 1px 5px;
font-family: Inconsolata, Monaco, Consolas, 'Courier New', Courier, monospace;
font-size: 0.91rem;
color: #e96900;
background-color: #f8f8f8;
border-radius: 2px;
}
.code_copy {
position: absolute;
top: 0.7rem;
right: 35px;
z-index: 1;
filter: invert(50%);
cursor: pointer;
}
.code_lang {
position: absolute;
top: 1.2rem;
right: 60px;
line-height: 0;
font-weight: bold;
font-family: normal;
z-index: 1;
filter: invert(50%);
cursor: pointer;
}
.code-expand {
position: absolute;
top: 4px;
right: 0px;
filter: invert(50%);
padding: 7px 10px;
z-index: 1;
cursor: pointer;
transition: all .3s;
transform: rotate(0deg);
}
.code-closed .code-expand {
transform: rotate(-180deg) !important;
transition: all .3s;
}
.code-closed pre::before {
height: 0px;
}
pre code {
padding: 0;
color: #e8eaf6;
background-color: #272822;
}
pre[class*="language-"] {
padding: 1.2em;
margin: .5em 0;
}
code[class*="language-"],
pre[class*="language-"] {
color: #e8eaf6;
white-space: pre-wrap !important;
}
最后在 $\text{post.ejs}$ 中加入:
众所周知,复制了别人大量的代码一定会出问题。 hexo s
后,代码块不能正常显示。
经过一番胡乱百度,发现需要在博客配置文件修改:
highlight:
enable: true
line_number: true
auto_detect: false
tab_replace: ''
wrap: true
hljs: false
prismjs:
enable: false
preprocess: true
line_number: true
tab_replace: ''
highlight:
enable: false
line_number: true
auto_detect: false
tab_replace: ''
wrap: true
hljs: false
prismjs:
enable: true
preprocess: false
line_number: true
tab_replace: ''
然后就成功了吗?并没有。
还是没有代码高亮。
查阅了相关资料,去代码高亮官网下载文件后,放入至 $\text{\source}$ 路径中并按提示在 $\text{post.ejs}$ 引用:
可以看到代码块终于有高亮显示,但不知道为什么 html
语言还是没有高亮。
最后在 $\text{\css\main.css}$ 中,作如下修改:
pre {
max-height: 500px; /* update */
padding: 1.5rem !important;
margin: 1rem 0 !important;
background: #272822;
overflow: auto;
border-radius: 0.35rem;
tab-size: 4;
}
这样的目的是限制代码块的高度不要超过 500 px
,防止占用过长的页面。
链接
在每个链接后添加 fa fa-link
图标,如: link
我们可以使用 ::after
伪元素为某个元素添加类似后缀的东西,注意 content
中不能插入图片,于是去 $\text{font-awesome.css}$ 中找到了 fa fa-link
的图标,用 \f08e
表示,故在 $\text{main.css}$ 放入如下代码:
#article a::after {
content: ' \f08e ';
font-family: FontAwesome;
}
然后发现,不仅正常的链接被显示,所有的大标题前也都有链接,这是因为在添加标题标签时自动补充的链接。
我们发现每个小标题都有一个叫 headerlink
的 class
,所以在 $\text{main.css}$ 中补充:
#article a.headerlink::after {
content: '';
}
这样即可让小标题前不显示链接标记。
图片
因为图片有时不易被发现,所以希望实现在每个图片下都有一个 fa fa-image
加图片名称的显示。
这次自己实现了一个 $\text{JavaScript}$。
var labelList = $("#article").children(), imgList = [];
console.log('labellength: ' + labelList.length);
var res = 0;
function dfs(ulist) {
for(var i = 0;i < ulist.length;i++) {
console.log(ulist[i]);
if($(ulist[i]).is("img")) {
imgList.push({node: $(ulist[i]), alt: ulist[i].alt});
}
var vlist = ulist[i].children;
if(vlist.length != 0) {
dfs(vlist);
}
}
}
dfs(labelList);
imgList.forEach(function (image) {
image.node.after('' + image.alt + '
');
});
console.log('res: ' + res);
学过算法的应该能理解吧,这里主要说几个内置函数:
$(name).is("elementname")
:可以理解为判断某个html
语言是否为这个元素。name.node.after(html)
:在某个元素后插入一段html
语言。console.log(...)
:将一些东西输出到F12
的控制台。
也不知道能不能这么说,完全是自己的理解。
这样我们就能实现图片后添加图片名称,但前提是你需要在写文章引用图片时,保留图片名。
其它
还有一些零零碎碎的细节,不作过多介绍,请参见 main.css 的 $\text{post.ejs}$ 部分。
$\text{More Tips}$
$\text{Font Awesome}$
Font Awesome 字体为您提供可缩放矢量图标,它可以被定制大小、颜色、阴影以及任何可以用CSS的样式。
使用方法:
在Font Awesome 中文网 – | 字体图标中下载文件,解压出文件夹,拷出当中的 $\text{css}$ 和 $\text{font}$ 文件夹,然后放在主题文件夹中的某个位置。
$\text{Hexo}$ 部署至 $\text{github}$
通过
hexo g -d
指令部署,即可将本地文件上传至 $\text{github}$ 仓库。在传取少量主题个性图片时,可以将图片放在 $\text{\hexo-theme-MeaningLessNess\source\images}$ 中,部署后可以通过 $\text{url/images/name.*}$ 访问。如将我的博客网站图标以 $\text{favicon.ico}$ 存在上述路径中,则访问时可以通过 https://wyy-oier.github.io/images/favicon.ico 访问。Hexo g
指令生成缺少 $\text{index.html}$ 等主要文件生成文件或者部署到本地时,不包含 $\text{index.html}$ 文件,导致了博客无法正常加载。
解决方案:我采用了暴力方法,直接
hexo init
。重新hexo g
和hexo d
,果然就有相应的文件了。再把主题复制回去,即可修复成功。