Taro+vue3 实现滑动列表 时切换电影

<template>
    <div class="movie-list-component">
        <view class="list-container">
            <scroll-view id="contentScroll" class="scroll-view" :scroll-with-animation="true" :scroll-left="scrollLeft"
                :scroll-x="true" style="width: 100%;" @scroll="onScroll" @touchstart="onTouchStart" @touchend="onTouchEnd">
                <div class="movie-item seat"></div>
                <view :data-id="item.id" @click="selectMovie" :id="`movieItem${item.id}`" class="movie-item"
                    :class="{ active: modelValue == item.id }" v-for="( item, index ) in  list " :key="index">
                    <div class="img-container">
                        <image class="img" :src="item?.image" alt="" />
                    </div>
                    <!-- <div class="point-container"></div> -->
                </view>
                <div class="movie-item seat1"></div>
            </scroll-view>
        </view>
    </div>
</template>
<script setup lang="ts">
import Taro from "@tarojs/taro";
import { onMounted, ref, reactive, toRefs, watch } from "vue";
const props = defineProps({
    // 子组件接收父组件传递过来的值
    list: {
        type: Array<any>,
        required: true,
    },
    modelValue: {
        type: Number,
        required: true,
    },
});
//使用父组件传递过来的值
const { list, modelValue } = toRefs(props);
const emit = defineEmits(["onchangeMovie"]);
const clientWidths = ref(0)
const isSwitchingMovie = ref(false)
onMounted(() => {

    list?.value.map((item, index) => {
        if (item.id === modelValue?.value) {
            list?.value.unshift(list?.value.splice(index, 1)[0]);
        }
    });

});
const scrollLeft = ref(0);
//选择电影
const selectMovie = (e) => {
    isSwitchingMovie.value = true; // 点击切换电影时设置为true
    let offsetLeft = e.currentTarget.offsetLeft;
    let { id } = e.currentTarget.dataset;
    if (!id) {
        id = list.value[0].id;
    }
    if (modelValue.value === id) {
        return;
    }
    emit("onchangeMovie", id);
    getRect(id, offsetLeft);
};
//滚动事件处理函数
const onScroll = (e) => {
    if (isSwitchingMovie.value) {
        return; // 如果处于切换电影状态,不执行滚动事件逻辑
    }
    requestAnimationFrame(() => {
        const contentScroll = Taro.createSelectorQuery();
        contentScroll.select("#contentScroll").boundingClientRect();
        contentScroll.exec((res) => {
            const clientWidth = res[0].width;
            clientWidths.value = clientWidth;
            // 执行其他逻辑
        });

        const { scrollLeft } = e.detail;
        const currentIndex = Math.round(scrollLeft / (clientWidths.value / 4));
        const index = currentIndex >= list.value.length ? list.value.length - 1 : currentIndex;
        const id = list.value[index]?.id;

        if (modelValue.value !== id) {
            emit("onchangeMovie", id);
        }
    });
};
// 触摸开始事件,用于标记点击切换电影状态开始
const onTouchStart = () => {
    isSwitchingMovie.value = true;
};

// 触摸结束事件,用于标记点击切换电影状态结束
const onTouchEnd = () => {

    isSwitchingMovie.value = false;

};
//计算电影item的偏移量
const getRect = async (id, offsetLeft) => {

    const eleId = `#movieItem${id}`;

    const contentScrollWidth: any = await getContentScrollWidth("#contentScroll");
    const query = Taro.createSelectorQuery();
    query.select(eleId).boundingClientRect();
    query.selectViewport().scrollOffset();
    query.exec(async (res) => {

        //获取item的宽度de 一半
        const subhalfwidth = res[0].width / 2;
        //需要scrollview 移动的距离是
        const juli = offsetLeft - contentScrollWidth / 2 + subhalfwidth;
        scrollLeft.value = juli;
    });
};
// 获取ScrollView的宽度
const getContentScrollWidth = (ele) => {
    return new Promise((resolve) => {
        const query = Taro.createSelectorQuery();
        query.select(ele).boundingClientRect();
        query.selectViewport().scrollOffset();
        query.exec((res) => {
            const width = res[0].width;
            resolve(width);
        });
    });
};
</script>
<style lang="scss">
.movie-list-component {
    display: flex;
    flex-direction: column;

    .list-container {
        display: flex;
        flex-direction: column;
        justify-content: center;
        height: 350px;

        .scroll-view {
            width: 100%;
            height: 320px;
            white-space: nowrap;
            position: relative;

            .movie-item {
                display: inline-block;
                position: relative;
                margin-left: 25px;
                // display: flex;
                // justify-content: center;
                // align-items: center;
                border-radius: 18px;
                // overflow: hidden;
                width: 146px;
                height: 218px;
                transition: width 0.8s;
                transition: height 0.8s;

                .img-container {
                    border-radius: 8px;
                    width: 100%;
                    height: 100%;
                    overflow: hidden;
                    position: relative;
                    z-index: 2;
                    // border: 5px #ffffff solid;

                    .img {
                        width: 100%;
                        height: 100%;
                    }
                }
            }

            .movie-item.active {
                // width: 180px !important;
                // height: 270px !important;
                transform: scale(1.1);
                transition: transform 0.8s ease;


                .img-container {
                    border-radius: 10px;
                    border: 3px #ffffff solid;
                }

                // .point-container {
                //     z-index: 1;
                //     height: 30px;
                //     width: 30px;
                //     background: #5232B7;
                //     // border-radius: 7px;
                //     position: absolute;
                //     bottom: -15px;
                //     left: 50%;
                //     margin-left: -15px;
                //     transform: rotate(45deg);
                // }
            }

            .seat {
                display: inline-block;
                width: 50%;
                height: 290px;
                margin-left: -100px;
            }

            .seat1 {
                display: inline-block;
                width: 36%;
                height: 290px;
                // margin-left: 50px;
            }
        }
    }
} 
</style> 

以上代码是滑动的组件 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值