小程序【搜索】功能是很常见的,在开发公司的一个电商小程序的时候想尝试使用“云开发”做系统的后端,而首页顶端就有个搜索框,所以第一步想先解决【搜索】的一些前期工作:【最近搜索】和【大家在搜】关键词的存储和读取逻辑。
效果图如下:
效果视频请点击链接查看:
https://v.vuevideo.net/share/post/-2263996935468719531
或者微信扫码观看:
为什么需要这两个功能?
【最近搜索】:可以帮助用户快速选择历史搜索记录(我这里只保存10个),搜索相同内容时减少打字操作,更加人性化;
【大家在搜】:这部分的数据可以是从所有用户的海量搜索中提取的前n名,也可以是运营者想给用户推荐的商品关键词,前者是真实的“大家在搜”,后者更像是一种推广。
具体实现
流程图:
可以结合效果图看流程图,用户触发操作有三种形式:
- 输入关键词,点击搜索按钮;
- 点击【大家在搜】列举的关键词;
- 点击【最近搜索】的关键词
这里发现1和2是一样的逻辑,而3更简单,所以把1和2归为一类(左边流程图),3单独一类(右边流程图)
两个流程图里都含有相同的片段(图中红色背景块部分):“找出这条记录”->“更新其时间”。故这部分可以封装成函数:updateTimeStamp()。
更新时间指的是更新该条记录的时间戳,每条记录包含以下字段:_id、keyword、openid、timeStamp。其中_id是自动生成的,openid是当前用户唯一标识,意味着关键词记录与人是绑定的,每个用户只能看到自己的搜索记录,timeStamp是触发搜索动作时的时间戳,记录时间是为了排序,即最近搜索的排在最前面。
代码结构:
云函数:
cloudfunctions / searchHistory / index.js
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()
exports.main = async (event, context) => {
try {
switch (event.type) {
// 根据openid获取记录
case 'getByOpenid':
return await db.collection('searchHistory').where({
openid: event.openid
}).orderBy('timeStamp', 'desc').limit(10).get()
break
// 添加记录
case 'add':
return await db.collection('searchHistory').add({
// data 字段表示需新增的 JSON 数据
data: {
openid: event.openid,
timeStamp: event.timeStamp,
keyword: event.keyword
}
})
break
// 根据openid和keyword找出记录,并更新其时间戳
case 'updateOfOpenidKeyword':
return await db.collection('searchHistory').where({
openid: event.openid,
keyword: event.keyword
}).update({
data: {
timeStamp: event.timeStamp
}
})
break
// 根据openid和keyword能否找出这条记录(count是否大于0)
case 'canFindIt':
return await db.collection('searchHistory').where({
openid: event.openid,
keyword: event.keyword
}).count()
break
// 根据openid查询当前记录条数
case 'countOfOpenid':
return await db.collection('searchHistory').where({
openid: event.openid
}).count()
break
// 找出该openid下最早的一条记录
case 'getEarliestOfOpenid':
return await db.collection('searchHistory').where({
openid: event.openid
}).orderBy('timeStamp', 'asc').limit(1).get()
break
// 根据最早记录的id,删除这条记录
case 'removeOfId':
return await db.collection('searchHistory').where({
_id: event._id
}).remove()
break
// 删除该openid下的所有记录
case 'removeAllOfOpenid':
return await db.collection('searchHistory').where({
openid: event.openid
}).remove()
break
}
} catch (e) {
console.error('云函数【searchHistory】报错!!!', e)
}
}
cloudfunctions / recommendedKeywords / index.js
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()
exports.main = async (event, context) => await db.collection('recommendedKeywords')
.orderBy('level', 'asc')
.limit(10)
.get()
cloudfunctions / removeExpiredSearchHistory / config.json
// 该定时触发器被设置成每天晚上23:00执行一次 index.js (删除3天前的数据)
{
"triggers": [
{
"name": "remove expired search history",
"type": "timer",
"config": "0 0 23 * * * *"
}
]
}
cloudfunctions / removeExpiredSearchHistory / index.js
const cloud = require('wx-server-sdk')
cloud.init()
const db = cloud.database()
const _ = db.command
let timeStamp = new Date().getTime()
// 删除3天前的数据
let duration = timeStamp - 1000 * 60 * 60 * 24 * 3
exports.main = async (event, context) => {
try {
let arr = await db.collection('searchHistory').where({
timeStamp: _.lt(duration)
}).get()
let idArr = arr.data.map(v => v._id)
console.log('idArr=', idArr)
for (let i = 0; i < idArr.length; i++) {
await db.collection('searchHistory').where({
_id: idArr[i]
}).remove()
}
} catch (e) {
console.error(e)
}
}
search.js 关键代码:
// 输入关键词,点击搜索
tapSearch: function () {
let that = this
if (that.data.openid) {
// 只为已登录的用户记录搜索历史
that.tapSearchOrRecommended(that.data.keyword, that.data.openid)
} else {
// 游客直接跳转
wx.navigateTo({
url: `../goods-list/goods-list?keyword=${that.data.keyword}`,
})
}
},
// 点击推荐的关键词
tabRecommended: function (e) {
let that = this
let keyword = e.currentTarget.dataset.keyword
that.setData({
keyword
})
if (that.data.openid) {
// 只为已登录的用户记录搜索历史
that.tapSearchOrRecommended(keyword, that.data.openid)
} else {
// 游客直接跳转
wx.navigateTo({
url: `../goods-list/goods-list?keyword=${keyword}`,
})
}
},
// 点击历史关键词
tabHistory: function (e) {
let that = this
let keyword = e.currentTarget.dataset.keyword
wx.navigateTo({
url: `../goods-list/goods-list?keyword=${keyword}`,
})
that.updateTimeStamp(keyword, that.data.openid)
},
// 获取历史记录和推荐
getHistoryAndRecommended: function () {
let that = this
try {
// 只为已登录的用户获取搜索历史
if (that.data.openid) {
let searchHistoryNeedUpdate = app.globalData.searchHistoryNeedUpdate
const searchHistory = wx.getStorageSync('searchHistory')
// 如果本地有历史并且还没有更新的历史
if (searchHistory && !searchHistoryNeedUpdate) {
console.log('本地有搜索历史,暂时不需要更新')
that.setData({
searchHistory
})
} else {
console.log('需要更新(或者本地没有搜索历史)')
wx.cloud.callFunction({
name: 'searchHistory',
data: {
type: 'getByOpenid',
openid: that.data.openid
},
success(res) {
console.log('云函数获取关键词记录成功')
let searchHistory = []
for (let i = 0; i < res.result.data.length; i++) {
searchHistory.push(res.result.data[i].keyword)
}
that.setData({
searchHistory
})
wx.setStorage({
key: 'searchHistory',
data: searchHistory,
success(res) {
console.log('searchHistory本地存储成功')
// wx.stopPullDownRefresh()
app.globalData.searchHistoryNeedUpdate = false
},
fail: console.error
})
},
fail: console.error
})
}
}
// 获取推荐关键词
wx.cloud.callFunction({
name: 'recommendedKeywords',
success(res) {
console.log('云函数获取推荐关键词记录成功')
let recommendedKeywords = []
for (let i = 0; i < res.result.data.length; i++) {
recommendedKeywords.push(res.result.data[i].keyword)
}
that.setData({
recommendedKeywords
})
},
fail: console.error
})
} catch (e) {
fail: console.error
}
},
// 添加该条新记录(tapSearchOrRecommended()要用到它两次)
addRecord: function (keyword, timeStamp) {
let that = this
// 【添加】
wx.cloud.callFunction({
name: 'searchHistory',
data: {
type: 'add',
openid: that.data.openid,
keyword,
timeStamp
},
success(res) {
console.log('云函数添加关键词成功')
app.globalData.searchHistoryNeedUpdate = true
},
fail: console.error
})
},
// 根据openid和keyword找出记录,并更新其时间戳
updateTimeStamp: function (keyword, openid) {
this.setData({
keyword
})
let timeStamp = new Date().getTime()
wx.cloud.callFunction({
name: 'searchHistory',
data: {
type: 'updateOfOpenidKeyword',
openid,
keyword,
timeStamp,
},
success(res) {
console.log('云函数更新关键词时间戳成功')
app.globalData.searchHistoryNeedUpdate = true
},
fail: console.error
})
},
// 输入关键词,点击搜索或者点击推荐的关键词
tapSearchOrRecommended: function (keyword, openid) {
let that = this
if (!keyword) {
wx.showToast({
icon: 'none',
title: '请输入商品关键词',
})
setTimeout(function () {
that.setData({
isFocus: true
})
}, 1500)
return false
}
wx.navigateTo({
url: `../goods-list/goods-list?keyword=${keyword}`,
})
let timeStamp = new Date().getTime()
// 【根据openid和keyword能否找出这条记录(count是否大于0)】
wx.cloud.callFunction({
name: 'searchHistory',
data: {
type: 'canFindIt',
openid,
keyword
},
success(res) {
console.log('res.result.total=', res.result.total)
if (res.result.total === 0) {
// 集合中没有
// 【根据openid查询当前记录条数】
wx.cloud.callFunction({
name: 'searchHistory',
data: {
type: 'countOfOpenid',
openid
},
success(res) {
// 记录少于10条
if (res.result.total < 10) {
// 【添加】
that.addRecord(keyword, timeStamp)
} else {
// 【找出该openid下最早的一条记录】
wx.cloud.callFunction({
name: 'searchHistory',
data: {
type: 'getEarliestOfOpenid',
openid
},
success(res) {
console.log('云函数找出最早的一条关键词成功', res.result.data[0])
let _id = res.result.data[0]._id
// 【根据最早记录的id,删除这条记录】
wx.cloud.callFunction({
name: 'searchHistory',
data: {
type: 'removeOfId',
_id
},
success(res) {
console.log('云函数删除最早的一条关键词成功')
// 【添加】
that.addRecord(keyword, timeStamp)
},
fail: console.error
})
},
fail: console.error
})
}
},
fail: console.error
})
} else {
// 【根据openid和keyword找出记录,并更新其时间戳】
that.updateTimeStamp(keyword, openid)
}
},
fail: console.error
})
}