4 月 1 号打开了 StackOverflow, 看见满屏幕中二元素还以为自己走错了板块. 后来才想到愚人节的事情. 除了独角兽和超 gay 配色, 还有个鼠标下雪的效果还行, 就想着做做看.
mousemove
事件, 获取鼠标位置.fade out
, 和 x, y 轴两个方向的移动组成, 原实现并没有太复杂的诸如抖动, 动画曲线之类效果, 也没太大必要. 这一部分 css 可以实现, 问题是要不要利用transition
, 用的话代码上简单一点, 不用的话可以精细控制做点其他效果.找一个区域, 盛放雪花元素. 再放一个雪花的模板, 克隆用.
<div id="playground" style="width: 500px; height: 500px; background: lightgrey;"></div>
<span id="snowflake-template" class="snowflake">*</span>
一些默认的 css 属性, 主要是控制雪花 sprite.
<style>
.snowflake {
display: none;
position: fixed;
z-index: 861112;
transition: all 2s;
opacity: 1;
pointer-events: none;
}
#playground .snowflake {
display: block;
}
</style>
准备工作
let COLORS = [...]
let playground = document.getElementById('playground')
let template = document.getElementById('snowflake-template')
function onMouseMove() {
// todo
}
playground.addEventListener('mousemove', onMouseMove)
然后实现onMouseMove
, 要做的事情就是, 1, 从模板复制一个雪花出来, 塞到容器里 2, 添加相关 css 属性. 3, 一定时间后摘除雪花元素. 考虑性能这个方法可做throttle
, 这里略过.
function onMouseMove(evt) {
let color = COLORS[(Math.random() * 3) | 0];
let snowflake = template.cloneNode(true);
snowflake.removeAttribute('id');
playground.appendChild(snowflake);
snowflake.style.cssText = `
top: ${evt.clientY}px;
left:${evt.clientX}px;
color: ${color};
`;
setTimeout(() => {
snowflake.style.opacity = 0;
snowflake.style.transform = `scale(.4) translate3d(${(0.5 - Math.random()) * 200}px, ${Math.random() * 280}px, 0)`;
});
setTimeout(() => {
snowflake.remove();
}, 2000);
}
值得注意的是, opacity
和transform
是通过setTimeout
另外加到元素上, 这样可以使transition
生效. 这里也可以用setInterval
或requestAnimationFrame
来控制, 各个数值亦可以根据效果调整.
*
上面的 demo, 颜色是借用的, 其他都是按照效果实现. 原实现其实已经公布在了 StackOverflow 上. 对比下来主要区别是, 原实现没用transition
而是上面提到的requestAnimationFrame
方案, 效果上确实没有 demo 中的卡顿(原因应该是是 demo 中的第一个setTimeout
的频繁 DOM 操作).