refactor(components): migrate to vant and tailwind, clean up

- refactor TopNavBar: replace legacy flex classes with Tailwind utilities, swap uni-icons to Vant van-icon, remove unused status bar placeholder and old SCSS classes
- overhaul ImageSwiper: replace custom swiper with Vant Swipe components, migrate all SCSS styles to inline Tailwind classes, remove unused znicons font assets and delete old stylesheet
- clean up goods page: remove unused TopNavBar import and template, remove dead navOpacity scroll logic, remove local style import
This commit is contained in:
DEV_DSW
2026-05-28 09:35:03 +08:00
parent b98687bebc
commit 4edf19ce0c
5 changed files with 29 additions and 140 deletions

View File

@@ -1,33 +1,32 @@
<template>
<div class="image-swiper">
<swiper class="swiper-box" :style="swiperStyle" :autoplay="false" :interval="3000" :duration="1000"
:current="active" @change="handleSwiperChange">
<swiper-item class="swiper-item" v-for="(item, index) in thumbnails" :key="index">
<img class="swiper-item-image" :src="item.photoUrl" mode="aspectFill">
</swiper-item>
</swiper>
<div class="relative w-full">
<van-swipe class="overflow-hidden" :style="swiperStyle" @change="handleSwiperChange">
<van-swipe-item class="swiper-item" v-for="(item, index) in thumbnails" :key="index">
<img class="w-full h-full" :src="item.photoUrl">
</van-swipe-item>
</van-swipe>
<!-- 缩略图部分 -->
<div v-if="showThumbnails && thumbnails.length > 0" class="thumbnail-box" :style="thumbnailBoxStyle">
<div class="thumbnail-scroll" scroll-x="true" :scroll-left="scrollLeft" :scroll-with-animation="true"
show-scrollbar="false">
<div class="thumbnail-list" v-if="thumbnails.length > 1">
<div v-if="showThumbnails && thumbnails.length"
class="absolute left-[12px] right-[12px] flex items-end flex-row flex-nowrap" :style="thumbnailBoxStyle">
<div class="flex-auto h-full whitespace-nowrap" scroll-x="true" :scroll-left="scrollLeft"
:scroll-with-animation="true" show-scrollbar="false">
<div class="flex items-center gap-[10px]" v-if="thumbnails.length > 1">
<div v-for="(thumb, index) in thumbnails" :key="index"
:class="['thumbnail-item', { active: index === active }]" :id="`thumbnail-${index}`"
@click="handleThumbnailClick(index)">
<img class="thumbnail-image" :src="thumb.photoUrl" mode="aspectFill">
:class="['shrink-0 text-center', index === active && 'border-2 border-white border-solid']"
:id="`thumbnail-${index}`" @click="handleThumbnailClick(index)">
<img class="w-[36px] h-[36px] rounded-card border border-[#171717] border-solid" :src="thumb.photoUrl">
</div>
</div>
</div>
<div class="custom-indicator" @click="handlePredivClick">
<uni-icons fontFamily="znicons" size="10" color="#fff">{{
zniconsMap["zn-camera"]
}}</uni-icons>
<span class="custom-indicator-text">{{ thumbnails.length }}</span>
<uni-icons fontFamily="znicons" size="10" color="#fff">{{
zniconsMap["zn-nav-arrow-right"]
}}</uni-icons>
<div class="ml-[12px] bg-[rgba(0,0,0,0.5)] rounded-[50px] p-[0_6px_4px_8px] flex-auto shrink-0 whitespace-nowrap"
@click="handlePredivClick">
<van-icon name="arrow-left" size="10" color="#fff"></van-icon>
<span class="mx-[4px] text-[10px] text-white align-center">
{{ thumbnails.length }}
</span>
<van-icon name="arrow-right" size="10" color="#fff"></van-icon>
</div>
</div>
</div>
@@ -35,8 +34,8 @@
<script setup>
import { ref, computed, nextTick } from "vue";
import { zniconsMap } from "@/assets/fonts/znicons";
import { usePictureStore } from "@/store";
const pictureStore = usePictureStore();
// Props定义
@@ -144,7 +143,3 @@ const handlePredivClick = () => {
});
};
</script>
<style scoped lang="scss">
@import "./styles/index.scss";
</style>

View File

@@ -1,85 +0,0 @@
@font-face {
font-family: znicons;
src: url("@/assets/fonts/znicons.ttf");
}
.image-swiper {
position: relative;
width: 100%;
}
.swiper-box {
overflow: hidden;
// 高度和圆角通过内联样式动态设置
}
.swiper-item .swiper-item-image {
width: 100%;
height: 100%;
}
.thumbnail-box {
position: absolute;
left: 12px;
right: 12px;
display: flex;
align-items: flex-end;
flex-direction: row;
flex-wrap: nowrap;
max-width: 100%;
box-sizing: border-box;
}
.custom-indicator {
margin-left: 12px;
background: rgba(0, 0, 0, 0.5);
border-radius: 50px;
padding: 0 6px 4px 8px;
flex: 0 0 auto;
flex-shrink: 0;
white-space: nowrap;
}
.custom-indicator-text {
margin: 0 4px;
font-size: 10px;
text-align: center;
align-items: center;
color: #fff;
}
.thumbnail-scroll {
flex: 1 1 auto;
min-width: 0; // 允许在flex容器中收缩以适配剩余空间
overflow: auto; // 防止超出thumbnail-box的宽度
height: 100%;
white-space: nowrap;
}
.thumbnail-list {
display: flex;
align-items: center;
gap: 10px;
}
.thumbnail-item {
flex-shrink: 0;
text-align: center;
transition: all 0.3s ease;
&.active {
.thumbnail-image {
border: 2px solid #fff;
}
}
}
.thumbnail-item .thumbnail-image {
width: 36px;
height: 36px;
border-radius: 8px;
box-sizing: border-box;
border: 1px solid #171717;
transition: all 0.3s ease;
display: block;
}

View File

@@ -1,30 +1,26 @@
<template>
<div :class="navBarClass" :style="navBarStyle">
<!-- 状态栏占位 -->
<div :style="{ height: statusBarHeight + 'px' }" v-if="!hideStatusBar"></div>
<!-- 导航栏内容 -->
<div class="flex flex-items-center flex-justify-between border-box pl-8 pr-8"
:style="{ height: navBarHeight + 'px' }">
<div class="flex items-center justify-between px-[8px]" :style="{ height: navBarHeight + 'px' }">
<!-- 左侧返回按钮 -->
<div class="nav-bar-left flex flex-items-center flex-justify-center" v-if="showBack" @click="handleBack">
<uni-icons type="left" size="20" :color="backIconColor" />
<div class="w-[30px] h-[30px] flex items-center justify-center" v-if="showBack" @click="handleBack">
<van-icon name="arrow-left" size="20" :color="backIconColor" />
</div>
<!-- 中间标题区域 -->
<div :class="[
'nav-bar-center flex flex-items-center flex-justify-center',
'flex-1 h-[30px] px-[20px] flex items-center justify-center',
`nav-bar-center--${titleAlign}`,
]">
<slot name="title">
<text class="font-size-17 font-500 color-000" :style="{ color: titleColor }">
<text class="text-[17px] font-medium text-black" :style="{ color: titleColor }">
{{ title }}
</text>
</slot>
</div>
<!-- 右侧操作区域 -->
<div class="nav-bar-right">
<div class="w-[30px] h-[30px]">
<slot name="right"></slot>
</div>
</div>

View File

@@ -12,11 +12,6 @@
}
}
.nav-bar-left,
.nav-bar-right {
width: 30px;
height: 30px;
}
.nav-bar-center {
flex: 1;

View File

@@ -1,12 +1,8 @@
<template>
<div class="flex flex-col h-screen bg-white">
<TopNavBar :title="navOpacity < 0.5 ? '' : '商品详情'" :background="`rgba(217, 238, 255, ${navOpacity})`"
:titleColor="navOpacity < 0.5 ? '#ffffff' : '#000000'"
:backIconColor="navOpacity < 0.5 ? '#ffffff' : '#000000'" />
<!-- 滚动区域 -->
<div class="flex-1 overflow-y-auto" @scroll="handleScroll">
<imgSwiper :border-radius="0" :height="300" :images="goodsData.commodityPhotoList" thumbnailBottom="42px" />
<ImageSwiper :border-radius="0" :height="300" :images="goodsData.commodityPhotoList" thumbnailBottom="42px" />
<div class="bg-white py-[20px] relative -mt-[30px] z-10 rounded-t-[28px]">
<!-- 商品信息组件 -->
@@ -66,7 +62,6 @@ import { ref } from "vue";
import { useRouter } from 'vue-router'
import { goodsDetail, commodityDailyPriceList } from "@/api/goods";
import { DateUtils } from "@/utils/dateUtils";
import TopNavBar from "@/components/TopNavBar/index.vue";
import ImageSwiper from "@/components/ImageSwiper/index.vue";
import GoodInfo from "./components/GoodInfo/index.vue";
import Calender from "@/components/Calender/index.vue";
@@ -81,7 +76,6 @@ import { useSelectedDateStore } from "@/store";
const router = useRouter()
// 导航栏透明度 - 默认透明,随滚动变为不透明
const navOpacity = ref(0);
const calendarVisible = ref(false);
const goodsData = ref({});
@@ -90,8 +84,6 @@ const handleScroll = (e) => {
const scrollTop = e.detail.scrollTop;
// 设置一个阈值当滚动超过200px时导航栏完全不透明
const threshold = 200;
// 计算透明度范围从0到1
navOpacity.value = Math.min(scrollTop / threshold, 1);
};
const selectedDate = ref({
@@ -247,7 +239,3 @@ const navigateToPay = ({ commodityId }) => {
})
};
</script>
<style scoped lang="scss">
@import "./styles/index.scss";
</style>