6. 搜索
6.1 实现搜索页面基础结构
基础结构
vue
<!-- 头部搜索栏 -->
<view class="header">
<view class="header-search">
<icon type="search" size="13"></icon>
<input type="text" class="search-title" v-model="query.keyword" />
</view>
<view class="search-btn" @click="getSearch">搜索</view>
</view>
<!-- tabs栏 -->
<van-tabs type="card" color="#1baeae" @click="changeTab" >
<van-tab title="推荐" name=""></van-tab>
<van-tab title="新品" name="new"></van-tab>
<van-tab title="价格" name="price"></van-tab>
</van-tabs>
<!-- 内容列表 -->
<view class="content">
<!-- 空状态 -->
<view v-else class="search-tip">
<image class="empty" src="https://s.yezgea02.com/1604041313083/kesrtd.png" alt="搜索"></image>
<view class="finished-text">搜索想要的商品</view>
</view>
</view>
UI布局样式
scss
.header {
display: flex;
justify-content: space-between;
height: 100rpx;
line-height: 100rpx;
padding: 0 30rpx;
font-size: 30rpx;
color: #656771;
.header-search {
display: flex;
flex: 1;
height: 40rpx;
line-height: 40rpx;
margin: 20rpx 0;
padding: 10rpx 0;
color: #232326;
background: #f7f7f7;
border-radius: 40rpx;
icon {
padding: 4rpx 18rpx 0 20rpx;
font-size: 32rpx;
}
.search-title {
font-size: 24rpx;
color: #666;
background: #f7f7f7;
width: 80%;
}
}
.search-btn {
height: 56rpx;
margin: 16rpx 0;
line-height: 56rpx;
padding: 0 20rpx;
color: #f7f7f7;
background-color: $uni-primary;
border-radius: 10rpx;
margin-top: 20rpx;
margin-left: 30rpx;
}
}
.content {
height: calc(100vh - 160rpx);
overflow: hidden;
.search-tip {
padding-top: 100rpx;
.empty {
display: block;
width: 300rpx;
height: 300rpx;
margin: 0rpx auto 40rpx;
}
.finished-text {
color: #969799;
font-size: 28rpx;
line-height: 28rpx;
text-align: center;
}
}
}
6.2 根据关键词搜索
查询列表
绑定关键词输入框双向 点击按钮搜索
js// 搜索商品 const getSearch = () => { init() }
加载数据 (关键词空不能搜索)
js// 加载数据 const init = async () => { const { keyword, page, categoryId, orderBy } = state.query console.log(keyword, categoryId); // 0. 判断参数的有效性 关键词 或 类别ID if (!keyword && !categoryId) return state.refreshing = false state.loading = true // 1. 发起请求 keyword不能为空 keyword: '', goodsCategoryId: '', orderBy: '', pageNumber: 1 const { data: { totalPage, list } } = await search({ keyword, goodsCategoryId: categoryId, orderBy , pageNumber: page }) state.list = state.list.concat(list) state.loading = false // 2. 判断是否还能加载 if (page >= totalPage) state.hasMore = false state.refreshing = false }
实现列表布局结构
vue<!-- 内容列表 --> <view class="content"> <scroll-view scroll-y class="product-list" refresher-enabled :refresher-triggered="refreshing" @refresherrefresh="onRefresh" @scrolltolower="loadMore"> <template v-if="list.length"> <view class="product-item" v-for="item in list" :key="item" @click="productDetail(item)"> <!-- 左侧内容 --> <image :src="item.goodsCoverImg"></image> <!-- 中间内容 --> <view class="product-info"> <view class="name">{{ item.goodsName }}</view> <view class="subtitle">{{ item.goodsIntro }}</view> <text class="price">¥ {{item.sellingPrice}}</text> </view> </view> <!-- 加载状态提示 --> <view class="loading-tip">{{ state.hasMore ? '加载中...' : '没有更多了' }}</view> </template> <view v-else class="search-tip"> <image class="empty" src="https://s.yezgea02.com/1604041313083/kesrtd.png" alt="搜索"></image> <view class="finished-text">搜索想要的商品</view> </view> </scroll-view> </view>
补充UI布局
scss.content { height: calc(100vh - 160rpx); overflow: hidden; .product-list { height: 100%; } .product-item { width: 100%; display: flex; justify-content: space-between; height: 240rpx; padding: 20rpx 0; border-bottom: 2rpx solid #dcdcdc; image { width: 280rpx; height: 240rpx; padding: 0 20rpx; box-sizing: border-box; } .product-info { width: 56%; height: 240rpx; padding: 10rpx; text-align: left; box-sizing: border-box; .name { width: 100%; max-height: 80rpx; line-height: 40rpx; font-size: 30rpx; color: #333; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .subtitle { width: 100%; max-height: 40rpx; padding: 20rpx 0; line-height: 50rpx; font-size: 26rpx; color: #999; overflow: hidden; } .price { color: $uni-primary; font-size: 32rpx; } } } .loading-tip { color: #969799; font-size: 24rpx; line-height: 24rpx; text-align: center; padding: 30rpx 0; } .search-tip { padding-top: 100rpx; .empty { display: block; width: 300rpx; height: 300rpx; margin: 0rpx auto 40rpx; } .finished-text { color: #969799; font-size: 28rpx; line-height: 28rpx; text-align: center; } } }
6.3 分类ID搜索
分类页面点击跳转搜索
js// 根据分类选择商品 const selectProduct = item => { console.log('item', item.categoryId) uni.navigateTo({ url: `/subpkg/goods_list/goods_list?categoryId=${item.categoryId}` }) }
onLoad函数中取参数 加载搜索
jsonLoad((options) => { // 保存categoryID state.query.categoryId = options.categoryId || '' init() })
6.4 下拉刷新与上拉加载
scroll-view
绑定事件vue<scroll-view scroll-y class="product-list" refresher-enabled :refresher-triggered="refreshing" @refresherrefresh="onRefresh" @scrolltolower="loadMore"> </scroll-view>
实现事件函数
js// 加载更多 const loadMore = () => { // 1. 判断是否正在加载 if (state.loading) return // 2. 判断是否还能加载 if (!state.hasMore) return state.query.page += 1 init() } // 刷新加载 const onRefresh = () => { state.refreshing = true state.list = [] state.hasMore = true state.query.page = 1 init() }
6.5 排序搜索
tabs绑定事件
处理事件函数
js// 切换tab类型【排序】 const changeTab = (e) => { console.log('name', e) state.query.orderBy = e.detail.name onRefresh() }
6.6 历史搜索
- 基础UI布局 使用van-tag排版
- 关键词搜索 添加为历史记录
- 后置添加 最多10条
- 点击历史 进行关键词搜索
- 一键删除