我用 TRAE 翻译了J友的数字滚动组件,从原生到Vue!

最近在做自己的大屏项目,毕竟很多公司还是要求提交自己的作品的。

虽然做的效果一般,但是UI和UE上的体验一定要拉满,给面试官以视觉上的冲击力才是大屏的关键。

在掘金上看到这篇文章写的仿百度数字滚动效果,打算比着葫芦画瓢,复刻一个Vue3版本的数字滚动组件。

正好现在一直在用 TRAE,复刻代码也比较简单。

效果

数字滚动组件的核心部分就是延迟滚动效果,各个数字从前到后延迟滚动会造成一种非常好的视觉效果。

我一开始以为直接用CSS实现就齐活了,后来发现事情不是这么简单的。

  • 每位数字的滚动时间不同,做出前后延迟效果。
  • 数字需要精准的滚动到所需的内容,并且滚动过程需要连贯。
  • 滚动效果上带有一种惯性的感觉。

本来想着自己比着来一遍速度也很快,但是低估了内容的难度。

于是乎我打开 TRAE ,将J友的代码拷进去,输入指令:

请帮我将上述代码转换为Vue3的组件代码,我要实现的是一个数字滚动的组件,将每个数字进行分割,最大8位数,不足8位使用0补齐8位。同时每3位增加一个逗号分隔符,每位数字都拥有自己的背景,类似于记分牌的效果。

1,2,3.....

于是乎以下的代码就输出了出来!

实现代码

html 复制代码
<div class="num-statistic">
    <div class="num-statistic-content">
        <template v-for="(_digit, index) in numList" :key="index">
            <div class="digit-container" :class="`digit-container${index+1}`" ref="digitListRefs">
                <div class="digit-list">
                    <div v-for="(_item, idx) in 10" :key="idx" class="digit">{{ idx }}</div>
                    <div v-for="(_item, idx) in 10" :key="`dup-${idx}`" class="digit">{{ idx }}</div>
                    <div v-for="(_item, idx) in 10" :key="`dup2-${idx}`" class="digit">{{ idx }}</div>
                </div>
            </div>
            <div v-if="index === 1 || index === 4" class="num-split" :key="`split-${index}`">,</div>
        </template>
    </div>
</div>

Ps: TRAE提醒我,每个需要滚动的数字组件一定要通过 v-for 循环创建,即便你的数字位数是固定的。

因为Vue3中只有通过v-for定义相同的ref才会被归纳到一个数组中。

单纯的写多个divref相同的话,并不是数组,而是一个对象,指向最后一个DOM

js 复制代码
const props = defineProps<{
    num: number
}>()
const digitListRefs = ref<HTMLDivElement[]>([])

const numList = computed(() => {
    const numStr = String(props.num).padStart(8, '0');
    return numStr.split('');
});

watch(numList, () => {
    nextTick(() => {
        startAnimate();
    })
}, {
    immediate: true
})

const startAnimate = () => {
    const digits = numList.value;
    digitListRefs.value.forEach((element, i) => {
        if (element && element.querySelector('.digit-list')) {
            const list = element.querySelector('.digit-list') as HTMLElement;
            const targetDigit = parseInt(digits[i], 10);
            const targetY = -(20 + targetDigit) * 50;

            list.style.transform = `translateY(${targetY}px)`;
        }
    });
}

Ps: 这里注意,我设置的数字最大8位数,逻辑上是不足8位以0补全。

完整组件代码

html 复制代码
<script setup lang="ts">
import {ref, defineProps, computed, watch, nextTick} from "vue";

const props = defineProps<{
    num: number
}>()

const digitListRefs = ref<HTMLDivElement[]>([])

const numList = computed(() => {
    const numStr = String(props.num).padStart(8, '0');
    return numStr.split('');
});

watch(numList, () => {
    nextTick(() => {
        startAnimate();
    })
}, {
    immediate: true
})

const startAnimate = () => {
    const digits = numList.value;
    digitListRefs.value.forEach((element, i) => {
        if (element && element.querySelector('.digit-list')) {
            const list = element.querySelector('.digit-list') as HTMLElement;
            const targetDigit = parseInt(digits[i], 10);
            const targetY = -(20 + targetDigit) * 50;

            list.style.transform = `translateY(${targetY}px)`;
        }
    });
}
</script>

<template>
    <div class="num-statistic">
        <div class="num-statistic-content">
            <template v-for="(_digit, index) in numList" :key="index">
                <div class="digit-container" :class="`digit-container${index+1}`" ref="digitListRefs">
                    <div class="digit-list">
                        <div v-for="(_item, idx) in 10" :key="idx" class="digit">{{ idx }}</div>
                        <div v-for="(_item, idx) in 10" :key="`dup-${idx}`" class="digit">{{ idx }}</div>
                        <div v-for="(_item, idx) in 10" :key="`dup2-${idx}`" class="digit">{{ idx }}</div>
                    </div>
                </div>
                <div v-if="index === 1 || index === 4" class="num-split" :key="`split-${index}`">,</div>
            </template>
        </div>
    </div>
</template>

<style scoped lang="less">
.num-statistic-content {
    display: flex;
    gap: 12px;
}

.digit-container1,
.digit-container2,
.digit-container3,
.digit-container4,
.digit-container5,
.digit-container6,
.digit-container7,
.digit-container8 {
    width: 36px;
    height: 50px;
    text-align: center;
    line-height: 50px;
    overflow: hidden;
    background-color: #244193;
    font-size: 24px;
    font-weight: bold;
    border-radius: 4px;

    .digit {
        height: 50px;
        display: flex;
        align-items: center;
        justify-content: center;
    }
}

.digit-container1 .digit-list {
    transition: transform 1720ms ease-in-out;
}

.digit-container2 .digit-list {
    transition: transform 1760ms ease-in-out;
}

.digit-container3 .digit-list {
    transition: transform 1800ms ease-in-out;
}

.digit-container4 .digit-list {
    transition: transform 1840ms ease-in-out;
}

.digit-container5 .digit-list {
    transition: transform 1880ms ease-in-out;
}

.digit-container6 .digit-list {
    transition: transform 1920ms ease-in-out;
}

.digit-container7 .digit-list {
    transition: transform 1960ms ease-in-out;
}

.digit-container8 .digit-list {
    transition: transform 2000ms ease-in-out;
}

.num-split {
    width: 20px;
    text-align: center;
    font-size: 24px;
    font-weight: bold;
    line-height: 50px;
}
</style>

最后非常感谢这位兄弟@三个木base的思路及源码,再次感谢!

相关推荐
zhouzhouya3 小时前
TRAE SOLO:前端开发的新范式与实践指南
trae
天天摸鱼的java工程师5 小时前
从Java老兵到AI开发实战:我眼中的 TRAE SOLO 助力实践落地
trae
用户4099322502126 小时前
Vue 3响应式系统的底层机制:Proxy如何实现依赖追踪与自动更新?
前端·ai编程·trae
掘金酱9 小时前
🚀TRAE SOLO 实战赛 | 智启Coding 码力全开
ai编程·trae·vibecoding
五月君1 天前
刚刚!字节 Trae SOLO 正式发布,限时免费
ai编程·trae
飞哥数智坊1 天前
TRAE SOLO 正式版上线,限时免费活动开启
人工智能·trae·solo
顾三殇1 天前
【TRAE】AI 编程:颠覆全栈开发,基于 TRAE AI 编程完成 Vue 3 + Node.js + MySQL 企业级项目实战,从环境搭建到部署上线
vue.js·ai编程·trae·ai 开发工具
用户4099322502122 天前
Vue3响应式系统中,对象新增属性、数组改索引、原始值代理的问题如何解决?
前端·ai编程·trae
飞哥数智坊2 天前
TRAE CN + K2 Thinking,我试着生成了一个简版的在线 PS
人工智能·ai编程·trae