javascript - 创建迪士尼尘埃风格的光标轨迹
问题描述
我正在尝试制作一个光标,它会像任何迪士尼电影的介绍一样留下魔法尘埃的痕迹:example。所以我看到它的方式是它分为两部分。1. 小道和 2. 类似的落下和淡出的小道。到目前为止,我已经使基本轨迹工作得很好,下面的代码是用于下降轨迹的,本质上是它的副本和一个 css 动画..
我遇到的问题是抖动很多。我猜 css 动画对性能来说不是很好,并且导致它在我的页面上真正抖动。我刚刚阅读了 requestAnimationFrame 但对此很陌生,所以不知道如何实现它。我怎么能在这里使用 requestAnimationFrame 而不是 css?
我还认为在 js 中创建动画自定义将允许在下落粒子的动画中也有一个随机偏移......更像是在视频中。
window.addEventListener('mousemove', function (e) {
//trail
[1, .9, .8, .5, .25, .6, .4, .3, .2].forEach(function (i) {
var j = (1 - i) * 50;
var elem = document.createElement('div');
var size = Math.ceil(Math.random() * 10 * i) + 'px';
elem.style.position = 'fixed';
elem.style.zIndex = 6;
elem.style.top = e.pageY - window.scrollY + Math.round(Math.random() * j - j / 2) + 'px';
elem.style.left = e.pageX + Math.round(Math.random() * j - j / 2) + 'px';
elem.style.width = size;
elem.style.opacity = "0.5";
elem.style.height = size;
elem.style.background = 'hsla(' +
Math.round(Math.random() * 160) + ', ' +
'60%, ' +
'90%, ' +
i + ')';
elem.style.borderRadius = size;
elem.style.pointerEvents = 'none';
document.body.appendChild(elem);
window.setTimeout(function () {
document.body.removeChild(elem);
}, Math.round(Math.random() * i * 1000));
});
// falling trail
[1, .9, .8, .5, .25, .6, .3, .2].forEach(function (i) {
var j = (1 - i) * 50;
var elem = document.createElement('div');
var size = Math.ceil(Math.random() * 10 * i) + 'px';
elem.style.position = 'fixed';
elem.style.zIndex = 6;
elem.style.top = e.pageY - window.scrollY + Math.round(Math.random() * j - j / 2) + 'px';
elem.style.left = e.pageX + Math.round(Math.random() * j - j / 2) + 'px';
elem.style.width = size;
elem.style.opacity = "0.5";
elem.style.height = size;
elem.style.animation = "fallingsparkles 1s";
elem.style.background = 'hsla(' +
Math.round(Math.random() * 160) + ', ' +
'60%, ' +
'90%, ' +
i + ')';
elem.style.borderRadius = size;
elem.style.pointerEvents = 'none';
document.body.appendChild(elem);
window.setTimeout(function () {
document.body.removeChild(elem);
}, Math.round(Math.random() * i * 1000));
});
}, false);
body {
width:100%;
height:100%;
background-color: #000;
}
@keyframes fallingsparkles {
from {
transform: translateY(0);
}
to {
transform: translateY(50px);
}
}
<body></body>
解决方案
多么酷的小动画。我认为从长远来看这会很烦人,但仍然:很酷。
我不喜欢这个解决方案的一点是,我必须执行一个连续的递归循环,即使没有要设置动画的元素也会继续。可能有一些方法可以避免这种情况,但仅仅展示如何实现requestAnimationFrame
. 如您所见,使用 requestAnimationFrame 并不难。您只需调用与您进行计算相同的方法。
除了将每个元素添加到正文之外,我还sparkleArr
通过addAnimationProperties
. 我终于添加了一种全新的方法——moveSparkles
用于计算运动和移除元素。calculateInterpolation
根据元素的创建时间、消失时间和当前时间计算元素应移动多长时间的百分比。
我认为代码是不言自明的。我不得不在一个地方做评论,我认为不可能通过变量或方法名称来解释代码。
let trailArr = [1, .9, .8, .5, .25, .6, .4, .3, .2];
var sparklesArr = [];
function trailAnimation(e, i, maxYTranslation) {
let elem = document.createElement('div');
elem = styleSparkle(elem, e, i);
elem.classList.add("sparkle");
document.body.appendChild(elem);
elem = addAnimationProperties(elem, i, maxYTranslation);
sparklesArr.push(elem);
}
function styleSparkle(elem, e, i) {
let j = (1 - i) * 50;
let size = Math.ceil(Math.random() * 10 * i) + 'px';
elem.style.top = e.pageY - window.scrollY + Math.round(Math.random() * j - j / 2) + 'px';
elem.style.left = e.pageX + Math.round(Math.random() * j - j / 2) + 'px';
elem.style.width = size;
elem.style.height = size;
elem.style.borderRadius = size;
elem.style.background = 'hsla(' +
Math.round(Math.random() * 160) + ', ' +
'60%, ' +
'90%, ' +
i + ')';
return elem;
}
function addAnimationProperties(elem, i, maxYTranslation) {
const ANIMATION_SPEED = 1100;
let lifeExpectancy = Math.round(Math.random() * i * ANIMATION_SPEED);
elem.maxYTranslation = maxYTranslation;
elem.animationSpeed = ANIMATION_SPEED;
elem.created = Date.now();
elem.diesAt = elem.created + lifeExpectancy;
return elem;
}
function moveSparkles() {
let remove = false;
let moveIndex = 0;
let sparkle;
for (let i = 0; i < sparklesArr.length; i++) {
sparkle = sparklesArr[i];
remove = sparkle.diesAt <= Date.now();
if (remove) {
document.body.removeChild(sparkle);
} else {
if (sparkle.maxYTranslation) {
let interpolation = calculateInterpolation(sparkle);
sparkle.style.transform = `translateY(${interpolation}px)`;
}
sparklesArr[moveIndex++] = sparkle; // faster than array.splice()
}
}
sparklesArr.length = moveIndex;
requestAnimationFrame(moveSparkles);
}
function calculateInterpolation(sparkle) {
let currentMillis = Date.now();
let lifeProgress = (currentMillis - sparkle.created) / sparkle.animationSpeed;
let interpolation = sparkle.maxYTranslation * lifeProgress;
return interpolation;
}
window.addEventListener('mousemove', function (e) {
trailArr.forEach((i) => {trailAnimation(e, i)});
let maxYTranslation = '80';
trailArr.forEach((i) => {trailAnimation(e, i, maxYTranslation)});
}, false);
moveSparkles(); // starts the recursive loop
body {
width:100%;
height:100%;
background-color: #000;
}
.sparkle {
position: fixed;
z-index: 6;
opacity: 0.5;
pointer-events: none;
}
<body></body>
推荐阅读
- reactjs - 在不点击按钮或锚标签的情况下显示语义-ui-react 弹出窗口:React+Typescript
- java - Android:ListView 在 OnClickListener 中不起作用
- apache-kafka - 高扩展性问题:如何跨多个微服务同步数据
- javascript - 返回 NAN 的对象输出
- qt - 有没有办法从文件中读取一行并暂停几秒钟,在暂停期间,函数会检查用户是否输入了相同的单词?
- xml - 名称不能以“?”开头 字符,十六进制值 0x3F
- python - 如何将数据框中的特定值导入熊猫中的变量
- amazon-web-services - 用于取消订阅 AWS Organizations 成员账户中的营销电子邮件的 SDK
- python - 用于从 URL 解析 uid 的正则表达式
- swift - NSFont 和 CTFont 有什么区别,为什么 CTFont 会挂起 NSTextFieldCell?