You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将指定JS特效代码转换为Vue代码并正确实现frame方法

完整实现代码

Template 部分修改

<template>
    <section id="successful-order" class="container">
        <!-- 新增canvas用于绘制彩屑效果 -->
        <canvas id="confetti-canvas" style="position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; pointer-events: none; z-index: 999;"></canvas>
        <div class="row office-banner">
            <div class="col-12">
                <img :src="successful" alt="Popper Image"/>
                <div class="sub-title">Your order is complete!</div>
                <div>You will be receiving a confirmation email with your order details.</div>
                <div class="button-area">
                    <button class="btn button">Checkout your tickets</button>
                    <button class="btn button-secondary">Go to homepage!</button>
                </div>
            </div>
        </div>
    </section>
</template>

Script 部分修改

<script>
import successful from "../../../../img/poppers.png";

export default {
    data() {
        return {
            successful: successful,
            // 可自行扩展更多彩屑颜色
            color: ["#8b5642", "#6a696b", "#f2c029", "#e85d44", "#58b9c7"],
            particles: [], // 存储所有彩屑实例
            animationId: null, // 存储动画帧ID用于销毁
            ctx: null, // canvas 上下文
            canvasWidth: 0,
            canvasHeight: 0
        };
    },
    mounted() {
        // 初始化canvas
        const canvas = document.getElementById('confetti-canvas')
        this.ctx = canvas.getContext('2d')
        this.canvasWidth = canvas.width = window.innerWidth
        this.canvasHeight = canvas.height = window.innerHeight
        // 监听窗口大小变化调整canvas尺寸
        window.addEventListener('resize', this.resizeCanvas)
        // 初始化彩屑
        this.initParticles()
        // 启动动画
        this.frame()
    },
    beforeUnmount() {
        // 组件销毁前清除动画和事件监听,避免内存泄漏
        window.removeEventListener('resize', this.resizeCanvas)
        if (this.animationId) cancelAnimationFrame(this.animationId)
    },
    methods: {
        resizeCanvas() {
            const canvas = document.getElementById('confetti-canvas')
            this.canvasWidth = canvas.width = window.innerWidth
            this.canvasHeight = canvas.height = window.innerHeight
        },
        initParticles() {
            // 生成200个彩屑,数量可自行调整
            for (let i = 0; i < 200; i++) {
                this.particles.push({
                    x: Math.random() * this.canvasWidth, // 随机x轴起始位置
                    y: Math.random() * -this.canvasHeight, // 从屏幕上方外开始下落
                    r: Math.random() * 6 + 2, // 彩屑大小
                    d: Math.random() * 50 + 10, // 下落速度系数
                    color: this.color[Math.floor(Math.random() * this.color.length)], // 随机颜色
                    tilt: Math.random() * 10 - 10, // 倾斜角度
                    tiltAngleIncrement: Math.random() * 0.07 + 0.05, // 倾斜角度变化速度
                    tiltAngle: 0
                })
            }
        },
        frame() {
            this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
            let allOutOfScreen = true
            this.particles.forEach((p, i) => {
                // 更新倾斜角度
                p.tiltAngle += p.tiltAngleIncrement
                p.y += (Math.cos(p.d) + 3 + p.r / 2) / 2
                p.x += Math.sin(p.tiltAngle)
                p.tilt = Math.sin(p.tiltAngle - i / 3) * 15
                // 只要还有粒子在屏幕内就继续动画
                if (p.y < this.canvasHeight) allOutOfScreen = false
                // 绘制彩屑
                this.ctx.fillStyle = p.color
                this.ctx.beginPath()
                this.ctx.arc(p.x, p.y, p.r, 0, 2 * Math.PI)
                this.ctx.fill()
            })
            // 所有粒子都掉出屏幕就停止动画
            if (allOutOfScreen) {
                cancelAnimationFrame(this.animationId)
                return
            }
            this.animationId = requestAnimationFrame(this.frame)
        }
    }
};
</script>

核心修改说明

  • 新增canvas元素作为彩屑绘制载体,设置固定定位、最高层级且不响应鼠标事件,不会影响原有页面交互
  • 在mounted生命周期钩子中初始化canvas尺寸、彩屑数据并启动动画,此时组件已经挂载到DOM上可以正常获取canvas元素
  • 在beforeUnmount钩子中清除动画帧和事件监听,避免内存泄漏
  • frame方法中每一帧先清空画布,再更新所有彩屑的位置、倾斜属性后重新绘制,实现流畅的下落动画效果
  • 可以自行调整initParticles方法中的彩屑数量、颜色数组、速度参数来匹配你想要的视觉效果

内容的提问来源于stack exchange,提问作者magic bean

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 16:39:03