feat(首页): 重构首页UI组件并优化交互体验
- 使用NutUI组件替换自定义搜索栏和轮播图 - 优化商品卡片布局和收藏按钮样式 - 移除与NutUI冲突的样式和导入 - 更新全局组件声明以支持新增NutUI组件 - 修复文件末尾缺少换行符的问题
Showing
5 changed files
with
50 additions
and
94 deletions
| ... | @@ -8,7 +8,9 @@ export {} | ... | @@ -8,7 +8,9 @@ export {} |
| 8 | declare module 'vue' { | 8 | declare module 'vue' { |
| 9 | export interface GlobalComponents { | 9 | export interface GlobalComponents { |
| 10 | NavBar: typeof import('./src/components/navBar.vue')['default'] | 10 | NavBar: typeof import('./src/components/navBar.vue')['default'] |
| 11 | - NutInput: typeof import('@nutui/nutui-taro')['Input'] | 11 | + NutSearchbar: typeof import('@nutui/nutui-taro')['Searchbar'] |
| 12 | + NutSwiper: typeof import('@nutui/nutui-taro')['Swiper'] | ||
| 13 | + NutSwiperItem: typeof import('@nutui/nutui-taro')['SwiperItem'] | ||
| 12 | Picker: typeof import('./src/components/time-picker-data/picker.vue')['default'] | 14 | Picker: typeof import('./src/components/time-picker-data/picker.vue')['default'] |
| 13 | PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default'] | 15 | PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default'] |
| 14 | RouterLink: typeof import('vue-router')['RouterLink'] | 16 | RouterLink: typeof import('vue-router')['RouterLink'] | ... | ... |
| ... | @@ -69,7 +69,6 @@ export default defineConfig(async (merge) => { | ... | @@ -69,7 +69,6 @@ export default defineConfig(async (merge) => { |
| 69 | pxtransform: { | 69 | pxtransform: { |
| 70 | enable: true, | 70 | enable: true, |
| 71 | config: { | 71 | config: { |
| 72 | - | ||
| 73 | } | 72 | } |
| 74 | }, | 73 | }, |
| 75 | // url: { | 74 | // url: { |
| ... | @@ -134,7 +133,6 @@ export default defineConfig(async (merge) => { | ... | @@ -134,7 +133,6 @@ export default defineConfig(async (merge) => { |
| 134 | } | 133 | } |
| 135 | }, | 134 | }, |
| 136 | webpackChain(chain) { | 135 | webpackChain(chain) { |
| 137 | - | ||
| 138 | chain.plugin('unplugin-vue-components').use(Components({ | 136 | chain.plugin('unplugin-vue-components').use(Components({ |
| 139 | resolvers: [NutUIResolver({taro: true})] | 137 | resolvers: [NutUIResolver({taro: true})] |
| 140 | })) | 138 | })) | ... | ... |
| ... | @@ -3,13 +3,13 @@ | ... | @@ -3,13 +3,13 @@ |
| 3 | @tailwind utilities; | 3 | @tailwind utilities; |
| 4 | 4 | ||
| 5 | /* 修复 NutUI 图标字体样式 */ | 5 | /* 修复 NutUI 图标字体样式 */ |
| 6 | -.nut-icon { | 6 | +// .nut-icon { |
| 7 | - font-style: normal !important; | 7 | +// font-style: normal !important; |
| 8 | - font-weight: normal !important; | 8 | +// font-weight: normal !important; |
| 9 | -} | 9 | +// } |
| 10 | 10 | ||
| 11 | /* 修复所有可能的图标字体 */ | 11 | /* 修复所有可能的图标字体 */ |
| 12 | -[class*="nut-icon"] { | 12 | +// [class*="nut-icon"] { |
| 13 | - font-style: normal !important; | 13 | +// font-style: normal !important; |
| 14 | - font-weight: normal !important; | 14 | +// font-weight: normal !important; |
| 15 | -} | 15 | +// } | ... | ... |
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2025-06-28 10:33:00 | 2 | * @Date: 2025-06-28 10:33:00 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-07-01 18:18:19 | 4 | + * @LastEditTime: 2025-07-01 19:43:08 |
| 5 | * @FilePath: /jgdl/src/pages/index/index.vue | 5 | * @FilePath: /jgdl/src/pages/index/index.vue |
| 6 | * @Description: 捡个电驴首页 | 6 | * @Description: 捡个电驴首页 |
| 7 | --> | 7 | --> |
| ... | @@ -11,33 +11,22 @@ | ... | @@ -11,33 +11,22 @@ |
| 11 | <view class="bg-orange-400 p-4 pt-8 pb-6"> | 11 | <view class="bg-orange-400 p-4 pt-8 pb-6"> |
| 12 | <view class="text-2xl font-bold text-white mb-3">捡个电驴</view> | 12 | <view class="text-2xl font-bold text-white mb-3">捡个电驴</view> |
| 13 | <!-- Search Bar --> | 13 | <!-- Search Bar --> |
| 14 | - <view class="relative"> | 14 | + <nut-searchbar v-model="searchValue" placeholder="搜索品牌型号" shape="round" background="transparent" |
| 15 | - <view class="absolute inset-y-0 left-3 flex items-center pointer-events-none"> | 15 | + input-background="#ffffff"> |
| 16 | - <Search size="18" color="#9ca3af" /> | 16 | + <template #leftin> |
| 17 | - </view> | 17 | + <Search2 /> |
| 18 | - <nut-input | 18 | + </template> |
| 19 | - v-model="searchValue" | 19 | + </nut-searchbar> |
| 20 | - placeholder="搜索品牌型号" | ||
| 21 | - class="w-full py-2 pl-10 pr-4 rounded-full bg-white" | ||
| 22 | - :border="false" | ||
| 23 | - /> | ||
| 24 | - </view> | ||
| 25 | </view> | 20 | </view> |
| 26 | 21 | ||
| 27 | <!-- Banner --> | 22 | <!-- Banner --> |
| 28 | <view class="px-4 mt-4"> | 23 | <view class="px-4 mt-4"> |
| 29 | - <view class="relative rounded-lg overflow-hidden"> | 24 | + <nut-swiper :init-page="0" :pagination-visible="true" pagination-color="#ffffff" auto-play="3000" |
| 30 | - <image | 25 | + class="rounded-lg overflow-hidden" height="160"> |
| 31 | - :src="bannerImages[0]" | 26 | + <nut-swiper-item v-for="(image, index) in bannerImages" :key="index"> |
| 32 | - mode="aspectFill" | 27 | + <image :src="image" mode="aspectFill" class="w-full h-40 object-cover" /> |
| 33 | - class="w-full h-40 object-cover rounded-lg" | 28 | + </nut-swiper-item> |
| 34 | - /> | 29 | + </nut-swiper> |
| 35 | - <view class="absolute bottom-2 right-2 flex space-x-1"> | ||
| 36 | - <view class="w-2 h-2 bg-white rounded-full opacity-100"></view> | ||
| 37 | - <view class="w-2 h-2 bg-white rounded-full opacity-50"></view> | ||
| 38 | - <view class="w-2 h-2 bg-white rounded-full opacity-50"></view> | ||
| 39 | - </view> | ||
| 40 | - </view> | ||
| 41 | </view> | 30 | </view> |
| 42 | 31 | ||
| 43 | <!-- Category Icons --> | 32 | <!-- Category Icons --> |
| ... | @@ -74,33 +63,17 @@ | ... | @@ -74,33 +63,17 @@ |
| 74 | </view> | 63 | </view> |
| 75 | </view> | 64 | </view> |
| 76 | <view class="grid grid-cols-2 gap-3"> | 65 | <view class="grid grid-cols-2 gap-3"> |
| 77 | - <view | 66 | + <view v-for="scooter in featuredScooters" :key="scooter.id" |
| 78 | - v-for="scooter in featuredScooters" | 67 | + class="bg-white rounded-lg shadow-sm overflow-hidden" @tap="() => onProductClick(scooter)"> |
| 79 | - :key="scooter.id" | ||
| 80 | - class="bg-white rounded-lg shadow-sm overflow-hidden" | ||
| 81 | - @tap="() => onProductClick(scooter)" | ||
| 82 | - > | ||
| 83 | <view class="relative p-2"> | 68 | <view class="relative p-2"> |
| 84 | - <image | 69 | + <image :src="scooter.imageUrl" :alt="scooter.name" mode="aspectFill" |
| 85 | - :src="scooter.imageUrl" | 70 | + class="w-full h-36 object-cover rounded-lg" /> |
| 86 | - :alt="scooter.name" | 71 | + <view class="absolute top-4 right-4 p-1" @tap.stop="() => toggleFavorite(scooter.id)"> |
| 87 | - mode="aspectFill" | 72 | + <Heart size="20" :color="favoriteIds.includes(scooter.id) ? '#ef4444' : '#ffffff'" |
| 88 | - class="w-full h-36 object-cover rounded-lg" | 73 | + :fill="favoriteIds.includes(scooter.id) ? '#ef4444' : 'none'" /> |
| 89 | - /> | ||
| 90 | - <view | ||
| 91 | - class="absolute top-4 right-4 p-1" | ||
| 92 | - @tap.stop="() => toggleFavorite(scooter.id)" | ||
| 93 | - > | ||
| 94 | - <Heart | ||
| 95 | - size="24" | ||
| 96 | - :color="favoriteIds.includes(scooter.id) ? '#f97316' : '#ffffff'" | ||
| 97 | - :fill="favoriteIds.includes(scooter.id) ? '#f97316' : 'none'" | ||
| 98 | - /> | ||
| 99 | </view> | 74 | </view> |
| 100 | - <view | 75 | + <view v-if="scooter.isVerified" |
| 101 | - v-if="scooter.isVerified" | 76 | + class="absolute bottom-4 right-4 bg-orange-500 text-white text-xs px-1.5 py-0.5 rounded flex items-center"> |
| 102 | - class="absolute bottom-4 right-4 bg-orange-500 text-white text-xs px-1.5 py-0.5 rounded flex items-center" | ||
| 103 | - > | ||
| 104 | <Check size="12" color="#ffffff" class="mr-0.5" /> | 77 | <Check size="12" color="#ffffff" class="mr-0.5" /> |
| 105 | <text class="text-white">认证</text> | 78 | <text class="text-white">认证</text> |
| 106 | </view> | 79 | </view> |
| ... | @@ -116,10 +89,7 @@ | ... | @@ -116,10 +89,7 @@ |
| 116 | <text class="text-orange-500 font-bold"> | 89 | <text class="text-orange-500 font-bold"> |
| 117 | ¥{{ scooter.price.toLocaleString() }} | 90 | ¥{{ scooter.price.toLocaleString() }} |
| 118 | </text> | 91 | </text> |
| 119 | - <text | 92 | + <text v-if="scooter.isVerified" class="ml-2 text-xs px-1 py-0.5 bg-orange-100 text-orange-500 rounded"> |
| 120 | - v-if="scooter.isVerified" | ||
| 121 | - class="ml-2 text-xs px-1 py-0.5 bg-orange-100 text-orange-500 rounded" | ||
| 122 | - > | ||
| 123 | 低于市场价10% | 93 | 低于市场价10% |
| 124 | </text> | 94 | </text> |
| 125 | <text class="text-xs text-gray-500 mt-1 block">{{ scooter.school }}</text> | 95 | <text class="text-xs text-gray-500 mt-1 block">{{ scooter.school }}</text> |
| ... | @@ -139,38 +109,22 @@ | ... | @@ -139,38 +109,22 @@ |
| 139 | </view> | 109 | </view> |
| 140 | </view> | 110 | </view> |
| 141 | <view class="flex flex-col"> | 111 | <view class="flex flex-col"> |
| 142 | - <view | 112 | + <view v-for="scooter in latestScooters" :key="scooter.id" |
| 143 | - v-for="scooter in latestScooters" | 113 | + class="bg-white rounded-lg shadow-sm overflow-hidden mb-3" @tap="() => onProductClick(scooter)"> |
| 144 | - :key="scooter.id" | ||
| 145 | - class="bg-white rounded-lg shadow-sm overflow-hidden mb-3" | ||
| 146 | - @tap="() => onProductClick(scooter)" | ||
| 147 | - > | ||
| 148 | <view class="flex"> | 114 | <view class="flex"> |
| 149 | <view class="w-32 h-24 relative p-2"> | 115 | <view class="w-32 h-24 relative p-2"> |
| 150 | - <image | 116 | + <image :src="scooter.imageUrl" :alt="scooter.name" mode="aspectFill" |
| 151 | - :src="scooter.imageUrl" | 117 | + class="w-full h-full object-cover rounded-lg" /> |
| 152 | - :alt="scooter.name" | 118 | + <view v-if="scooter.isVerified" |
| 153 | - mode="aspectFill" | 119 | + class="absolute bottom-3 right-3 bg-orange-500 text-white text-xs px-1 rounded flex items-center"> |
| 154 | - class="w-full h-full object-cover rounded-lg" | ||
| 155 | - /> | ||
| 156 | - <view | ||
| 157 | - v-if="scooter.isVerified" | ||
| 158 | - class="absolute bottom-3 right-3 bg-orange-500 text-white text-xs px-1 rounded flex items-center" | ||
| 159 | - > | ||
| 160 | <Check size="12" color="#ffffff" class="mr-0.5" /> | 120 | <Check size="12" color="#ffffff" class="mr-0.5" /> |
| 161 | <text class="text-white">认证</text> | 121 | <text class="text-white">认证</text> |
| 162 | </view> | 122 | </view> |
| 163 | </view> | 123 | </view> |
| 164 | <view class="flex-1 p-3 relative"> | 124 | <view class="flex-1 p-3 relative"> |
| 165 | - <view | 125 | + <view class="absolute top-2 right-2" @tap.stop="() => toggleFavorite(scooter.id)"> |
| 166 | - class="absolute top-2 right-2" | 126 | + <Heart size="16" :color="favoriteIds.includes(scooter.id) ? '#ef4444' : '#d1d5db'" |
| 167 | - @tap.stop="() => toggleFavorite(scooter.id)" | 127 | + :fill="favoriteIds.includes(scooter.id) ? '#ef4444' : 'none'" /> |
| 168 | - > | ||
| 169 | - <Heart | ||
| 170 | - size="20" | ||
| 171 | - :color="favoriteIds.includes(scooter.id) ? '#f97316' : '#d1d5db'" | ||
| 172 | - :fill="favoriteIds.includes(scooter.id) ? '#f97316' : 'none'" | ||
| 173 | - /> | ||
| 174 | </view> | 128 | </view> |
| 175 | <text class="font-medium text-sm block">{{ scooter.name }}</text> | 129 | <text class="font-medium text-sm block">{{ scooter.name }}</text> |
| 176 | <text class="text-xs text-gray-600 mt-1 block"> | 130 | <text class="text-xs text-gray-600 mt-1 block"> |
| ... | @@ -194,10 +148,10 @@ | ... | @@ -194,10 +148,10 @@ |
| 194 | 148 | ||
| 195 | <script setup> | 149 | <script setup> |
| 196 | import Taro from '@tarojs/taro' | 150 | import Taro from '@tarojs/taro' |
| 197 | -import '@tarojs/taro/html.css' | 151 | +// import '@tarojs/taro/html.css' 和 nutui组件居然有冲突? |
| 198 | import { ref, onMounted } from 'vue' | 152 | import { ref, onMounted } from 'vue' |
| 199 | import { useDidShow, useReady } from '@tarojs/taro' | 153 | import { useDidShow, useReady } from '@tarojs/taro' |
| 200 | -import { Search, Clock, Star, Service, Right, Heart, Check } from '@nutui/icons-vue-taro' | 154 | +import { Clock, Star, Service, Right, Heart, Check, Search2 } from '@nutui/icons-vue-taro' |
| 201 | import "./index.less"; | 155 | import "./index.less"; |
| 202 | 156 | ||
| 203 | // 响应式数据 | 157 | // 响应式数据 |
| ... | @@ -206,7 +160,9 @@ const favoriteIds = ref([]) | ... | @@ -206,7 +160,9 @@ const favoriteIds = ref([]) |
| 206 | 160 | ||
| 207 | // Banner图片 | 161 | // Banner图片 |
| 208 | const bannerImages = ref([ | 162 | const bannerImages = ref([ |
| 209 | - 'https://images.unsplash.com/photo-1558981806-ec527fa84c39?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60' | 163 | + 'https://images.unsplash.com/photo-1558981806-ec527fa84c39?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60', |
| 164 | + 'https://images.unsplash.com/photo-1558981285-6f0c94958bb6?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60', | ||
| 165 | + 'https://images.unsplash.com/photo-1558981403-c5f9899a28bc?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60' | ||
| 210 | ]) | 166 | ]) |
| 211 | 167 | ||
| 212 | // 精品推荐数据 | 168 | // 精品推荐数据 |
| ... | @@ -391,7 +347,7 @@ import { getCurrentPageParam } from "@/utils/weapp"; | ... | @@ -391,7 +347,7 @@ import { getCurrentPageParam } from "@/utils/weapp"; |
| 391 | 347 | ||
| 392 | export default { | 348 | export default { |
| 393 | name: "indexPage", | 349 | name: "indexPage", |
| 394 | - onHide () { | 350 | + onHide() { |
| 395 | console.warn('index onHide') | 351 | console.warn('index onHide') |
| 396 | }, | 352 | }, |
| 397 | onShareAppMessage() { | 353 | onShareAppMessage() { | ... | ... |
-
Please register or login to post a comment