feat(search): 添加搜索页面功能
实现搜索页面基础功能,包括搜索框、筛选条件和结果展示 在首页添加搜索框跳转逻辑 更新应用配置添加搜索页面路由
Showing
5 changed files
with
498 additions
and
6 deletions
| 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-03 20:40:08 | 4 | + * @LastEditTime: 2025-07-04 10:34:25 |
| 5 | * @FilePath: /jgdl/src/app.config.js | 5 | * @FilePath: /jgdl/src/app.config.js |
| 6 | - * @Description: 文件描述 | 6 | + * @Description: 配置文件 |
| 7 | */ | 7 | */ |
| 8 | export default { | 8 | export default { |
| 9 | pages: [ | 9 | pages: [ |
| ... | @@ -26,6 +26,7 @@ export default { | ... | @@ -26,6 +26,7 @@ export default { |
| 26 | 'pages/myAuthCar/index', | 26 | 'pages/myAuthCar/index', |
| 27 | 'pages/feedBack/index', | 27 | 'pages/feedBack/index', |
| 28 | 'pages/helpCenter/index', | 28 | 'pages/helpCenter/index', |
| 29 | + 'pages/search/index', | ||
| 29 | ], | 30 | ], |
| 30 | subpackages: [ // 配置在tabBar中的页面不能分包写到subpackages中去 | 31 | subpackages: [ // 配置在tabBar中的页面不能分包写到subpackages中去 |
| 31 | { | 32 | { | ... | ... |
| 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-04 10:05:07 | 4 | + * @LastEditTime: 2025-07-04 10:30:39 |
| 5 | * @FilePath: /jgdl/src/pages/index/index.vue | 5 | * @FilePath: /jgdl/src/pages/index/index.vue |
| 6 | * @Description: 捡个电驴首页 | 6 | * @Description: 捡个电驴首页 |
| 7 | --> | 7 | --> |
| ... | @@ -16,7 +16,7 @@ | ... | @@ -16,7 +16,7 @@ |
| 16 | </nut-col> | 16 | </nut-col> |
| 17 | <nut-col span="18"> | 17 | <nut-col span="18"> |
| 18 | <!-- Search Bar --> | 18 | <!-- Search Bar --> |
| 19 | - <nut-searchbar v-model="searchValue" placeholder="搜索品牌型号" @blur="onBlurSearch" shape="round" background="transparent" input-background="#ffffff"> | 19 | + <nut-searchbar v-model="searchValue" placeholder="搜索品牌型号" @focus="onFocusSearch" shape="round" background="transparent" input-background="#ffffff"> |
| 20 | <template #leftin> | 20 | <template #leftin> |
| 21 | <Search2 /> | 21 | <Search2 /> |
| 22 | </template> | 22 | </template> |
| ... | @@ -169,8 +169,11 @@ import "./index.less"; | ... | @@ -169,8 +169,11 @@ import "./index.less"; |
| 169 | const searchValue = ref('') | 169 | const searchValue = ref('') |
| 170 | const favoriteIds = ref([]) | 170 | const favoriteIds = ref([]) |
| 171 | 171 | ||
| 172 | -const onBlurSearch = () => { | 172 | +const onFocusSearch = () => { |
| 173 | - console.warn(searchValue.value) | 173 | + // 跳转到搜索页面 |
| 174 | + Taro.navigateTo({ | ||
| 175 | + url: '/pages/search/index' | ||
| 176 | + }) | ||
| 174 | } | 177 | } |
| 175 | 178 | ||
| 176 | // Banner图片 | 179 | // Banner图片 | ... | ... |
src/pages/search/index.config.js
0 → 100755
| 1 | +/* | ||
| 2 | + * @Date: 2025-07-04 10:33:52 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-07-04 10:57:35 | ||
| 5 | + * @FilePath: /jgdl/src/pages/search/index.config.js | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | + */ | ||
| 8 | +export default { | ||
| 9 | + navigationBarTitleText: '', | ||
| 10 | + usingComponents: { | ||
| 11 | + }, | ||
| 12 | +} |
src/pages/search/index.less
0 → 100644
| 1 | +/* 搜索页面样式 */ | ||
| 2 | +.search-page { | ||
| 3 | + background-color: #f5f5f5; | ||
| 4 | + min-height: 100vh; | ||
| 5 | +} | ||
| 6 | + | ||
| 7 | +/* 搜索结果列表样式 */ | ||
| 8 | +.search-results-list { | ||
| 9 | + width: 100%; | ||
| 10 | + box-sizing: border-box; | ||
| 11 | + | ||
| 12 | + /* 滚动条样式 */ | ||
| 13 | + &::-webkit-scrollbar { | ||
| 14 | + width: 6rpx; | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | + &::-webkit-scrollbar-track { | ||
| 18 | + background: #f1f1f1; | ||
| 19 | + border-radius: 3rpx; | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + &::-webkit-scrollbar-thumb { | ||
| 23 | + background: #c1c1c1; | ||
| 24 | + border-radius: 3rpx; | ||
| 25 | + | ||
| 26 | + &:hover { | ||
| 27 | + background: #a8a8a8; | ||
| 28 | + } | ||
| 29 | + } | ||
| 30 | +} | ||
| 31 | + | ||
| 32 | +/* 加载状态样式 */ | ||
| 33 | +.load-more-container { | ||
| 34 | + padding: 40rpx 0; | ||
| 35 | + | ||
| 36 | + .loading-container { | ||
| 37 | + display: flex; | ||
| 38 | + align-items: center; | ||
| 39 | + justify-content: center; | ||
| 40 | + color: #666; | ||
| 41 | + | ||
| 42 | + .loading-spinner { | ||
| 43 | + width: 32rpx; | ||
| 44 | + height: 32rpx; | ||
| 45 | + border: 4rpx solid #f3f3f3; | ||
| 46 | + border-top: 4rpx solid #f97316; | ||
| 47 | + border-radius: 50%; | ||
| 48 | + animation: spin 1s linear infinite; | ||
| 49 | + margin-right: 16rpx; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + .loading-text { | ||
| 53 | + font-size: 28rpx; | ||
| 54 | + color: #666; | ||
| 55 | + } | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + .no-more-data { | ||
| 59 | + padding: 20rpx 0; | ||
| 60 | + text-align: center; | ||
| 61 | + color: #999; | ||
| 62 | + font-size: 28rpx; | ||
| 63 | + } | ||
| 64 | +} | ||
| 65 | + | ||
| 66 | +/* 旋转动画 */ | ||
| 67 | +@keyframes spin { | ||
| 68 | + 0% { transform: rotate(0deg); } | ||
| 69 | + 100% { transform: rotate(360deg); } | ||
| 70 | +} | ||
| 71 | + | ||
| 72 | +/* 空状态样式 */ | ||
| 73 | +.empty-state { | ||
| 74 | + .empty-icon { | ||
| 75 | + display: flex; | ||
| 76 | + justify-content: center; | ||
| 77 | + align-items: center; | ||
| 78 | + opacity: 0.6; | ||
| 79 | + } | ||
| 80 | +} | ||
| 81 | + | ||
| 82 | +.no-results-state { | ||
| 83 | + .no-results-icon { | ||
| 84 | + display: flex; | ||
| 85 | + justify-content: center; | ||
| 86 | + align-items: center; | ||
| 87 | + opacity: 0.7; | ||
| 88 | + } | ||
| 89 | +} | ||
| 90 | + | ||
| 91 | +/* 搜索结果卡片样式优化 */ | ||
| 92 | +.search-results-list { | ||
| 93 | + .grid { | ||
| 94 | + .bg-white { | ||
| 95 | + transition: all 0.3s ease; | ||
| 96 | + border: 1rpx solid #e5e7eb; | ||
| 97 | + | ||
| 98 | + &:hover { | ||
| 99 | + box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.12); | ||
| 100 | + transform: translateY(-2rpx); | ||
| 101 | + } | ||
| 102 | + } | ||
| 103 | + } | ||
| 104 | +} |
src/pages/search/index.vue
0 → 100644
| 1 | +<!-- | ||
| 2 | + * @Date: 2022-09-19 14:11:06 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-07-04 11:12:55 | ||
| 5 | + * @FilePath: /jgdl/src/pages/search/index.vue | ||
| 6 | + * @Description: 搜索页面 | ||
| 7 | +--> | ||
| 8 | +<template> | ||
| 9 | + <view class="search-page"> | ||
| 10 | + <view class="flex flex-col bg-white min-h-screen"> | ||
| 11 | + <!-- Header --> | ||
| 12 | + <nut-sticky> | ||
| 13 | + <view class="bg-orange-400 p-4 pt-4 pb-4"> | ||
| 14 | + <nut-row type="flex" justify="center" align="center"> | ||
| 15 | + <nut-col span="3"> | ||
| 16 | + <view class="text-xl font-bold text-white">搜索</view> | ||
| 17 | + </nut-col> | ||
| 18 | + <nut-col span="21"> | ||
| 19 | + <!-- Search Bar --> | ||
| 20 | + <nut-searchbar v-model="searchValue" placeholder="搜索品牌型号" @search="onSearch" @blur="onBlurSearch" @clear="onClearSearch" shape="round" background="transparent" input-background="#ffffff"> | ||
| 21 | + <template #leftin> | ||
| 22 | + <Search2 /> | ||
| 23 | + </template> | ||
| 24 | + </nut-searchbar> | ||
| 25 | + </nut-col> | ||
| 26 | + </nut-row> | ||
| 27 | + </view> | ||
| 28 | + | ||
| 29 | + <!-- Filter options --> | ||
| 30 | + <nut-menu> | ||
| 31 | + <nut-menu-item v-model="selectedBrand" :options="brandOptions" @change="onBrandChange" /> | ||
| 32 | + <nut-menu-item v-model="selectedYear" :options="yearOptions" @change="onYearChange" /> | ||
| 33 | + <nut-menu-item v-model="selectedSchool" :options="schoolOptions" @change="onSchoolChange" /> | ||
| 34 | + </nut-menu> | ||
| 35 | + </nut-sticky> | ||
| 36 | + | ||
| 37 | + <!-- Search Results --> | ||
| 38 | + <view class="flex-1"> | ||
| 39 | + <!-- 滚动列表 --> | ||
| 40 | + <scroll-view | ||
| 41 | + class="search-results-list" | ||
| 42 | + :style="scrollStyle" | ||
| 43 | + :scroll-y="true" | ||
| 44 | + @scrolltolower="loadMore" | ||
| 45 | + :lower-threshold="50" | ||
| 46 | + :enable-flex="false" | ||
| 47 | + > | ||
| 48 | + <view class="p-4"> | ||
| 49 | + <!-- 搜索结果统计 --> | ||
| 50 | + <view v-if="searchResults.length > 0" class="mb-4"> | ||
| 51 | + <text class="text-sm text-gray-600">找到 {{ totalCount }} 个相关结果</text> | ||
| 52 | + </view> | ||
| 53 | + | ||
| 54 | + <!-- 搜索结果网格布局 --> | ||
| 55 | + <view class="grid grid-cols-2 gap-3"> | ||
| 56 | + <view v-for="scooter in searchResults" :key="scooter.id" | ||
| 57 | + class="bg-white rounded-lg shadow-sm overflow-hidden" @tap="() => onProductClick(scooter)"> | ||
| 58 | + <view class="relative p-2"> | ||
| 59 | + <image :src="scooter.imageUrl" :alt="scooter.name" mode="aspectFill" | ||
| 60 | + class="w-full h-36 object-cover rounded-lg" /> | ||
| 61 | + <view class="absolute top-4 right-3 w-7 h-7 rounded-full bg-white bg-opacity-90" @tap.stop="() => toggleFavorite(scooter.id)" style="padding-top: 12rpx; padding-left: 10rpx;"> | ||
| 62 | + <Heart1 v-if="!favoriteIds.includes(scooter.id)" size="22" :color="'#9ca3af'" /> | ||
| 63 | + <HeartFill v-else size="22" :color="'#ef4444'" /> | ||
| 64 | + </view> | ||
| 65 | + <view v-if="scooter.isVerified" | ||
| 66 | + class="absolute bottom-4 right-4 text-white text-xs px-1.5 py-0.5 rounded flex items-center" style="background-color: #EB5305;"> | ||
| 67 | + <Check size="12" color="#ffffff" class="mr-0.5" /> | ||
| 68 | + <text class="text-white">认证</text> | ||
| 69 | + </view> | ||
| 70 | + </view> | ||
| 71 | + <view class="p-2 pl-3"> | ||
| 72 | + <text class="font-medium text-sm block">{{ scooter.name }}</text> | ||
| 73 | + <text class="text-xs text-gray-500 block mt-1 mb-1"> | ||
| 74 | + {{ scooter.year }} · {{ scooter.school }} | ||
| 75 | + <text v-if="scooter.batteryHealth">电池健康度{{ scooter.batteryHealth }}%</text> | ||
| 76 | + <text v-if="scooter.mileage"> 行驶{{ scooter.mileage }}公里</text> | ||
| 77 | + </text> | ||
| 78 | + <view class="mt-1"> | ||
| 79 | + <text class="text-orange-500 font-bold" style="font-size: 1.25rem;"> | ||
| 80 | + ¥{{ scooter.price.toLocaleString() }} | ||
| 81 | + </text> | ||
| 82 | + </view> | ||
| 83 | + </view> | ||
| 84 | + </view> | ||
| 85 | + </view> | ||
| 86 | + | ||
| 87 | + <!-- 初始空状态 --> | ||
| 88 | + <view v-if="searchResults.length === 0 && !loading && !hasSearched" class="empty-state text-center py-20"> | ||
| 89 | + <view class="empty-icon mb-4"> | ||
| 90 | + <Search2 size="80" color="#d1d5db" /> | ||
| 91 | + </view> | ||
| 92 | + <text class="text-lg font-medium text-gray-600 block mb-2">搜索电动车</text> | ||
| 93 | + <text class="text-sm text-gray-400 block">输入品牌型号,找到心仪的电动车</text> | ||
| 94 | + </view> | ||
| 95 | + | ||
| 96 | + <!-- 搜索无结果状态 --> | ||
| 97 | + <view v-if="searchResults.length === 0 && !loading && hasSearched" class="no-results-state text-center py-20"> | ||
| 98 | + <view class="no-results-icon mb-4"> | ||
| 99 | + <Search2 size="60" color="#9ca3af" /> | ||
| 100 | + </view> | ||
| 101 | + <text class="text-base font-medium text-gray-600 block mb-2">暂无搜索结果</text> | ||
| 102 | + <text class="text-sm text-gray-400 block">试试其他关键词或调整筛选条件</text> | ||
| 103 | + </view> | ||
| 104 | + | ||
| 105 | + <!-- 加载更多 --> | ||
| 106 | + <view v-if="searchResults.length > 0" class="load-more-container mt-6"> | ||
| 107 | + <view v-if="loading" class="loading-container"> | ||
| 108 | + <view class="loading-spinner"></view> | ||
| 109 | + <text class="loading-text">加载中...</text> | ||
| 110 | + </view> | ||
| 111 | + <view v-else-if="noMoreData" class="no-more-data text-center"> | ||
| 112 | + <text class="text-gray-500">没有更多数据了</text> | ||
| 113 | + </view> | ||
| 114 | + </view> | ||
| 115 | + </view> | ||
| 116 | + </scroll-view> | ||
| 117 | + </view> | ||
| 118 | + </view> | ||
| 119 | + </view> | ||
| 120 | +</template> | ||
| 121 | + | ||
| 122 | +<script setup> | ||
| 123 | +import { ref, computed, onMounted } from 'vue' | ||
| 124 | +import Taro from '@tarojs/taro' | ||
| 125 | +import { Search2, Check, Heart1, HeartFill } from '@nutui/icons-vue-taro' | ||
| 126 | +import "./index.less"; | ||
| 127 | + | ||
| 128 | +// 响应式数据 | ||
| 129 | +const searchValue = ref('') | ||
| 130 | +const favoriteIds = ref(['5', '7', '1']) | ||
| 131 | +const hasSearched = ref(false) | ||
| 132 | + | ||
| 133 | +// 滚动相关 | ||
| 134 | +const loading = ref(false) | ||
| 135 | +const noMoreData = ref(false) | ||
| 136 | +const currentPage = ref(1) | ||
| 137 | +const pageSize = ref(10) | ||
| 138 | +const totalCount = ref(0) | ||
| 139 | + | ||
| 140 | +// Filter states | ||
| 141 | +const selectedBrand = ref('全部品牌') | ||
| 142 | +const selectedYear = ref('出厂年份') | ||
| 143 | +const selectedSchool = ref('所在学校') | ||
| 144 | + | ||
| 145 | +// Menu选项数据 | ||
| 146 | +const brandOptions = ref([ | ||
| 147 | + { text: '全部品牌', value: '全部品牌' }, | ||
| 148 | + { text: '雅迪', value: '雅迪' }, | ||
| 149 | + { text: '台铃', value: '台铃' }, | ||
| 150 | + { text: '小鸟', value: '小鸟' }, | ||
| 151 | + { text: '新日', value: '新日' }, | ||
| 152 | + { text: '爱玛', value: '爱玛' }, | ||
| 153 | + { text: '小牛', value: '小牛' } | ||
| 154 | +]) | ||
| 155 | + | ||
| 156 | +const yearOptions = ref([ | ||
| 157 | + { text: '出厂年份', value: '出厂年份' }, | ||
| 158 | + { text: '2024年', value: '2024年' }, | ||
| 159 | + { text: '2023年', value: '2023年' }, | ||
| 160 | + { text: '2022年', value: '2022年' }, | ||
| 161 | + { text: '2021年', value: '2021年' }, | ||
| 162 | + { text: '2020年', value: '2020年' } | ||
| 163 | +]) | ||
| 164 | + | ||
| 165 | +const schoolOptions = ref([ | ||
| 166 | + { text: '所在学校', value: '所在学校' }, | ||
| 167 | + { text: '上海理工大学', value: '上海理工大学' }, | ||
| 168 | + { text: '上海复旦大学', value: '上海复旦大学' }, | ||
| 169 | + { text: '上海同济大学', value: '上海同济大学' }, | ||
| 170 | + { text: '上海交通大学', value: '上海交通大学' } | ||
| 171 | +]) | ||
| 172 | + | ||
| 173 | +// 搜索结果数据 | ||
| 174 | +const searchResults = ref([]) | ||
| 175 | + | ||
| 176 | +// 滚动样式 | ||
| 177 | +const scrollStyle = computed(() => { | ||
| 178 | + return { | ||
| 179 | + height: 'calc(100vh - 200rpx)' | ||
| 180 | + } | ||
| 181 | +}) | ||
| 182 | + | ||
| 183 | +/** | ||
| 184 | + * 生成模拟数据 | ||
| 185 | + * @param {number} page 页码 | ||
| 186 | + * @param {number} size 每页数量 | ||
| 187 | + * @returns {Array} 模拟数据数组 | ||
| 188 | + */ | ||
| 189 | +const generateMockData = (page, size) => { | ||
| 190 | + const brands = ['雅迪', '台铃', '小鸟', '新日', '爱玛', '小牛'] | ||
| 191 | + const schools = ['上海理工大学', '上海复旦大学', '上海同济大学', '上海交通大学'] | ||
| 192 | + const years = ['2024年', '2023年', '2022年', '2021年', '2020年'] | ||
| 193 | + const images = [ | ||
| 194 | + 'https://images.unsplash.com/photo-1558981285-6f0c94958bb6?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60', | ||
| 195 | + 'https://images.unsplash.com/photo-1558981403-c5f9899a28bc?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60', | ||
| 196 | + 'https://images.unsplash.com/photo-1591637333184-19aa84b3e01f?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60', | ||
| 197 | + 'https://images.unsplash.com/photo-1558980664-3a031cf67ea8?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60', | ||
| 198 | + 'https://images.unsplash.com/photo-1595941069915-4ebc5197c14a?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=60' | ||
| 199 | + ] | ||
| 200 | + | ||
| 201 | + const data = [] | ||
| 202 | + const startId = (page - 1) * size + 1 | ||
| 203 | + | ||
| 204 | + for (let i = 0; i < size; i++) { | ||
| 205 | + const brand = brands[Math.floor(Math.random() * brands.length)] | ||
| 206 | + const school = schools[Math.floor(Math.random() * schools.length)] | ||
| 207 | + const year = years[Math.floor(Math.random() * years.length)] | ||
| 208 | + const image = images[Math.floor(Math.random() * images.length)] | ||
| 209 | + | ||
| 210 | + data.push({ | ||
| 211 | + id: `search_${startId + i}`, | ||
| 212 | + name: `${brand} ${['豪华版', '标准版', '运动版', '经典版'][Math.floor(Math.random() * 4)]}`, | ||
| 213 | + year: year, | ||
| 214 | + school: school, | ||
| 215 | + price: Math.floor(Math.random() * 5000) + 2000, | ||
| 216 | + imageUrl: image, | ||
| 217 | + batteryHealth: Math.floor(Math.random() * 30) + 70, | ||
| 218 | + mileage: Math.floor(Math.random() * 5000) + 500, | ||
| 219 | + brand: brand, | ||
| 220 | + isVerified: Math.random() > 0.6 | ||
| 221 | + }) | ||
| 222 | + } | ||
| 223 | + | ||
| 224 | + return data | ||
| 225 | +} | ||
| 226 | + | ||
| 227 | +/** | ||
| 228 | + * 执行搜索 | ||
| 229 | + */ | ||
| 230 | +const performSearch = () => { | ||
| 231 | + if (!searchValue.value.trim()) { | ||
| 232 | + clearSearchResults() | ||
| 233 | + return | ||
| 234 | + } | ||
| 235 | + | ||
| 236 | + loading.value = true | ||
| 237 | + hasSearched.value = true | ||
| 238 | + currentPage.value = 1 | ||
| 239 | + noMoreData.value = false | ||
| 240 | + | ||
| 241 | + // 模拟API调用延迟 | ||
| 242 | + setTimeout(() => { | ||
| 243 | + const mockData = generateMockData(1, pageSize.value) | ||
| 244 | + searchResults.value = mockData | ||
| 245 | + totalCount.value = 50 // 模拟总数 | ||
| 246 | + loading.value = false | ||
| 247 | + }, 500) | ||
| 248 | +} | ||
| 249 | + | ||
| 250 | +/** | ||
| 251 | + * 清除搜索结果 | ||
| 252 | + */ | ||
| 253 | +const clearSearchResults = () => { | ||
| 254 | + searchResults.value = [] | ||
| 255 | + hasSearched.value = false | ||
| 256 | + currentPage.value = 1 | ||
| 257 | + noMoreData.value = false | ||
| 258 | + totalCount.value = 0 | ||
| 259 | +} | ||
| 260 | + | ||
| 261 | +/** | ||
| 262 | + * 搜索事件处理 | ||
| 263 | + */ | ||
| 264 | +const onSearch = () => { | ||
| 265 | + performSearch() | ||
| 266 | +} | ||
| 267 | + | ||
| 268 | +/** | ||
| 269 | + * 搜索框失焦事件 | ||
| 270 | + */ | ||
| 271 | +const onBlurSearch = () => { | ||
| 272 | + if (searchValue.value.trim()) { | ||
| 273 | + performSearch() | ||
| 274 | + } else { | ||
| 275 | + // 如果搜索框为空,清除搜索结果 | ||
| 276 | + clearSearchResults() | ||
| 277 | + } | ||
| 278 | +} | ||
| 279 | + | ||
| 280 | +const onClearSearch = () => { | ||
| 281 | + clearSearchResults() | ||
| 282 | +} | ||
| 283 | + | ||
| 284 | +/** | ||
| 285 | + * 品牌筛选变化 | ||
| 286 | + */ | ||
| 287 | +const onBrandChange = () => { | ||
| 288 | + if (hasSearched.value) { | ||
| 289 | + performSearch() | ||
| 290 | + } | ||
| 291 | +} | ||
| 292 | + | ||
| 293 | +/** | ||
| 294 | + * 年份筛选变化 | ||
| 295 | + */ | ||
| 296 | +const onYearChange = () => { | ||
| 297 | + if (hasSearched.value) { | ||
| 298 | + performSearch() | ||
| 299 | + } | ||
| 300 | +} | ||
| 301 | + | ||
| 302 | +/** | ||
| 303 | + * 学校筛选变化 | ||
| 304 | + */ | ||
| 305 | +const onSchoolChange = () => { | ||
| 306 | + if (hasSearched.value) { | ||
| 307 | + performSearch() | ||
| 308 | + } | ||
| 309 | +} | ||
| 310 | + | ||
| 311 | +/** | ||
| 312 | + * 加载更多数据 | ||
| 313 | + */ | ||
| 314 | +const loadMore = () => { | ||
| 315 | + if (loading.value || noMoreData.value) return | ||
| 316 | + | ||
| 317 | + loading.value = true | ||
| 318 | + currentPage.value++ | ||
| 319 | + | ||
| 320 | + // 模拟API调用延迟 | ||
| 321 | + setTimeout(() => { | ||
| 322 | + const mockData = generateMockData(currentPage.value, pageSize.value) | ||
| 323 | + | ||
| 324 | + if (mockData.length === 0 || searchResults.value.length >= totalCount.value) { | ||
| 325 | + noMoreData.value = true | ||
| 326 | + } else { | ||
| 327 | + searchResults.value.push(...mockData) | ||
| 328 | + } | ||
| 329 | + | ||
| 330 | + loading.value = false | ||
| 331 | + }, 500) | ||
| 332 | +} | ||
| 333 | + | ||
| 334 | +/** | ||
| 335 | + * 切换收藏状态 | ||
| 336 | + * @param {string} id 商品ID | ||
| 337 | + */ | ||
| 338 | +const toggleFavorite = (id) => { | ||
| 339 | + const index = favoriteIds.value.indexOf(id) | ||
| 340 | + if (index > -1) { | ||
| 341 | + favoriteIds.value.splice(index, 1) | ||
| 342 | + } else { | ||
| 343 | + favoriteIds.value.push(id) | ||
| 344 | + } | ||
| 345 | +} | ||
| 346 | + | ||
| 347 | +/** | ||
| 348 | + * 商品点击事件 | ||
| 349 | + * @param {Object} scooter 商品信息 | ||
| 350 | + */ | ||
| 351 | +const onProductClick = (scooter) => { | ||
| 352 | + Taro.navigateTo({ | ||
| 353 | + url: `/pages/productDetail/index?id=${scooter.id}` | ||
| 354 | + }) | ||
| 355 | +} | ||
| 356 | + | ||
| 357 | +// 页面初始化 | ||
| 358 | +onMounted(() => { | ||
| 359 | + // 如果有搜索参数,自动执行搜索 | ||
| 360 | + const instance = Taro.getCurrentInstance() | ||
| 361 | + if (instance.router?.params?.keyword) { | ||
| 362 | + searchValue.value = instance.router.params.keyword | ||
| 363 | + performSearch() | ||
| 364 | + } | ||
| 365 | +}) | ||
| 366 | +</script> | ||
| 367 | + | ||
| 368 | +<script> | ||
| 369 | +export default { | ||
| 370 | + name: "SearchPage", | ||
| 371 | +}; | ||
| 372 | +</script> |
-
Please register or login to post a comment