在 Cactus 主题中启用 Fancybox 图片放大功能

起因

最近写的文档里引用的屏幕截图分辨率较高,渲染在文章段落中看不清细节,而使用的 Cactus 主题也不支持图片放大,遂想找个解锁图片缩放的方式。

解决步骤

首先查阅相关资料发现 fancybox 是一种简单通用的插件解决方案。

Fancybox is the ultimate JavaScript lightbox alternative that sets the standard for premium user experience in multimedia display. Supports images, videos, maps, inline content, iframes and any other HTML content.

然后找到这篇博客详细记录了集成 fancybox 到 cactus 的方式,使用过程中发现点小问题,这里简单记录下。

Step 1 - 在主题目录 /themes/cactus/layout/_partial/head.ejs 中引入 css 文件

1
2
3
<% if (theme.fancybox.enabled) {%>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui@4.0/dist/fancybox.css" />
<% } %>

Step 2 - 在同级目录的 script.ejs 中引入 js 文件

1
2
3
4
5
6
7
<!-- FancyBox -->
<% if (theme.fancybox.enabled) {%>
<script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui@4.0/dist/fancybox.umd.js"></script>
<script>
Fancybox.defaults.hideScrollbar = false;
</script>
<% } %>

这里和原文的区别在于保留了外部的滚动条,可以解决图片放大缩小切换时页面布局变化导致错位的问题,参考 https://fancyapps.com/fancybox/layout-shift/

Step 3 - 在主题配置中加入 fancybox 开关

1
2
3
# Enable FancyBox
fancybox:
enabled: true

Step 4 - 添加脚本替换图片标签

原文的实现方式是修改 node_modules 中 markdown 渲染插件的 js,但是这样部署到 clouldflare 上后会重新 npm run build,无法生效。所以我们使用官方的添加自定义脚本方式实现。

首先在 hexo 的根目录添加 /scripts 目录,然后在里面新建一个 js 脚本用于替换图片标签。

更新:之前使用的 marked:renderer 过滤器仅适用于 hexo-renderer-marked,如果切换到 hexo-renderer-markdown-it 等其他渲染器会导致该过滤器不生效,图片放大功能失效。现改用 after_post_render 过滤器,在 HTML 渲染完成后对 <img> 标签进行替换,兼容任意 markdown 渲染器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
hexo.extend.filter.register('after_post_render', function(data) {
// 将img标签包裹在a标签中,并添加Fancybox属性(兼容任意 markdown 渲染器)
data.content = data.content.replace(/<img([^>]*?)src="([^"]*?)"([^>]*?)>/gi, (match, before, src, after) => {
// 如果已经被 <a> 包裹则跳过
if (data.content.indexOf(`data-fancybox`) !== -1 && data.content.indexOf(match) !== -1) {
const idx = data.content.indexOf(match);
const preceding = data.content.substring(Math.max(0, idx - 100), idx);
if (preceding.match(/<a[^>]*data-fancybox/)) {
return match;
}
}
const altMatch = (before + after).match(/alt="([^"]*)"/);
const alt = altMatch ? altMatch[1] : '';
return `<a data-fancybox="gallery" data-src="${src}" data-caption="${alt}"><img${before}src="${src}"${after}></a>`;
});
return data;
});

Step 5 - hexo clean && hexo s 后确认效果

效果参考:
bayesian-visualization-derivation