Javascript 点击 五彩纸屑效果的实际

演示链接

这个怎么运作#

让我们考虑一下这种效果如何发挥作用的基本原理:

  • 首先:我们需要创建所有单独的五彩纸屑。
  • 接下来:我们需要像五彩纸屑一样移动它们,即达到一个顶峰,然后下降。?
  • 最后:我们需要淡出并移除五彩纸屑。

为了制作五彩纸屑,我们将制作很多小divs。我们将为它们分配所有随机颜色。

为此,代码如下所示:

.confetti-item {
    width: 10px;
    position: absolute;
    top: 0;
    left: 0;
    height: 10px;
}
.confetti {
    position: fixed;
    top: 0;
    left: 0;
}
// Create a confetti holder element
let createElement = document.createElement('div');
createElement.classList.add('confetti');
// These are our 'random' colors
let colors = [ '#2162ff', '#9e21ff', '#21a9ff', '#a9ff21', '#ff2184' ]

// Let's generate some confetti. The function below is generating 40 random confetti items!
let confettiHTML = '';
for(var i = 0; i < 20; ++i) {
    let color = Math.floor(Math.random() * (colors.length));
    confettiHTML += `<div class="confetti-item" style="background-color: ${colors[color]};" data-angle="${Math.random()}" data-speed="${Math.random()}"></div>`;
    confettiHTML += `<div class="confetti-item reverse" style="background-color: ${colors[color]};" data-angle="${Math.random()}" data-speed="${Math.random()}"></div>`;
}

// Updates the style of our new confetti element and appends it to the body
createElement.style.position = `fixed`;
createElement.style.top = `${y}px`;
createElement.style.left = `${x}px`;
createElement.innerHTML = confettiHTML;
document.body.appendChild(createElement);

现在我们已经创建了五彩纸屑的结构,我们必须进入它的运动。

移动#

建模运动需要方程。对于这篇文章,我们将使用传统的弹丸运动方程。如果您不熟悉这些,它们会模拟物体从起点沿 x 和 y 轴的运动,给定一定的速度。

方程如下所示:

// x = speed * time * cos(angle)
// y = speed * time * sin(angle) - (0.5 * gravity * time^2)

我们将使用这些核心方程来创建我们的运动,并为其添加一些修饰符以创建“随机”运动的感觉。例如,这里有一个物体随着抛射运动移动:

上述效果是使用这些射弹运动方程生成的,并根据它们的值简单地平移元素。

弹丸运动的实现#

当我们将其应用于每个五彩纸屑时,我们需要遍历每个项目并相应地调整其运动。您可能已经注意到,我们在每个五彩纸屑元素上都有两个数据标签,它们都有随机数。我们将使用这些随机数来产生随机运动的感觉。

我们将有一个角度和速度的随机数,然后通过其随机数调整每个五彩纸屑元素的位置。

我们将使用时间间隔为 33.3 微秒的时间间隔。

// The gravity or 'falling speed' adjuster
let gravity =  50; // Fjolt is a high gravity planet

// The range of speeds
let maxSpeed = 105000; // Pixels * 1000
let minSpeed = 65000; // Pixels * 1000

// The time
let t = 0; // Time starts at 0

// The range of angles
let maxAngle = 1500; // Radians * 1000
let minAngle = 400; // Radians * 1000

// The initial opacity
let opacity = 1;

// The initial confetti rotation
let rotateAngle = 0;

// The interval
let interval = setInterval(function() {

    // Generate motion for each confetti element
    document.querySelectorAll(`.confetti-item`).forEach(function(item) {
        // So we can have two directions of confetti, we use a modifier on the X axis.
        let modifierX = 1;
        if(item.classList.contains('reverse')) {
            modifierX = -1;
        }
        item.style.opacity = opacity;
        // Get both our random numbers
        let randomNumber = parseFloat(item.getAttribute('data-angle'));
        let otherRandom = parseFloat(item.getAttribute('data-speed'));

        // Generate a random angle motion for rotating each confetti element
        let newRotateAngle = randomNumber * rotateAngle;

        // Generate the angle and speed we use for the equations of motion
        let angle = (randomNumber * (maxAngle - minAngle) + minAngle) / 1000;
        let speed = (randomNumber * (maxSpeed - minSpeed) + minSpeed) / 1000;
            
        // Get x,y for projectile motion. We adjust this by the random number.
        let x = speed * t * Math.cos(angle) + (50 * otherRandom * t);
        let y = speed * t * Math.sin(angle) - (0.5 * gravity * Math.pow(t, 2))  + (50 * otherRandom * t);
        // Transform the element accordingly.
        item.style.transform = `translateX(${x * modifierX}px) translateY(${y * -1}px) rotateY(${newRotateAngle}deg) scale(${1})`;
    })
    // Increase time, and rotate angle
    // Decrease opacity
    t += 0.1;
    rotateAngle += 3;
    opacity -= 0.02;
        
    // If the time is above 6, then lets remove the element
    if(t >= 6) {
        t = 0.1;
        if(document.querySelector(`.confetti`) !== null) {
            console.log(document.querySelector(`.confetti`));
            document.querySelector(`.confetti`).remove();
        }
        clearInterval(interval);
    }
}, 33.33);

最后#

在最终代码中,我为每个 confetti 实例指定了一个单独的 ID,因此我们可以在页面上拥有多个 confetti 实例。还有一些其他的补充,这使它更具交互性。

我目前正在开展一个项目,如果用户点击正确答案,该项目会奖励用户。为用户提供与他们给出正确答案时的感受相匹配的响应,是用户体验的重要组成部分。

我想了几种方法来做到这一点——也许当用户点击正确的响应时,按钮会以积极的方式抖动。我对此不太走运,所以我的注意力转向了五彩纸屑,它(出于所有意图和目的)仅与庆祝有关。

值得一提的是,此页面启用了五彩纸屑。单击任意位置,五彩纸屑应从光标末端或您触摸的任何位置出现。

有趣的事实:在这样做的同时,我还发现五彩纸屑早在 14 世纪的米兰就被使用了,这比我预期的要长得多。