注:以下将以./代替Hexo根目录。

确认Hexo设置

确认渲染插件

打开./package.json文件,确认当前安装并启用的渲染插件是hexo-renderer-marked

1
2
3
4
5
6
7
8
9
{
// ...
"dependencies": {
// ...
"hexo-renderer-marked": "^x.x.x",
// ...
},
// ...
}

确认网站设置

打开./_config.yml文件,修改或确认以下设置:

1
2
3
4
5
post_asset_folder: true
relative_link: false
marked:
prependRoot: true
postAsset: true

设置详解:

  • post_asset_folder: true
    执行hexo new post xxx时,会同时生成./source/_posts/xxx.md文件和./source/_posts/xxx目录,可以将该文章相关联的资源放置在该资源目录中。
  • relative_link: false
    不要将链接改为与根目录的相对地址。此为默认配置。
  • prependRoot: true
    将文章根路径添加到文章内的链接之前。此为默认配置。
  • postAsset: true
    post_asset_folder设置为true的情况下,在根据prependRoot的设置在所有链接开头添加文章根路径之前,先将文章内资源的路径解析为相对于资源目录的路径。

举例说明:
执行hexo new post demo后,在demo文章的资源路径下存放了a.jpgcover.jpg(用作封面),目录组织结构如下:

1
2
3
4
5
./source/_posts
├── demo.md
└── demo
├── a.jpg
└── cover.jpg

demo.md的适当位置引用这两张图片,指定图片相对路径时需要假设当前目录为./source/_posts/demo/,而不是demo.md文件本身的所在目录。

注意,这会导致本地编辑器无法正常预览图像,只能让Hexo生成的网页可以正常加载图像,此问题稍后解决;

1
2
3
4
5
6
7
---
title: 演示
cover: cover.jpg

---
## 图片
![一张示例图片](a.jpg)

现在Hexo生成的网页可以正常加载图像了。

修改渲染插件代码

目前为止,我们使用的方法还不能让本地编辑器和Hexo生成的网页同时正常显示图像。在FrontMatter部分的cover.jpg一般不需要在本地编辑器预览,这倒是没问题;但如果我们希望在本地编辑器预览文章中的图片,就最好把图片的相对路径改为demo/a.jpg

可是,hexo-renderer-marked渲染插件默认的图片相对路径根目录是./source/_posts/demo/,我们需要让这个路径向上回退一层,变成demo.md文件所在的目录,与本地编辑器预览时默认的根目录一致,这样既满足了本地编辑器的渲染需求,又能让Hexo正确加载网页中的图片。

打开./node_modules/hexo-renderer-marked/lib/renderer.js,搜索image定位到修改图片相对路径的代码,按如下方式修改代码:

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
// Prepend root to image path
image(href, title, text) {
const { hexo, options } = this;
const { relative_link } = hexo.config;
const { lazyload, figcaption, prependRoot, postPath } = options;

if (!/^(#|\/\/|http(s)?:)/.test(href) && !relative_link && prependRoot) {
if (!href.startsWith('/') && !href.startsWith('\\') && postPath) {
const PostAsset = hexo.model('PostAsset');
// findById requires forward slash

// ============================== 以下代码有改动 ==============================
const fixPostPath = join(postPath, '../');
const asset = PostAsset.findById(join(fixPostPath, href.replace(/\\/g, '/')));
// const asset = PostAsset.findById(join(postPath, href.replace(/\\/g, '/')));
// ============================== 以上代码有改动 ==============================

// asset.path is backward slash in Windows
if (asset) href = asset.path.replace(/\\/g, '/');
}
href = url_for.call(hexo, href);
}

let out = `<img src="${encodeURL(href)}"`;
if (text) out += ` alt="${text}"`;
if (title) out += ` title="${title}"`;
if (lazyload) out += ' loading="lazy"';

out += '>';
if (figcaption) {
if (text) out += `<figcaption aria-hidden="true">${text}</figcaption>`;
}
return out;
}

简单地说,这里的修改就是将文章路径postPath换成了它的上一级路径fixPostPath,更换的方法就是在postPath后面加上../

现在,切换到demo.md,保留FrontMatter中cover的图片路径,将文章中的图片路径变更为demo/a.jpg

1
2
3
4
5
6
7
---
title: 演示
cover: cover.jpg

---
## 图片
![一张示例图片](demo/a.jpg)

注意事项

./node_modules一般来说不被git追踪,而且相关插件在更新后会覆盖掉人为修改,所以这个改动一般难以跨设备同步。现阶段可以采用的办法之一便是在仓库里另外保存renderer.js,并在部署时、安装插件后,使用自动指令覆盖插件中的文件。

参考资料

一张示例图片

图片