Hexo NexT 8.27 主题添加鼠标特效(樱花/爆炸)

适用Hexo NexT 主题8.0以后的版本

效果说明

这篇文章将为你的 Hexo NexT 主题(版本 8.27+)添加两种酷炫鼠标特效:

  • 樱花特效:彩色星形粒子跟随鼠标移动
  • 爆炸特效:点击鼠标时产生炫彩粒子爆炸
适配版本:NexT 8.27.0 及以上

实现步骤

第一步:创建鼠标特效 JavaScript 文件

创建文件夹

themes/next/source/js/ 目录下新建 cursor 文件夹:

1
themes/next/source/js/cursor/

创建 cherry.js(樱花特效)

文件路径:themes/next/source/js/cursor/cherry.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
(function cherry() {
var possibleColors = ["#D61C59", "#E7D84B", "#1B8798"]
var width = window.innerWidth;
var height = window.innerHeight;
var cursor = {x: width/2, y: width/2};
var particles = [];
function init() {
bindEvents();
loop();
}
function bindEvents() {
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('touchmove', onTouchMove);
document.addEventListener('touchstart', onTouchMove);
window.addEventListener('resize', onWindowResize);
}
function onWindowResize(e) {
width = window.innerWidth;
height = window.innerHeight;
}
function onTouchMove(e) {
if( e.touches.length > 0 ) {
for( var i = 0; i < e.touches.length; i++ ) {
addParticle( e.touches[i].clientX, e.touches[i].clientY, possibleColors[Math.floor(Math.random()*possibleColors.length)]);
}
}
}
function onMouseMove(e) {
cursor.x = e.clientX;
cursor.y = e.clientY;
addParticle( cursor.x, cursor.y, possibleColors[Math.floor(Math.random()*possibleColors.length)]);
}
function addParticle(x, y, color) {
var particle = new Particle();
particle.init(x, y, color);
particles.push(particle);
}
function updateParticles() {
for( var i = 0; i < particles.length; i++ ) {
particles[i].update();
}
for( var i = particles.length -1; i >= 0; i-- ) {
if( particles[i].lifeSpan < 0 ) {
particles[i].die();
particles.splice(i, 1);
}
}
}
function loop() {
requestAnimationFrame(loop);
updateParticles();
}
function Particle() {
this.character = "*";
this.lifeSpan = 120;
this.initialStyles ={
"position": "fixed",
"top": "0",
"display": "block",
"pointerEvents": "none",
"z-index": "10000000",
"fontSize": "20px",
"will-change": "transform"
};
this.init = function(x, y, color) {
this.velocity = {
x: (Math.random() < 0.5 ? -1 : 1) * (Math.random() / 2),
y: 1
};
this.position = {x: x - 10, y: y - 20};
this.initialStyles.color = color;
this.element = document.createElement('span');
this.element.innerHTML = this.character;
applyProperties(this.element, this.initialStyles);
this.update();
document.body.appendChild(this.element);
};
this.update = function() {
this.position.x += this.velocity.x;
this.position.y += this.velocity.y;
this.lifeSpan--;
this.element.style.transform = "translate3d(" + this.position.x + "px," + this.position.y + "px,0) scale(" + (this.lifeSpan / 120) + ")";
}
this.die = function() {
this.element.parentNode.removeChild(this.element);
}
}
function applyProperties( target, properties ) {
for( var key in properties ) {
target.style[ key ] = properties[ key ];
}
}
init();
})();

创建 explosion.min.js(爆炸特效)

文件路径:themes/next/source/js/cursor/explosion.min.js

1
"use strict";function updateCoords(e){pointerX=(e.clientX||e.touches[0].clientX)-canvasEl.getBoundingClientRect().left,pointerY=e.clientY||e.touches[0].clientY-canvasEl.getBoundingClientRect().top}function setParticuleDirection(e){var t=anime.random(0,360)*Math.PI/180,a=anime.random(50,180),n=[-1,1][anime.random(0,1)]*a;return{x:e.x+n*Math.cos(t),y:e.y+n*Math.sin(t)}}function createParticule(e,t){var a={};return a.x=e,a.y=t,a.color=colors[anime.random(0,colors.length-1)],a.radius=anime.random(16,32),a.endPos=setParticuleDirection(a),a.draw=function(){ctx.beginPath(),ctx.arc(a.x,a.y,a.radius,0,2*Math.PI,!0),ctx.fillStyle=a.color,ctx.fill()},a}function createCircle(e,t){var a={};return a.x=e,a.y=t,a.color="#F00",a.radius=0.1,a.alpha=0.5,a.lineWidth=6,a.draw=function(){ctx.globalAlpha=a.alpha,ctx.beginPath(),ctx.arc(a.x,a.y,a.radius,0,2*Math.PI,!0),ctx.lineWidth=a.lineWidth,ctx.strokeStyle=a.color,ctx.stroke(),ctx.globalAlpha=1},a}function renderParticule(e){for(var t=0;t<e.animatables.length;t++){e.animatables[t].target.draw()}}function animateParticules(e,t){for(var a=createCircle(e,t),n=[],i=0;i<numberOfParticules;i++){n.push(createParticule(e,t))}anime.timeline().add({targets:n,x:function(e){return e.endPos.x},y:function(e){return e.endPos.y},radius:0.1,duration:anime.random(1200,1800),easing:"easeOutExpo",update:renderParticule}).add({targets:a,radius:anime.random(80,160),lineWidth:0,alpha:{value:0,easing:"linear",duration:anime.random(600,800)},duration:anime.random(1200,1800),easing:"easeOutExpo",update:renderParticule,offset:0})}function debounce(e,t){var a;return function(){var n=this,i=arguments;clearTimeout(a),a=setTimeout(function(){e.apply(n,i)},t)}}var canvasEl=document.querySelector(".fireworks");if(canvasEl){var ctx=canvasEl.getContext("2d"),numberOfParticules=30,pointerX=0,pointerY=0,tap="mousedown",colors=["#FF1461","#18FF92","#5A87FF","#FBF38C"],setCanvasSize=debounce(function(){canvasEl.width=2*window.innerWidth,canvasEl.height=2*window.innerHeight,canvasEl.style.width=window.innerWidth+"px",canvasEl.style.height=window.innerHeight+"px",canvasEl.getContext("2d").scale(2,2)},500),render=anime({duration:1/0,update:function(){ctx.clearRect(0,0,canvasEl.width,canvasEl.height)}});document.addEventListener(tap,function(e){"sidebar"!==e.target.id&&"toggle-sidebar"!==e.target.id&&"A"!==e.target.nodeName&&"IMG"!==e.target.nodeName&&(render.play(),updateCoords(e),animateParticules(pointerX,pointerY))},!1),setCanvasSize(),window.addEventListener("resize",setCanvasSize,!1)}

第二步:创建自定义模板文件

创建 _custom 文件夹

themes/next/layout/ 目录下新建 _custom 文件夹:

1
themes/next/layout/_custom/

创建 custom.njk 文件

文件路径:themes/next/layout/_custom/custom.njk

1
2
3
4
5
6
7
8
9
{% if theme.cursor_effect.enabled %}
{% if theme.cursor_effect.type == "explosion" %}
<canvas class="fireworks" style="position: fixed;left: 0;top: 0;z-index: 9999;pointer-events: none;"></canvas>
<script src="https://cdn.bootcss.com/animejs/2.2.0/anime.min.js"></script>
<script src="/js/cursor/explosion.min.js"></script>
{% elseif theme.cursor_effect.type == "cherry" %}
<script src="/js/cursor/cherry.js"></script>
{% endif %}
{% endif %}

第三步:配置主题

编辑主题配置文件

打开 themes/next/_config.yml,找到第 21 行的 custom_file_path 配置,确保 bodyEnd 已启用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Define custom file paths.
# Create your custom files in site directory `source/_data` and uncomment needed files below.
custom_file_path:
#head: source/_data/head.njk
#header: source/_data/header.njk
#sidebar: source/_data/sidebar.njk
#postMeta: source/_data/post-meta.njk
#postBodyStart: source/_data/post-body-start.njk
#postBodyEnd: source/_data/post-body-end.njk
#footer: source/_data/footer.njk
bodyEnd: source/_data/body-end.njk # 确保这一行没有被注释
#variable: source/_data/variables.styl
#mixin: source/_data/mixins.styl
#style: source/_data/styles.styl

添加鼠标特效配置

themes/next/_config.yml 文件末尾添加:

1
2
3
4
5
# 鼠标特效配置
# cherry: 樱花特效 | explosion: 爆炸特效
cursor_effect:
enabled: true
type: cherry

第四步:创建自定义注入文件

创建 _data 目录

source/ 目录下创建 _data 文件夹(如果已存在则跳过):

1
source/_data/

创建 body-end.njk 文件

文件路径:source/_data/body-end.njk

1
2
3
4
5
6
7
8
9
{% if theme.cursor_effect.enabled %}
{% if theme.cursor_effect.type == "explosion" %}
<canvas class="fireworks" style="position: fixed;left: 0;top: 0;z-index: 9999;pointer-events: none;"></canvas>
<script src="https://cdn.bootcss.com/animejs/2.2.0/anime.min.js"></script>
<script src="/js/cursor/explosion.min.js"></script>
{% elseif theme.cursor_effect.type == "cherry" %}
<script src="/js/cursor/cherry.js"></script>
{% endif %}
{% endif %}

第五步:重新生成并测试

在博客根目录执行:

1
2
3
hexo clean
hexo g
hexo s

打开浏览器访问 http://localhost:4000,移动鼠标应该能看到樱花粒子跟随。

切换特效

想要切换为爆炸特效?只需修改 themes/next/_config.yml

1
2
3
cursor_effect:
enabled: true
type: explosion # 改为 explosion

然后重新生成即可:

1
hexo clean && hexo g

常见问题

Q: 为什么看不到特效?

A: 检查以下几点:

  1. 确认 source/_data/body-end.njk 文件存在且配置正确
  2. 确认 themes/next/_config.ymlcursor_effect.enabledtrue
  3. 执行 hexo clean 清理缓存后重新生成

Q: 爆炸特效不工作?

A: 确保 anime.min.js 库已正确加载,检查浏览器控制台是否有错误信息。

Q: 可以自定义粒子颜色吗?

A: 可以!编辑 cherry.js 中的 possibleColors 数组,或编辑 explosion.min.js 中的 colors 数组。

总结

通过以上步骤,你就能为 Hexo NexT 主题添加炫彩鼠标特效了。这种方法采用了 NexT 8.27+ 的官方推荐做法,使用 custom_file_pathbodyEnd 配置,不会与主题更新产生冲突。

希望你喜欢这个特效!