让 Hexo NexT 支持 emoji 表情

将 markdown 转化为 html 的转化器叫做 markdown 渲染器。

在 Hexo 中默认的 markdown 渲染器是 hexo-renderer-marked ,这个渲染器是不支持 emoji 表情的。

在 NexT 的 issue 上有推荐使用 hexo-tag-emojis 这个插件来支持 emoji 表情,但可惜的是这个插件已经不再维护,已经不支持 Hexo v3+ 了。还好在 Hexo 的 plugins 页,我们找到了另外一个 emoji 插件 hexo-filter-github-emojis

下面我们就来实现 Hexo NexT 对 emoji 的支持。

Version

Hexo 3.3.9
NexT 5.1.2

安装

1
$ npm install hexo-filter-github-emojis --save

配置

打开 站点配置文件,添加以下内容:

1
2
3
4
5
6
githubEmojis:
enable: true
className: github-emoji
unicode: false
styles:
localEmojis:

具体的每个配置项含义可以看插件的文档

基本使用

  1. Emoji Cheat Sheet 中找到你想要的表情,然后点击即可复制。
  2. 使用方法和 GitHub 一样,比如你想发一个笑脸 😊 直接输入笑脸对应的 emoji 编码 :smile: 就可以。
  3. 默认配置下是使用图片表情,如果需要使用 Unicode 表情,可以将上面配置中的 unicode 设置为 true,就会渲染如 😄 😏 😌

兼容 Hexo NexT 处理

hexo NexT 使用 FancyBox 这个图片插件,在 themes/next/source/js/src/utils.js 中:

看红框中的代码可以知道在文章中 img 标签没有被 a 标签包含时,会加上 a 标签,所以在渲染 emoji 表情时,会被自动加上 a 标签。

这样就导致渲染错误。我们修改 themes/next/layout/_partials/head.swig

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
<script type="text/javascript" id="hexo.configurations">
var NexT = window.NexT || {};
var CONFIG = {
root: '{{ theme.root }}',
scheme: '{{ theme.scheme }}',
sidebar: {{ theme.sidebar | json_encode }},
fancybox: {{ theme.fancybox }},
tabs: {{ theme.tabs.enable }},
motion: {{ theme.use_motion }},
duoshuo: {
userId: '{{ theme.duoshuo_info.user_id | default() }}',
author: '{{ theme.duoshuo_info.admin_nickname | default(__('author'))}}'
},
algolia: {
applicationID: '{{ theme.algolia.applicationID }}',
apiKey: '{{ theme.algolia.apiKey }}',
indexName: '{{ theme.algolia.indexName }}',
hits: {{ theme.algolia_search.hits | json_encode }},
labels: {{ theme.algolia_search.labels | json_encode }}
},
{# ↓ 在这里修改,其他未动 ↓ #}
{# 添加 emojis 参数 #}
emojis: {
className: '{{ config.githubEmojis.className | default('github-emoji') }}'
}
};
</script>

修改 themes/next/source/js/src/utils.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
// 注意看 CONFIG.emojis.className 那一行,其他未动
$('.content img')
.not('[hidden]')
.not('.group-picture img, .post-gallery img, img.' + CONFIG.emojis.className)
.each(function () {
var $image = $(this);
var imageTitle = $image.attr('title');
var $imageWrapLink = $image.parent('a');

if ($imageWrapLink.size() < 1) {
var imageLink = ($image.attr('data-original')) ? this.getAttribute('data-original') : this.getAttribute('src');
$imageWrapLink = $image.wrap('<a href="' + imageLink + '"></a>').parent('a');
}

$imageWrapLink.addClass('fancybox fancybox.image');
$imageWrapLink.attr('rel', 'group');

if (imageTitle) {
$imageWrapLink.append('<p class="image-caption">' + imageTitle + '</p>');

//make sure img title tag will show correctly in fancybox
$imageWrapLink.attr('title', imageTitle);
}
});

$('.fancybox').fancybox({
helpers: {
overlay: {
locked: false
}
}
});

这样修改完就全部显示正常了。

最后一点点改进

图片 emoji 表情的高宽都是固定设定为 20,看起来太小了,所以我们需要自定义一下样式,但是自定义样式出现一个问题。

站点配置文件 中,我们配置:

1
2
3
4
5
6
githubEmojis:
enable: true
className: github-emoji
unicode: false
styles:
localEmojis:

我们看到 className 的值为 github-emoji,这个值是在渲染 emoji 图片表情时,img 标签上的 class,如:

1
<img class="github-emoji" title="smile" alt="smile" src="https://assets-cdn.github.com/images/icons/emoji/unicode/1f604.png?v7" height="20" width="20">

这个值是可以动态配置的,所以我们写样式的就必须动态的去获取 className 的值。

我们需要在 themes/next/source/css/_variables/base.styl 定义一个变量去获取 className 的值,*.styl 文件是使用 hexo-renderer-stylus 插件,这个插件只有 hexo-config 这个方法去获取 主题配置文件 中的值,但是我们的 className 是写在 站点配置文件 中,是没办法获取到的。

还好在这个 issue 有说到一个解决办法,所以我们替换 hexo-renderer-stylus 插件 :

1
2
$ npm un hexo-renderer-stylus --save
$ npm i hexo-renderer-stylus-plus --save

就可以在 themes/next/source/css/_variables/base.styl 中使用 hexo-site-config 方法获取 站点配置文件 中的值,我们添加:

1
2
3
4
5
6
7
8
9
// Github emojis class name
// --------------------------------------------------

get_emoji_class() {
emoji_class = hexo-site-config('githubEmojis.className')
return emoji_class ? emoji_class : 'github-emoji'
}

$github-emojis-class-name = get_emoji_class()

最后在自定义样式文件 themes/next/source/css/_custom/custom.styl 中添加:

1
2
3
4
5
6
7
img.{$github-emojis-class-name} {
display: inline;
height: 1.7em;
width: 1.7em;
vertical-align: -0.4em;
border: none !important;
}

现在一切完美了。Enjoy it!✨