css 实现从下往下飞入动画

73 阅读5分钟
<view class="lottery">
    <view class="lottery-item flex-column-center" :style="{
            width: imageWidth + 'px',
            height: imageHeight + 20 + 'px',
            left: item.left,
            top: '-400rpx',
            opacity: 0
        }" :class="'prize_' + lists.length + '_' + index" v-for="(item, index) in lists" :key="index">
        <view :style="{ background: colors[item.lottery_id].bgcolor }" class="tag flex-center"
            @click="categoryChange(item.lottery_id)">
            <view :style="{
                    background: colors[item.lottery_id].color,
                    '-webkit-background-clip': 'text',
                    '-webkit-text-fill-color': 'transparent'
                }" class="tag-name">
                {{ item.lottery_name }}
            </view>
        </view>
        <view class="info text-center" :style="{ height:imageHeight+'px'}">
            <view :style="{ height: imgHeight }" class="img flex-center">
                <image :src="item.thumbnail_image" mode="aspectFit"></image>
            </view>
            <view class="font-size-12 text-ellipsis px-3">{{ item.box_name }}</view>
            <view class="price">¥{{ Number(item.price).toFixed(0) }}</view>
        </view>
    </view>
</view>

 mounted() {
    this.initImgHeight();
},
updated() {
    this.initImgHeight();
},
methods: {
    initImgHeight() {
        if (0 === this.imageHeight) {
            uni.createSelectorQuery()
                .in(this)
                .select('.lottery')
                .boundingClientRect(data => {
                    if (data) {
                        const widthRatio = 1 === this.lists.length ? 0.46 : (3 === this.lists.length ?
                            0.35 : 0.26);
                        this.imageWidth = data.width * widthRatio;
                        this.imageHeight = this.imageWidth / 0.82
                        this.init()
                    }
                })
                .exec();
        }
    },
    init() {
        if (1 === this.lists.length) {
            this.imgHeight = '78%'
            this.lists = this.lists.map((item, index) => {
                item.width = '46%'
                if (0 === index || 1 === index) {
                    item.top = '135px'
                }
                if (0 === index) {
                    item.left = '27%'
                }
                return item
            })
        }
        if (3 === this.lists.length) {
            this.imgHeight = '72%'
            this.lists = this.lists.map((item, index) => {
                item.width = '35%'
                if (0 === index || 1 === index) {
                    item.top = '135px'
                }
                if (0 === index) {
                    item.left = '12%'
                }
                if (1 === index) {
                    item.left = '53%'
                }
                if (2 === index) {
                    item.left = "32.5%"
                    item.top = (135 + this.imageHeight + 40) + 'px'
                }
                return item
            })
        } else if (5 === this.lists.length || 10 === this.lists.length) {
            this.imgHeight = '65%'
            this.lists = this.lists.map((item, index) => {
                item.width = '26%'
                if (0 === index || 1 === index || 2 === index) {
                    item.top = '135px'
                }
                if (6 === index || 7 === index || 8 === index) {
                    item.top = (135 + this.imageHeight * 2 + 80) + 'px'
                }
                if (9 === index) {
                    item.left = "37%"
                    item.top = (135 + this.imageHeight * 3 + 120) + 'px'
                }
                if (3 === index || 4 === index || 5 === index) {
                    item.top = (135 + this.imageHeight + 40) + 'px'
                }
                if (0 === index || 6 === index) {
                    item.left = '8%'
                }
                if (1 === index || 7 === index) {
                    item.left = '37%'
                }
                if (2 === index || 5 === index || 8 === index) {
                    item.left = '66%'
                }
                if (3 === index) {
                    item.left = 5 === this.lists.length ? '22.5%' : '8%'
                }
                if (4 === index) {
                    item.left = 5 === this.lists.length ? '51.5%' : '37%'
                }
                return item
            })
        }
    }
}

.lottery-item {
    position: absolute;

    .tag {
        display: inline-block;
        transform: skew(-20deg);
        padding: 5rpx 15rpx;
        margin-bottom: 10rpx;

        &-name {
            line-height: 1;
            font-family: YouSheBiaoTiHei;
            transform: skew(20deg);
        }
    }

    .info {
        width: 100%;
        height: 100%;
        background-color: #fff;
        border-radius: 30rpx;

        .img {
            width: 100%;

            image {
                width: 60%;
            }
        }

        .price {
            font-size: 30rpx;
            font-weight: bold;
            line-height: 1;
        }
    }
}

// 第一行
@keyframes gif1 {
    100% {
        opacity: 1;
        top: 135px;
    }
}

.prize_1_0,
.prize_3_0,
.prize_5_0,
.prize_10_0 {
    animation: gif1 0.4s ease-in forwards;
}

.prize_3_1,
.prize_5_1,
.prize_10_1 {
    animation: gif1 0.4s ease-in 0.4s forwards;
}

.prize_3_2 {
    animation: gif32 0.4s ease-in 0.8s forwards;

    // 3个第二行
    @keyframes gif32 {
        100% {
            opacity: 1;
            top: 335px;
        }
    }
}

.prize_5_2,
.prize_10_2 {
    animation: gif1 0.4s ease-in 0.8s forwards;
}

// 5个第二行
@keyframes gif2 {
    100% {
        opacity: 1;
        top: 294px;
    }
}

.prize_5_3,
.prize_10_3 {
    animation: gif2 0.4s ease-in 1.2s forwards;
}

.prize_5_4,
.prize_10_4 {
    animation: gif2 0.4s ease-in 1.6s forwards;
}

.prize_10_5 {
    animation: gif2 0.4s ease-in 2s forwards;
}

// 10个第三行
@keyframes gif3 {
    100% {
        opacity: 1;
        top: 453px;
    }
}

.prize_10_6 {
    animation: gif3 0.4s ease-in 2.4s forwards;
}

.prize_10_7 {
    animation: gif3 0.4s ease-in 2.8s forwards;
}

.prize_10_8 {
    animation: gif3 0.4s ease-in 3.2s forwards;
}

.prize_10_9 {
    animation: gif9 0.4s ease-in 3.6s forwards;
    @keyframes gif9 {
        100% {
            opacity: 1;
            top: 612px;
        }
    }
}

效果图:

image.png

image.png

image.png

image.png

<template>
    <view class="lottery ">
        <view class="content" :style="{'margin-top':contentTop+'px'}">
            <view class="item flex-column-center" :style="{
                    width: imageWidth + 'px',
                    height: imageHeight+ 'px',
                    left: item.left,
                    opacity: 0
                }" :class="'prize_' + prizes.length + '_' + index" v-for="(item, index) in prizes" :key="index">
                <view :style="{ background: colors[item.lottery_id] ?colors[item.lottery_id].bgcolor :''}"
                    class="tag flex-center" @click="categoryChange(item.lottery_id)">
                    <view :style="{
                            background: colors[item.lottery_id]?colors[item.lottery_id].color:'',
                            '-webkit-background-clip': 'text',
                            '-webkit-text-fill-color': 'transparent'
                        }" class="tag-name">
                        {{ item.lottery_name }}
                    </view>
                </view>
                <view class="info text-center flex-center" :style="{
                    height:imageHeight+'px',
                    background: 'url('+colors[item.lottery_id].bgUrl+') '+positionFormat(item.lottery_id).left+'px '+positionFormat(item.lottery_id).top+'px/ '+(imageWidth+positionFormat(item.lottery_id).width)+'px '+(imageHeight+positionFormat(item.lottery_id).height)+'px no-repeat'
                    }">
                    <view class="box"
                        :style="{width: 'calc(100% - '+positions[prizes.length].padding+'rpx)',height: 'calc(100% - '+positions[prizes.length].padding+'rpx)','border-radius':positions[prizes.length].radius+'rpx'}">
                        <view :style="{ height: imgHeight }" class="img flex-center">
                            <image :src="item.thumbnail_image" mode="aspectFit"></image>
                        </view>
                        <view class="px-2">
                            <view class="font-size-12 text-ellipsis">{{ item.box_name }}</view>
                            <view class="price text-ellipsis">¥{{ Number(item.price).toFixed(0) }}</view>
                        </view>
                    </view>
                </view>
            </view>
        </view>
    </view>
</template>

<script>
    export default {
        data() {
            return {
                colors:{
                    1: {
                        bgcolor: 'rgba(32, 107, 81, 0.2)',
                        color: '-webkit-linear-gradient(0deg, #BAFDA5, #6DEFD1)',
                        borderColor: 'linear-gradient(135deg,#BAFDA5, #6DEFD1)',
                        bgUrl: '图片'
                    },
                    2: {
                        bgcolor: 'rgba(144, 76, 156, 0.2)',
                        color: '-webkit-linear-gradient(0deg, #FFC8FF, #A071EB)',
                        borderColor: 'linear-gradient(135deg,#FFC8FF,#A071EB)',
                        bgUrl: '图片'
                    },
                    3: {
                        bgcolor: 'rgba(60, 110, 141, 0.2)',
                        color: '-webkit-linear-gradient(0deg, #B8FFFF, #228190)',
                        borderColor: 'linear-gradient(135deg,#228190, #B8FFFF)',
                        bgUrl: '图片'
                    },
                    4: {
                        bgcolor: 'rgba(143, 127, 79, 0.2)',
                        color: '-webkit-linear-gradient(0deg, #FFFBE9, #FFE961)',
                        borderColor: 'linear-gradient(135deg,#FFE961, #FFDBAD)',
                        bgUrl: '图片'
                    }
                },
                positions: {
                    '1': {
                        left: -1,
                        top: 2,
                        width: 5,
                        height: -11,
                        padding: 184,
                        radius: 26,
                        margin: 370
                    },
                    '3': {
                        left: -8,
                        top: -5,
                        width: 18,
                        height: 4,
                        padding: 134,
                        radius: 24,
                        margin: 580
                    },
                    '5': {
                        left: 0,
                        top: 2,
                        width: 1,
                        height: -8,
                        padding: 124,
                        radius: 16,
                        margin: 510
                    },
                    '10': {
                        left: 12,
                        top: 11,
                        width: -23,
                        height: -25,
                        padding: 124,
                        radius: 14,
                        margin: 450
                    }
                },
                prizes: [],
                contentTop: 0,
                imageWidth: 0,
                imageHeight: 0,
                totalHeight: 0,
                imgHeight: '70%',
                isPng: true,
                newLine: false
            }
        },
        mounted() {
            this.initImgHeight();
            let info = uni.getSystemInfoSync();
            const contentTop = ((info.windowHeight- this.positions[this.prizes.length].margin) / 2)
            this.contentTop = contentTop > 85 ? contentTop : 85
        },
        updated() {
            this.initImgHeight();
        },
        onUnload() {
            uni.setStorageSync('taskIng', false)
        },
        methods: {
            initImgHeight() {
                if (0 === this.imageWidth) {
                    uni.createSelectorQuery()
                        .in(this)
                        .select('.lottery')
                        .boundingClientRect(data => {
                            if (data) {
                                const widthRatio = 1 === this.prizes.length ? 0.46 : (3 === this.prizes.length ?
                                    0.35 : (5 === this.prizes.length ? 0.26 : 0.18));
                                this.imageWidth = (data.width * widthRatio);
                                this.imageHeight = (this.imageWidth / 0.82) + 12 + 50;
                                this.imageWidth = this.imageWidth + 50;
                                this.init()
                            }
                        })
                        .exec();
                }
            },
            init() {
                if (1 === this.prizes.length) {
                    this.imgHeight = '78%'
                    this.prizes = this.prizes.map((item, index) => {
                        item.width = '46%'
                        if (0 === index) {
                            item.left = 'calc(27% - 50rpx)'
                        }
                        return item
                    })
                }
                if (3 === this.prizes.length) {
                    this.imgHeight = '72%'
                    this.prizes = this.prizes.map((item, index) => {
                        item.width = '35%'
                        if (0 === index) {
                            item.left = 'calc(12% - 50rpx)'
                        }
                        if (1 === index) {
                            item.left = 'calc(53% - 50rpx)'
                        }
                        if (2 === index) {
                            item.left = "calc(32.5% - 50rpx)"
                        }
                        return item
                    })
                } else if (5 === this.prizes.length) {
                    this.imgHeight = '65%'
                    this.prizes = this.prizes.map((item, index) => {
                        item.width = '26%'
                        if (0 === index) {
                            item.left = 'calc(8% - 50rpx)'
                        }
                        if (1 === index) {
                            item.left = 'calc(37% - 50rpx)'
                        }
                        if (2 === index) {
                            item.left = 'calc(66% - 50rpx)'
                        }
                        if (3 === index) {
                            item.left = 'calc(22.5% - 50rpx)'
                        }
                        if (4 === index) {
                            item.left = 'calc(51.5% - 50rpx)'
                        }
                        return item
                    })
                } else if (10 === this.prizes.length) {
                    this.imgHeight = '54%'
                    this.prizes = this.prizes.map((item, index) => {
                        item.width = '18%'
                        if (0 === index || 5 === index) {
                            item.left = 'calc(4% - 50rpx)'
                        }
                        if (1 === index || 6 === index) {
                            item.left = 'calc(23% - 50rpx)'
                        }
                        if (2 === index || 7 === index) {
                            item.left = 'calc(42% - 50rpx)'
                        }
                        if (3 === index || 8 === index) {
                            item.left = 'calc(60% - 50rpx)'
                        }
                        if (4 === index || 9 === index) {
                            item.left = 'calc(79% - 50rpx)'
                        }
                        return item
                    })
                }
            },
            positionFormat(id) {
                const position = this.positions[this.prizes.length] || {};
                return position
            }
        }
    }
</script>


.item {
        position: absolute;
        margin-top: -400rpx;
        .tag {
            display: inline-block;
            padding: 5rpx 15rpx;
            position: absolute;
            top: 0;
            left: 50%;
            transform: translateX(-50%) skew(-20deg);

            &-name {
                line-height: 1;
                font-family: YouSheBiaoTiHei;
                transform: skew(20deg);
            }
        }

        .info {
            width: 100%;
            height: 100%;
            border-radius: 30rpx;

            .box {
                background: #fff;
                margin: 12rpx;
            }

            .img {
                width: 100%;
                height: 100%;
                border-radius: 28rpx 28rpx 0 0;

                image {
                    width: 60%;
                    height: 100%;
                }
            }

            .price {
                font-size: 30rpx;
                font-weight: bold;
                line-height: 1;
            }
        }
    }

    // 第一行
    @keyframes gif1 {
        100% {
            opacity: 1;
            margin-top: 0;
        }
    }

    .prize_1_0,
    .prize_3_0,
    .prize_5_0 {
        animation: gif1 0.4s ease-in forwards;
    }

    .prize_3_1,
    .prize_5_1 {
        animation: gif1 0.4s ease-in 0.4s forwards;
    }

    .prize_3_2 {
        animation: gif32 0.4s ease-in 0.8s forwards;

        // 3个第二行
        @keyframes gif32 {
            100% {
                opacity: 1;
                margin-top: 205px;
            }
        }
    }

    .prize_5_2 {
        animation: gif1 0.4s ease-in 0.8s forwards;
    }

    // 5个第二行
    @keyframes gif2 {
        100% {
            opacity: 1;
            margin-top: 170px;
        }
    }

    .prize_5_3 {
        animation: gif2 0.4s ease-in 1.2s forwards;
    }

    .prize_5_4 {
        animation: gif2 0.4s ease-in 1.6s forwards;
    }

    // 10个
    // 第一行
    @keyframes gif101 {
        100% {
            opacity: 1;
            margin-top: 15px;
        }
    }
    // 第三行
    @keyframes gif102 {
        100% {
            opacity: 1;
            margin-top: 170px;
        }
    }

    .prize_10_0 {
        animation: gif101 0.4s ease-in forwards;
    }

    .prize_10_1 {
        animation: gif101 0.4s ease-in 0.4s forwards;
    }

    .prize_10_2 {
        animation: gif101 0.4s ease-in 0.8s forwards;
    }

    .prize_10_3 {
        animation: gif101 0.4s ease-in 1.2s forwards;
    }

    .prize_10_4 {
        animation: gif101 0.4s ease-in 1.6s forwards;
    }

    .prize_10_5 {
        animation: gif102 0.4s ease-in 2s forwards;
    }

    .prize_10_6 {
        animation: gif102 0.4s ease-in 2.4s forwards;
    }

    .prize_10_7 {
        animation: gif102 0.4s ease-in 2.8s forwards;
    }

    .prize_10_8 {
        animation: gif102 0.4s ease-in 3.2s forwards;
    }

    .prize_10_9 {
        animation: gif102 0.4s ease-in 3.6s forwards;
    }

内容居中

效果图:

image.png