鸿蒙OSUniApp实现个性化的搜索框与搜索历史记录#三方框架 #Uniapp
使用UniApp实现个性化的搜索框与搜索历史记录
在移动端应用开发中,搜索功能几乎是标配,而一个好的搜索体验不仅仅是功能的实现,更是用户留存的关键。本文将分享如何在UniApp框架下打造一个既美观又实用的搜索框,并实现搜索历史记录功能。
前言
做了这么多年的前端开发,发现搜索功能看似简单,但要做好却不容易。特别是在跨端开发框架UniApp中,既要考虑不同平台的兼容性,又要保证用户体验的一致性。最近在一个电商项目中,我重新设计了搜索模块,今天就把这部分经验分享给大家。
需求分析
首先明确我们要实现的功能:
- 一个美观的搜索框,支持输入搜索关键词
- 实时显示搜索建议(热门搜索)
- 记录用户的搜索历史,并提供查看和清除功能
- 点击历史记录可以快速进行搜索
这些看似常见的功能,实现起来却有不少细节需要注意。接下来,我们一步步来实现。
基础界面搭建
首先,我们创建一个搜索页面search.vue
:
<template><view class="search-container"><!-- 搜索框部分 --><view class="search-header"><view class="search-box"><text class="iconfont icon-search"></text><input type="text" v-model="keyword" confirm-type="search"placeholder="请输入搜索关键词" @confirm="handleSearch"@input="handleInput"/><text v-if="keyword" class="iconfont icon-close" @tap="clearKeyword"></text></view><text class="cancel-btn" @tap="goBack">取消</text></view><!-- 内容区域 --><view class="search-content"><!-- 搜索历史 --><view class="history-section" v-if="searchHistory.length > 0"><view class="section-header"><text>搜索历史</text><text class="iconfont icon-delete" @tap="clearHistory"></text></view><view class="tag-list"><view class="tag-item" v-for="(item, index) in searchHistory" :key="index"@tap="searchByTag(item)">{{item}}</view></view></view><!-- 热门搜索 --><view class="hot-section"><view class="section-header"><text>热门搜索</text></view><view class="tag-list"><view class="tag-item" v-for="(item, index) in hotKeywords" :key="index"@tap="searchByTag(item)">{{item}}</view></view></view></view></view>
</template><script>
export default {data() {return {keyword: '',searchHistory: [],hotKeywords: ['手机', '电脑', '耳机', '平板', '相机', '手表', '家电', '配件']}},onLoad() {// 页面加载时获取历史记录this.getSearchHistory()},methods: {handleSearch() {if (!this.keyword.trim()) return// 保存搜索记录this.saveSearchHistory(this.keyword)// 执行搜索跳转this.navigateToResult(this.keyword)},searchByTag(keyword) {this.keyword = keywordthis.handleSearch()},clearKeyword() {this.keyword = ''},goBack() {uni.navigateBack()},handleInput() {// 可以在这里实现输入联想功能},getSearchHistory() {const history = uni.getStorageSync('searchHistory')if (history) {this.searchHistory = JSON.parse(history)}},saveSearchHistory(keyword) {let history = [...this.searchHistory]// 如果已存在相同关键词,先移除const index = history.findIndex(item => item === keyword)if (index !== -1) {history.splice(index, 1)}// 将新关键词添加到头部history.unshift(keyword)// 只保留最近10条记录if (history.length > 10) {history = history.slice(0, 10)}this.searchHistory = historyuni.setStorageSync('searchHistory', JSON.stringify(history))},clearHistory() {uni.showModal({title: '提示',content: '确定要清空搜索历史吗?',success: res => {if (res.confirm) {this.searchHistory = []uni.removeStorageSync('searchHistory')}}})},navigateToResult(keyword) {uni.navigateTo({url: `/pages/search-result/search-result?keyword=${encodeURIComponent(keyword)}`})}}
}
</script><style lang="scss">
.search-container {display: flex;flex-direction: column;height: 100vh;background-color: #f8f8f8;.search-header {display: flex;align-items: center;padding: 20rpx 30rpx;background-color: #ffffff;.search-box {flex: 1;display: flex;align-items: center;height: 70rpx;background-color: #f5f5f5;border-radius: 35rpx;padding: 0 20rpx;.iconfont {font-size: 36rpx;color: #999;}input {flex: 1;height: 100%;margin: 0 15rpx;font-size: 28rpx;}.icon-close {padding: 10rpx;}}.cancel-btn {margin-left: 20rpx;font-size: 28rpx;color: #333;}}.search-content {flex: 1;padding: 30rpx;.section-header {display: flex;justify-content: space-between;margin-bottom: 20rpx;font-size: 30rpx;color: #333;.iconfont {font-size: 32rpx;color: #999;}}.tag-list {display: flex;flex-wrap: wrap;.tag-item {padding: 10rpx 30rpx;margin: 0 20rpx 20rpx 0;background-color: #ffffff;border-radius: 30rpx;font-size: 26rpx;color: #666;}}.history-section {margin-bottom: 50rpx;}}
}
</style>
实现搜索历史功能
在上面的代码中,我们已经基本实现了搜索历史的保存和展示功能。整个实现思路是:
- 在用户进行搜索时,通过
saveSearchHistory
方法将关键词保存到本地存储 - 页面加载时,通过
getSearchHistory
从本地读取历史记录 - 点击历史记录标签可以快速发起搜索
- 提供清空历史记录的功能
但是,这里还有一些优化点,比如:
1. 防止重复保存
当用户多次搜索相同关键词时,我们不应该重复保存。在代码中,我们先查找是否已存在相同关键词,如果存在则先移除,然后将新的关键词添加到列表头部,这样可以保证最近搜索的内容总是排在最前面。
2. 限制历史记录数量
为了避免占用过多存储空间,我们限制只保留最近的10条搜索记录:
// 只保留最近10条记录
if (history.length > 10) {history = history.slice(0, 10)
}
进阶:实现搜索建议功能
现在,我们的搜索框基本功能已经实现了,但是为了提升用户体验,我们可以增加实时搜索建议功能。当用户输入关键词时,后台可以返回相关的搜索建议。
<template><!-- 搜索建议列表 --><view class="suggestion-list" v-if="keyword && suggestions.length > 0"><view class="suggestion-item" v-for="(item, index) in suggestions" :key="index"@tap="searchByTag(item)"><text class="iconfont icon-search"></text><text>{{item}}</text></view></view>
</template><script>
export default {data() {return {// ...现有代码suggestions: []}},methods: {// ...现有代码// 修改handleInput方法handleInput() {if (!this.keyword.trim()) {this.suggestions = []return}// 这里模拟从服务端获取搜索建议// 实际开发中,应该调用API获取数据setTimeout(() => {if (this.keyword) {this.suggestions = this.mockSuggestions(this.keyword)}}, 300)},mockSuggestions(keyword) {// 这只是一个模拟的建议列表,实际开发中应该调用APIconst allSuggestions = {'手': ['手机', '手表', '手机壳', '手持云台'],'电': ['电脑', '电视', '电饭煲', '电动牙刷'],'耳': ['耳机', '耳麦', '耳温枪']}for (const key in allSuggestions) {if (keyword.includes(key)) {return allSuggestions[key]}}return []}}
}
</script><style lang="scss">
// 添加搜索建议样式
.suggestion-list {position: absolute;top: 110rpx;left: 0;right: 0;background-color: #fff;box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);z-index: 999;.suggestion-item {display: flex;align-items: center;padding: 20rpx 30rpx;border-bottom: 1px solid #f5f5f5;.iconfont {font-size: 32rpx;color: #999;margin-right: 15rpx;}text {font-size: 28rpx;color: #333;}}
}
</style>
防抖处理
为了避免频繁请求服务器,我们可以对输入事件进行防抖处理:
// 需要先定义一个定时器变量
data() {return {// ...现有数据debounceTimer: null}
},// 修改handleInput方法
handleInput() {if (!this.keyword.trim()) {this.suggestions = []return}// 清除之前的定时器clearTimeout(this.debounceTimer)// 设置新的定时器this.debounceTimer = setTimeout(() => {// 调用API获取搜索建议this.getSuggestions()}, 300)
},// 获取搜索建议的方法
getSuggestions() {// 实际开发中应该调用API// 这里使用模拟数据this.suggestions = this.mockSuggestions(this.keyword)// 真实API调用可能是这样:/*uni.request({url: 'https://your-api.com/suggestions',data: {keyword: this.keyword},success: (res) => {this.suggestions = res.data.suggestions || []}})*/
}
实战案例:电商搜索页面
在实际的电商项目中,我们不仅需要基础的搜索功能,还需要分类筛选、排序等高级功能。以下是一个简化的电商搜索结果页面:
<!-- search-result.vue -->
<template><view class="result-container"><!-- 搜索框 --><view class="search-bar"><view class="search-box" @tap="goToSearch"><text class="iconfont icon-search"></text><text class="placeholder">{{keyword || '请输入搜索关键词'}}</text></view></view><!-- 筛选条件 --><view class="filter-bar"><view class="filter-item" :class="{active: currentSort === 'default'}"@tap="changeSort('default')">综合</view><view class="filter-item" :class="{active: currentSort === 'sales'}"@tap="changeSort('sales')">销量</view><view class="filter-item" :class="{active: currentSort === 'price'}"@tap="changeSort('price')">价格<text class="iconfont" :class="priceOrder === 'asc' ? 'icon-up' : 'icon-down'"></text></view><view class="filter-item" :class="{active: showFilter}"@tap="toggleFilter">筛选<text class="iconfont icon-filter"></text></view></view><!-- 商品列表 --><view class="goods-list"><view class="goods-item" v-for="(item, index) in goodsList" :key="index"@tap="goToDetail(item.id)"><image :src="item.image" mode="aspectFill"></image><view class="goods-info"><view class="goods-title">{{item.title}}</view><view class="goods-price">¥{{item.price}}</view><view class="goods-extra"><text class="sales">销量 {{item.sales}}</text><text class="comment">评价 {{item.comment}}</text></view></view></view></view><!-- 无结果提示 --><view class="empty-tip" v-if="goodsList.length === 0"><image src="/static/images/empty.png"></image><text>没有找到相关商品</text></view></view>
</template>
总结与优化建议
通过本文,我们实现了一个功能完善的搜索框和搜索历史记录功能。但在实际应用中,还可以做以下优化:
- 搜索框自动聚焦:页面加载时,自动让输入框获得焦点,提高用户体验
- 历史记录去重:除了当前的去重逻辑,还可以考虑对相似关键词进行合并
- 个性化推荐:根据用户的历史搜索记录,提供个性化的搜索推荐
- 搜索结果缓存:对热门搜索结果进行缓存,提高加载速度
- 语音搜索:集成语音识别API,支持语音搜索功能
- 图片搜索:支持上传图片进行搜索,特别适用于电商场景
最后的思考
在移动端应用中,搜索功能是连接用户与内容的桥梁。一个好的搜索体验,能够大大提升用户对应用的满意度。因此,我们不仅要关注功能的实现,还要从用户体验的角度出发,打造更加人性化的搜索功能。
希望本文能对你在UniApp中实现搜索功能有所帮助。如果有任何问题或建议,欢迎在评论区交流讨论!