card滑动效果

 

image

image

 

<template>
    <view class="member-benefits">
        <!-- 卡片滑动容器 -->
        <view class="card-slider" :style="{
            background: currentSliderGradient,
            transition: 'background 0.5s ease'  // 渐变背景平滑过渡
        }">
            <view class="title">表头</view>
            <view class="slider-track" :style="{ transform: `translateX(-${currentIndex * (110 - overlapPercent)}%)` }"
                @touchstart="handleTouchStart" @touchmove="handleTouchMove" @touchend="handleTouchEnd"
                @touchcancel="handleTouchEnd">
                <view v-for="(level, index) in levels" :key="level.level" class="benefit-card" :class="{
                    'active-card': index === currentIndex,
                    'prev-card': index === currentIndex - 1,
                    'next-card': index === currentIndex + 1
                }" :style="{ background: currentCardSliderGradient }">
                    <view class="slider-stau">{{ level.status }}</view>
                    <view class="slider-con">
                        <view>
                            <h2 class="benefit-title" :style="{ color: currentLevelData.testCol }">
                                {{ level.level }}
                            </h2>
                            <p class="benefit-desc1" :style="{ color: currentLevelData.testCol }">
                                匹配 <text :style="{ color: currentLevelData.pricColor }">{{ level.matchTime }}</text>
                                服务期 <text :style="{ color: currentLevelData.pricColor }">{{ level.cycle }}</text>

                            </p>
                        </view>
                        <image class="slider-con_img" src="https://qiniu.5ug.top/alabo/dev_uploads/lan/logo.png" />
                    </view>
                    <p class="benefit-desc" :style="{ color: currentLevelData.testCol }">
                        权益 <text :style="{ color: currentLevelData.pricColor }">{{ level.price }}</text>
                        券 <text :style="{ color: currentLevelData.pricColor }">{{ level.ticket }}</text>
                    </p>
                </view>
            </view>
            <!-- 提示语 -->
            <view class="tips" v-if="currentLevelData.tips1" :style="{ background: currentLevelData.tipsBg }">
                <view class="tips-con">
                    <view class="tips-tips1">{{ currentLevelData.tips1 }}</view>
                    <view>{{ currentLevelData.tips2 }}
                        <text style="color:#fdca5c">{{ currentLevelData.profit }}</text>
                    </view>
                </view>
                <image class="tips-img" src="https://qiniu.5ug.top/alabo/dev_uploads/lan/logo.png" />
            </view>
        </view>

        <view class="upgrade-con">
            <view class="upgrade-tips"> 轮播文字 </view>
            <view class="upgrade-section">
                <h3 class="upgrade-title">title</h3>
                <ul class="upgrade-tasks">
                    <!-- <li v-for="(task, index) in currentLevelData.upgrade.tasks" :key="index" class="upgrade-tasks_li"> -->
                    <li v-for="(task, index) in tasks" :key="index" class="upgrade-tasks_li">
                        <view class="upgrade-tasks_li_t">
                            <img :src="task.icon" alt="任务图标" class="upgrade-tasks_li_ticon" />
                            <span>{{ task.text }}</span>
                        </view>
                        <view v-for="(dItem, dIndex) in task.device" :key="dIndex" class="upgrade-device">
                            <text class="upgrade-device_dian">・</text>
                            text1{{ dItem.v1 }}text2{{ dItem.examine }},text3{{ dItem.discount }}
                        </view>
                    </li>
                </ul>

            </view>
        </view>
        <view v-if="currentLevelData.button" class="upgrade-button">
            ¥ price{{ currentLevelData.button.price1 }}元+券{{ currentLevelData.button.price2 }}元 {{
                currentLevelData.button.text
            }}
        </view>
    </view>
</template>

<script>
export default {
    data() {
        return {
            currentIndex: 0, // 当前卡片索引
            startX: 0, // 触摸起始X坐标
            moveX: 0, // 触摸移动X坐标
            isDragging: false, // 是否正在拖动
            overlapPercent: 20, // 卡片重叠百分比(控制前后卡片显示范围)
            levels: [
                {
                    level: "title1",
                    cardSliderGradient: 'linear-gradient(to right, #f5fcfc, #d2e0e7, #d5e6ec, #a3bac6)',
                    sliderGradient: "linear-gradient(to bottom, #7d979e 0%, #446f7d 100%)",
                    status: '未达成',
                    matchTime: '1-7天',
                    cycle: '5天', 
                    price: '1000元',
                    ticket: '100元',
                    pricColor: '#446f7d',
                    testCol: "#88939b",
                    button: { price1: 1000, price2: 100, text: "直接开通" },
                },
                {
                    level: "title2",
                    cardSliderGradient: 'linear-gradient(to right, #fffbf1, #fbdcb0, #fae9d1, #fab35d)',
                    sliderGradient: "linear-gradient(to bottom, #ca834a 0%, #8e5324 100%)",
                    status: '未达成',
                    matchTime: '1-7天',
                    cycle: '6天',
                    price: '3000元', 
                    ticket: '100元',
                    pricColor: '#8e5324',
                    testCol: "#b78d64",
                    button: { price1: 3000, price2: 100, text: "直接开通" },
                },
            ],
            tasks: [
                {
                    icon: "https://qiniu.5ug.top/alabo/dev_uploads/lan/logo.png",
                    text: "title5",
                    device: [
                        { v1: '《等级1》', examine: '8个任务', discount: '70折' },
                        { v1: '《等级2》', examine: '6个任务', discount: '78折' },
                    ]
                },
                {
                    icon: "https://qiniu.5ug.top/alabo/dev_uploads/lan/logo.png",
                    text: "title6",
                    device: [
                        { v1: '《任务1》', examine: '三个四星', discount: '90折' },
                        { v1: '《任务2》', examine: '三个三星', discount: '92折' },
                    ]
                },
            ],
        };
    },
    computed: {
        currentSliderGradient() {
            return this.levels[this.currentIndex].sliderGradient || "linear-gradient(135deg, #ee631c 0%, #f89e53 100%)";
        },
        currentCardSliderGradient() {
            return this.levels[this.currentIndex].cardSliderGradient || "";
        },
        currentLevelData() {
            return this.levels[this.currentIndex] || {};
        }
    },
    methods: {
        handleTouchStart(e) {
            this.isDragging = true;
            this.startX = e.touches[0].clientX;
        },
        handleTouchMove(e) {
            if (!this.isDragging) return;
            this.moveX = e.touches[0].clientX;
        },
        handleTouchEnd() {
            if (!this.isDragging) return;

            const diffX = this.moveX - this.startX;
            const threshold = 50; // 滑动触发阈值
            const cardWidthRatio = 100 - this.overlapPercent + 10;

            if (diffX > threshold && this.currentIndex > 0) {
                this.currentIndex--;
            } else if (diffX < -threshold && this.currentIndex < this.levels.length - 1) {
                this.currentIndex++;
            }

            this.isDragging = false;
            this.startX = 0;
            this.moveX = 0;
        },
    },
};
</script>

<style scoped>
@import './two.scss';
</style>

  

.title {
    position: absolute;
    top: 25rpx;
    left: 42%;
    color: #fff;
    font-size: 32rpx;
}

.member-benefits {
    font-family: "Microsoft Yahei", sans-serif;
    max-width: 600px;
}

/* 滑动容器核心样式 */
.card-slider {
    position: relative;
    overflow: hidden;
    padding: 250rpx 20rpx 40rpx 20rpx;
}

.slider-track {
    display: flex;
    /* 核心动画:位置变化时平滑过渡 */
    transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
    will-change: transform;
    /* 告诉浏览器提前优化渲染 */
}

/* 卡片基础样式 */
.benefit-card {
    flex-shrink: 0;
    width: 90%;
    margin: 0 1%;
    border-radius: 18px;
    /* padding: 20px; */
    box-shadow: 0 4px 18px rgba(0, 0, 0, 0.08);
    transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
    /* 所有属性变化均有动画 */
    will-change: transform, opacity, box-shadow;
}

/* 当前激活卡片样式(放大+增强阴影) */
.benefit-card.active-card {
    transform: scale(1);
    opacity: 1;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
    z-index: 3;
    /* 层级最高,覆盖前后卡片 */
}

/* 前一张卡片样式(缩小+半透明) */
.benefit-card.prev-card {
    transform: scale(0.9) translateX(-5%);
    /* 缩小并向右偏移 */
    /* opacity: 0.7; */
    z-index: 2;
}

/* 后一张卡片样式(缩小+半透明) */
.benefit-card.next-card {
    transform: scale(0.9) translateX(-5%);
    /* 缩小并向左偏移 */
    /* opacity: 0.7; */
    z-index: 2;
}

/* 非相邻卡片样式(进一步缩小+降低透明度) */
.benefit-card:not(.active-card):not(.prev-card):not(.next-card) {
    transform: scale(0.8);
    opacity: 0.5;
    z-index: 1;
}

/* 卡片内部元素样式 */
.benefit-badge {
    width: 70px;
    height: 70px;
    margin-bottom: 12px;
    transition: transform 0.3s ease;
}

.active-card .benefit-badge {
    transform: scale(1.1);
    /* 当前卡片徽章轻微放大 */
}

.benefit-title {
    font-size: 22px;
    margin-bottom: 10px;
    font-weight: 600;
}

.slider-stau {
    display: inline;
    color: #fff;
    padding: 8rpx 18rpx;
    font-size: 20rpx;
    background-color: #b8c3c2;
    border-radius: 18rpx 0 20rpx 0;
}

.slider-con {
    display: flex;
    padding: 30rpx;
}

.benefit-desc1 {
    font-size: 15px;
    color: #555;
    margin-bottom: 6px;
}

.benefit-desc {
    font-size: 15px;
    color: #555;
    margin-bottom: 6px;
    padding: 0 30rpx 20rpx 30rpx;
}

.slider-con_img {
    width: 200rpx;
    height: 120rpx;
    margin: auto;
}

/* 其他区域样式保持不变 */
.tips {
    padding: 8px;
    border-radius: 4px;
    margin-top: 12px;
    color: #fffafd;
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 30rpx;
}

.tips-con {
    display: flex;
    flex-direction: column;
}

.tips-tips1 {
    font-size: 20rpx;
    margin-bottom: 15rpx;
}

.tips-img {
    width: 40px;
    height: 24px;
}

.upgrade-con {
    background-color: #f8f8f8;
    border-radius: 30rpx 30rpx 0 0;
    margin-top: -20rpx;
    padding-top: 30rpx;
    position: relative;
}

.upgrade-tips {
    background-color: #f9e8df;
    color: #f56f29;
    padding: 8px;
    margin: 0 20rpx;
    border-radius: 4px;
    margin-bottom: 16px;
}

.upgrade-section {
    max-height: 46vh;
    overflow: scroll;
    background-color: #fff;
    border-radius: 8px;
    padding: 32rpx 32rpx 0 32rpx;
    margin: 0 20rpx;
    /* box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); */
}

.upgrade-title {
    font-size: 16px;
    margin-bottom: 8px;
    width: 260rpx;
}

.upgrade-tasks {
    list-style: none;
    padding: 0;
}

.upgrade-tasks_li {
    margin-bottom: 15px;
}

.upgrade-tasks_li_t {
    display: flex;
    align-items: center;
}


.upgrade-tasks_li_ticon {
    width: 40px;
    height: 24px;
    margin-right: 8px;
}

.upgrade-device {
    margin-left: 70rpx;
    display: flex;
    /* align-items: center */
    color: #a6a6aa;
    font-size: 25rpx;
}

.upgrade-device_dian {
    font-size: 40rpx;
}

.upgrade-button {
    width: 83%;
    margin: 20rpx auto 0 auto;
    background-color: #722ed1;
    color: #fff;
    padding: 10px;
    border-radius: 4px;
    text-align: center;
    cursor: pointer;
}

 

posted @ 2025-10-14 11:33  挽你手  阅读(6)  评论(0)    收藏  举报