<template> <v-tabs class="tabs" v-model="tabRecom" color="white" bg-color="#eeeeee" style="margin-top: 40px" slider-color="blue-lighten-1" selected-class="active" v-if="recommendImages[0] !== null && !isMobile()" > <v-tab :value="1">Best Sellers</v-tab> <!-- <v-tab :value="3">商品百科</v-tab> --> </v-tabs> <div id="image-container" v-if="recommendImages[0] !== null && !isMobile()"> <div class="recommend-left-box"> <v-img src="https://m-canrd.oss-cn-shenzhen.aliyuncs.com/crmebimage/public/maintain/2024/09/14/76c987e13a334be481a346c19c2284f3qy4tjnxps7.png" alt="往左移" class="recommend-img-left" @click="toggleRowLeft" /> </div> <div class="image-row" id="row1"> <!-- <img v-for="(imageObj, index) in recommendImages.slice(0, 5)" :key="'row1-' + index" :src="imageObj[0]?.url" :alt="'Image ' + (index + 1)" style="margin: 0 5px; width: 200px; height: 200px" /> --> <div v-for="(imageObj, index) in recommendImages" :key="'row1-' + index" class="imageTotal" > <a v-if="imageObj" :href="imageObj[0]?.productUrl" target="_blank"> <img :src="imageObj[0]?.url" :alt="'Image ' + (index + 1)" class="item-imgHot" /> <span class="image-name"> {{ imageObj[0]?.name }} </span> </a> <div v-else class="image-substitute"></div> </div> </div> <div class="recommend-right-box"> <v-img src="https://m-canrd.oss-cn-shenzhen.aliyuncs.com/crmebimage/public/maintain/2024/09/14/b5daa0a8f2f140f5b406e984c730a453iznzlekysg.png" alt="往右移" class="recommend-img-right" @click="toggleRowRight" /> </div> </div> <div style="padding-left: 16px; padding-right: 16px"> <v-tabs class="tabs2" ref="tabs2" v-model="tabRecom" style="margin-top: 25px; margin-bottom: 20px; width: 100%" color="white" bg-color="#eeeeee" slider-color="blue-lighten-1" selected-class="active" v-if="isMobile()" > <v-tab :value="1">Best Sellers</v-tab> <!-- <v-tab :value="3">商品百科</v-tab> --> </v-tabs> <div class="tw-text-center" v-if="hotLoadingMobile && isMobile()"> <v-progress-circular color="blue-lighten-2" indeterminate size="64" class="tw-m-auto" ></v-progress-circular> </div> <v-item-group multiple v-if="isMobile()"> <v-row v-if="!hotLoadingMobile"> <v-col v-for="(item, i) in recommendImagesMobile" :key="i" cols="6" lg="3" md="4" sm="6" > <div v-if="item !== null"> <v-card :elevation="4" class="mx-auto" :href="item[0].productUrl"> <v-img :src="item[0].url" :alt="item[0].name" eager class="d-block" /> <v-card-text class="tw-text-left font-weight-medium title"> <h4 class="clamp-text">{{ item[0].name }}</h4> </v-card-text> </v-card> </div> </v-col> </v-row> </v-item-group> <v-row v-if="isMobile()"> <v-col> <v-pagination :size="isMobile() ? 'small' : 'default'" v-if="hotTotalMobile" v-model="currentIndexMobile" @update:modelValue="toggleRowMobile" :length="hotLength" rounded="0" class="tw-float-right tw-mt-[32px]" total-visible="5" ></v-pagination></v-col ></v-row> </div> </template> <script setup lang="ts"> import { computed, onMounted, reactive, ref } from "vue"; import { isMobile } from "../utils"; import { useRoute } from "vue-router"; const route = useRoute(); // 获取路由信息 const maxPage = ref(1); const maxPageMobile = ref(1); const tabRecom = ref(); const recommendList = ref({}); const recommendImages = ref({}); const currentIndex = ref(1); const hotLoading = ref(false); const hotTotal = ref(10); const isOrNotMobile = isMobile(); const recommendListMobile = ref({}); const recommendImagesMobile = ref({}); const currentIndexMobile = ref(1); const hotLoadingMobile = ref(false); const hotTotalMobile = ref(10); const loadHotProducts = async () => { hotLoading.value = true; let { data: hotProducts } = await useAsyncData( "hotProducts", () => $fetch("/shop/product/hotProducts", { method: "GET", params: { pageNo: currentIndex.value, pageSize: 5, }, }), { server: true, // 仅在服务器端获取数据 } ); hotTotal.value = hotProducts.value.data.total; recommendList.value = hotProducts.value.data.records; maxPage.value = hotProducts.value.data.pages; // recommendImages.value = recommendList.value.slice(0, 10).map((item) => { recommendImages.value = Array.from({ length: 5 }).map((_, index) => { const item = recommendList.value[index]; if (!item) { return null; } // 检查 productimageliststore 是否为字符串格式,如果是,则尝试解析 if (typeof item.productimageliststore === "string") { try { item.productimageliststore = JSON.parse(item.productimageliststore); } catch (error) { item.productimageliststore = []; // 解析失败时,设置为空数组 } } const ree = (item.productimageliststore = item?.productimageliststore.map( (productItem: ProductImage) => ({ ...productItem, // url: `http://112.74.45.244:8100/api/show/image?fileKey=${item.fileKey}`, url: `https://www.canrud.com/api/show/image?fileKey=${productItem.fileKey}&psize=p256`, name: item.name, productUrl: `https://www.canrud.com/products/detail/${item.id}`, }) )); return ree; }); hotLoading.value = false; }; const toggleRowLeft = () => { if (currentIndex.value !== 1) { currentIndex.value--; } else if (currentIndex.value == 1) { currentIndex.value = maxPage.value; } startTimer(); }; let intervalId: any; const toggleRowRight = () => { if (currentIndex.value < maxPage.value) { currentIndex.value++; } else if (currentIndex.value == maxPage.value) { currentIndex.value = 1; } startTimer(); }; const startTimer = () => { // 清除已有计时器,防止重复 clearInterval(intervalId); intervalId = setInterval(() => { toggleRowRight(); }, 5000); // 每6秒调用一次 }; onMounted(() => { startTimer(); }); const toggleRowMobile = (value: number) => { currentIndexMobile.value = value; }; const { width } = useDisplay(); const firstIndex = ref(true); watch(currentIndex, (newIndex) => { loadHotProducts(); // Call loadHotProducts when currentIndex changes }); const loadHotProductsMobile = async () => { hotLoadingMobile.value = true; let { data: hotProductsMobile } = await useAsyncData( "hotProducts", () => $fetch("/shop/product/hotProducts", { method: "GET", params: { pageNo: currentIndexMobile.value, pageSize: 4, }, }), { server: true, // 仅在服务器端获取数据 } ); hotTotalMobile.value = hotProductsMobile.value.data.total; recommendListMobile.value = hotProductsMobile.value.data.records; maxPageMobile.value = hotProductsMobile.value.data.pages; // recommendImages.value = recommendList.value.slice(0, 10).map((item) => { recommendImagesMobile.value = Array.from({ length: 4 }).map((_, index) => { const item = recommendListMobile.value[index]; if (!item) { return null; } // 检查 productimageliststore 是否为字符串格式,如果是,则尝试解析 if (typeof item.productimageliststore === "string") { try { item.productimageliststore = JSON.parse(item.productimageliststore); } catch (error) { item.productimageliststore = []; // 解析失败时,设置为空数组 } } const ree = (item.productimageliststore = item?.productimageliststore.map( (productItem: ProductImage) => ({ ...productItem, // url: `http://112.74.45.244:8100/api/show/image?fileKey=${item.fileKey}`, url: `https://www.canrud.com/api/show/image?fileKey=${productItem.fileKey}&psize=p256`, name: item.name, productUrl: `https://www.canrud.com/products/detail/${item.id}`, }) )); return ree; }); hotLoadingMobile.value = false; }; watch(currentIndexMobile, (newIndex) => { loadHotProductsMobile(); // Call loadHotProducts when currentIndex changes }); watchEffect(async () => { console.log("Current route:", route.fullPath, "Width:", width.value); if (firstIndex.value) { if (width.value > 600) { await loadHotProducts(); } else { await loadHotProductsMobile(); } } }); // Initial load of hot products const hotLength = computed(() => hotTotalMobile.value ? Math.ceil(hotTotalMobile.value / 4) : 0 ); </script> <style lang="scss" scoped> @media screen and (min-width: 1537px) { .tabs { border-bottom: 2px solid #1f88e5; margin: 10px auto 100px; width: 93%; } } @media screen and (max-width: 1536px) and (min-width: 1281px) { .tabs { border-bottom: 2px solid #1f88e5; margin: 10px auto 20px; width: 82%; } } @media screen and (max-width: 1280px) { .tabs { border-bottom: 2px solid #1f88e5; margin: 10px auto 0px; width: 88%; } } .active { background-color: #1086e8; } /* #image-container { display: flex; align-items: center; justify-content: center; height: 320px; margin: 10px auto 50px; width: 80%; } */ @media screen and (min-width: 1537px) { #image-container { display: flex; align-items: center; justify-content: center; height: 320px; margin: 10px auto 50px; width: 96%; } } @media screen and (max-width: 1536px) and (min-width: 1281px) { #image-container { display: flex; align-items: center; justify-content: center; height: 240px; margin: 10px auto 0px; width: 80%; } } @media screen and (max-width: 1280px) { #image-container { display: flex; align-items: center; justify-content: center; height: 260px; margin: 10px auto 0px; width: 90%; } } .image-row { display: flex; height: 305px; } @media screen and (min-width: 1537px) { .image-row { display: flex; height: 305px; } } @media screen and (max-width: 1536px) and (min-width: 1281px) { .image-row { display: flex; height: 245px; } } @media screen and (max-width: 1280px) { .image-row { display: flex; height: 220px; } } @media screen and (min-width: 1537px) { .imageTotal { display: inline-block; margin: 0 5px; text-align: center; width: 315px; } } @media screen and (max-width: 1536px) and (min-width: 1281px) { .imageTotal { display: inline-block; margin: 0 5px; text-align: center; width: 210px; } } @media screen and (max-width: 1280px) { .imageTotal { display: inline-block; margin: 0 5px; text-align: center; width: 185px; } } @media screen and (min-width: 1537px) { .image-row img { width: 240px; height: 240px; } } @media screen and (max-width: 1536px) and (min-width: 1281px) { .image-row img { width: 180px; height: 180px; } } @media screen and (min-width: 1537px) { .image-row .image-substitute { width: 200px; height: 200px; } } @media screen and (max-width: 1536px) and (min-width: 1281px) { .image-row .image-substitute { width: 200px; height: 200px; } } @media screen and (max-width: 1280px) { .image-row .image-substitute { width: 185px; height: 185px; } } @media screen and (max-width: 1280px) { .image-row img { width: 160px; height: 160px; margin-left: 10px; } } @media screen and (min-width: 1537px) { .image-name { display: -webkit-box; /* Enables multi-line text handling */ -webkit-box-orient: vertical; /* Defines the vertical orientation of the box */ -webkit-line-clamp: 3; /* Limits the text to 3 lines */ overflow: hidden; /* Hides the overflowed text */ text-overflow: ellipsis; /* Adds an ellipsis when the text overflows */ margin-top: 5px; font-size: 16px; width: 180px; color: #555; text-align: center; /* Centers the text horizontally */ margin-left: 50px; } } @media screen and (max-width: 1536px) and (min-width: 1281px) { .image-name { display: -webkit-box; /* Enables multi-line text handling */ -webkit-box-orient: vertical; /* Defines the vertical orientation of the box */ -webkit-line-clamp: 3; /* Limits the text to 3 lines */ overflow: hidden; /* Hides the overflowed text */ text-overflow: ellipsis; /* Adds an ellipsis when the text overflows */ margin-top: 5px; font-size: 16px; width: 180px; color: #555; text-align: center; /* Centers the text horizontally */ margin-left: 10px; } } @media screen and (max-width: 1280px) { .image-name { display: -webkit-box; /* Enables multi-line text handling */ -webkit-box-orient: vertical; /* Defines the vertical orientation of the box */ -webkit-line-clamp: 3; /* Limits the text to 3 lines */ overflow: hidden; /* Hides the overflowed text */ text-overflow: ellipsis; /* Adds an ellipsis when the text overflows */ margin-top: 5px; font-size: 16px; width: 180px; color: #555; text-align: center; /* Centers the text horizontally */ margin-left: 5px; } } button .recommendButton { margin: 0 0px; cursor: pointer; } .recommend-left-box { } .recommend-img-left { width: 26px; height: 27px; margin-right: 40px; } .recommend-img-left:hover { cursor: pointer; } .recommend-right-box { } .recommend-img-right { width: 26px; height: 27px; margin-left: 40px; } .recommend-img-right:hover { cursor: pointer; } .image-grid { padding: 16px; } .v-card { transition: all 0.3s ease-in-out; } .clamp-text { display: -webkit-box; /* 使用弹性盒子 */ -webkit-box-orient: vertical; /* 设置为垂直方向 */ -webkit-line-clamp: 3; /* 限制最多显示3行 */ overflow: hidden; /* 隐藏多余内容 */ text-overflow: ellipsis; /* 添加省略号 */ white-space: normal; /* 允许换行 */ line-height: 1.5em; /* 设置每行的高度 */ min-height: calc(3 * 1.5em); /* 确保最小高度为3行 */ } </style>