我用 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的思路及源码,再次感谢!

相关推荐
圣殿骑士-Khtangc1 天前
Trae IDE AI 编程超全使用教程|从入门到精通,解锁 AI 开发新效率
ide·人工智能·ai编程·编程助手·trae
Mr_Carl3 天前
我用 Trae 花了一周,从零打造了一个 AI 面试官🚀
面试·trae·vibecoding
北漂的尘埃3 天前
学习AI 编程工具
ai·trae·ai ide·vibe coding·claude code
丁劲犇3 天前
在Trae Solo模式下用Qt HttpServer和Concurrent升级MCP服务器绘制6G互联网覆盖区域
服务器·开发语言·qt·ai·6g·mcp·trae
豆包MarsCode5 天前
产品经理 6 大热门 Skills 推荐
trae
挂科边缘5 天前
字节跳动 AI 原生 IDE Trae 安装与上手图文教程
ide·人工智能·trae
豆包MarsCode6 天前
TRAE 技术专家推荐:6 个技巧让你的 Agent 更听话
trae
海石7 天前
微信小程序开发01:XR-FRAME的快速上手
前端·增强现实·trae
huazi999 天前
AI编程(三):Trae+高德MCP Server应用
ai编程·高德·mcp·trae
huazi999 天前
AI编程(一):Trae+Git 应用开发
git·ai编程·trae