vue 实现翻牌子效果

327 阅读2分钟

感谢原文作者分享! 点击传送~ 你可能需要这样的大屏数字滚动效果 - 掘金 (juejin.cn)

再次感谢原文作者的分享,本文为在原文代码上进行完善封装的一个翻牌子组件

具体的实现思路原文说的很清晰,这里就不再赘述,想了解的小伙伴可以查看原文

框架:Vue3

源码

创建公共组件 FlipCardNumber.vue

<template>
    <div id="flip_card_number">
        <ul class="ul_dom">
            <li :class="{ 'number-item': !isNaN(item) }" v-for="(item, index) in state.computeNumber" :key="index">
                <span v-if="!isNaN(item)">
                    <i :class="'numberItem' + props.selfClassId">0123456789</i>
                </span>
                <p v-else class="not_num_span">{{ item }}</p>
            </li>
        </ul>
    </div>
</template>

<script setup>
import {
    watch,
    nextTick,
    onBeforeMount,
    onBeforeUnmount,
    onMounted,
    reactive,
    ref,
} from "vue";

const props = defineProps({
    statisticalVal: {   // 按钮name
        type: [String, Number],
        // default: '00000'
    },
    selfClassId: {   // 翻牌子组件循环id标识
        type: [String, Number],
        default: 0
    },
})

const state = reactive({
    classNum: '',   // 为了区分不同组件的翻牌子
    newNumber: 0, // 获取到的新数字
    computeNumber: ['0', '0', ',', '0', '0', '0', ',', '0', '0', '0'], // 页面展示循环滚动的数字数组
})

watch(
    () => props.statisticalVal,
    (val, preVal) => {
        // console.log(val, preVal,  'val, preValval, preVal');
        state.classNum = props.selfClassId
        increaseNumber(val)
    },
);

onMounted(() => {

})

const increaseNumber = (val) => {
    let difference = 0
    if (val > state.newNumber) {
        difference = val - state.newNumber
    } else if (val < state.newNumber) {
        difference = state.newNumber - val
    }
    state.newNumber = state.newNumber + (difference)
    let comN = state.newNumber.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    state.computeNumber = comN.split('');
    setNumberTransform()
}

const setNumberTransform = () => {
    let numberItems = document.getElementsByClassName('numberItem' + state.classNum)
    let numberArr = state.computeNumber.filter(item => !isNaN(item))
    for (let index = 0; index < numberItems.length; index++) {
        let elem = numberItems[index]
        elem.style.transform = `translate(-50%, -${numberArr[index] * 10}%)`
    }
}
</script>

<style scoped lang="less">
#flip_card_number {
    height: 4rem;
}

.ul_dom {
    height: 100%;
    margin: 0 auto;
    padding: 0;
    font-size: 3rem;
    display: flex;
    justify-content: center;
    list-style-type: none;
}

.number-item {
    width: 2rem;
    background-size: 100% 100%;

    span {
        position: relative;
        display: inline-block;
        margin-right: 10px;
        width: 100%;
        height: 100%;
        writing-mode: vertical-rl;
        text-orientation: upright;
        overflow: hidden;

        i {
            position: absolute;
            top: 0;
            left: 50%;
            transform: translate(-50%, 0);
            transition: transform 0.5s ease-in-out;
            letter-spacing: 10px;
        }
    }
}

.not_num_span {
    margin: 0;
    line-height: 50px;
}
</style>

其中父组件传输的selfClassId是一个页面中展示多个翻牌组件需要的,如果页面中只有一个组件,可不传

父组件使用

// 1、引入
<script setup>
import FlipCardNumber from "@/components/FlipCardNumber.vue"
</script>

// 2、使用
<template>
    <div>
        <FlipCardNumber :statisticalVal="valCount" :selfClassId="0"/>
    </div>
</template>

valCount是从接口获取到的最新数字

再次说明 selfClassId 在一个页面中使用多个 <FlipCardNumber> 时需要添加的,如果页面中只有一个 <FlipCardNumber> 无需添加