在小程序中实现历史搜索记录
孙泽辉

最近老板想让单号搜索之后缓存起来,下次搜索的时候能显示历史搜索过的单号,立即联想到微信小程序是支持Storage存储的,三下五除二就写出来了!

效果

搜索后再次点击输入框会弹出历史记录列表,点击某条记录就会查询出结果来。

实现

首先写出html结构来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<view class="input-group {{historyShow? 'history-show' : ''}}">
<view class="input-box">
<input class="input" bindfocus='focus' bindblur='blur'></input>
<text class="icon iconfont icon-search"></text>
</view>
</view>
<button class="primary-btn" bindtap="doSearch">
查询
</button>
<view class="history">
<ul>
<li wx:for="{{historyList}}" wx:key="time" data-key="{{item.value}}" bindtap="onHistoryTap">{{item.value}}</li>
</ul>
</view>
</view>

为了节省篇幅,省略了点不必要的细节,

使用变量historyShow控制列表展示,展示时,为搜索框和历史记录添加外边框。

当时遇到了点击搜索框抖动的问题,是因为给输入框添加外边框的时候,增加了1rpx像素的大小,解决方法是给输入框提前设置1rpx透明的外边框。

问题复现:

这是我的css样式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
.input-group {
width: 90%;
margin: 0 auto;
margin-top: -20px;
display: flex;
position: relative;
.input-box {
position: relative;
font-size: 28rpx;
box-sizing: border-box;
padding-left: 80rpx;
background-color: white;
border-radius: 20px;
width: 73%;
// 提前占位1像素边框
border: 1rpx solid transparent;
.icon {
position: absolute;
font-size: 28rpx;
left: 35rpx;
top: 30rpx;
}
.input {
height: 90rpx;
overflow: hidden;

box-shadow: 24px 22px 26px -24px rgba(0, 0, 0, 0.1);
}
.input-placeholder {
color: #ccc;
}
}

.history {
position: absolute;
left: 0;
width: 73%;
top: 90rpx;
display: none;
background-color: white;
ul {
display: flex;
flex-direction: column;
text-align: left;
font-size: 35rpx;
border: 1px solid gray;
border-radius: 20rpx;
border-top: 0;
border-top-left-radius: 0;
border-top-right-radius: 0;
li {
margin: 0 40rpx;
padding: 20rpx 0;
border-bottom: 1px solid rgb(241, 243, 243);
}
}
}
&.history-show .input-box {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;

border: 1px solid gray;
}
&.history-show .history {
display: block;
}

.primary-btn {
width: 25%;
padding: 0;
height: 90rpx;
line-height: 80rpx;
font-size: 28rpx;
background-color: white;
border-radius: 50px;
}
}

样式就不细说了,也没做的多好看。。。

显示历史记录是由focus触发,所以监听它,在事件处理函数中查询历史记录并展示出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// pages/index/index.js
const { getStorage } = require("../../utils/util");
Page({
/**
* 页面的初始数据
*/
data: {
inputContent: "",
historyShow: false,
isStorageEmpty: true,
historyList: [],
},
// 点击某条历史记录时
onHistoryTap(evt) {
const key = evt.target.dataset.key;
// 填充输入框后查询详细信息
this.setData(
{ inputContent: key },
this.doSearch
);
},
// 去Storage查询历史记录列表,并排序
getStorageHistoryList(callback = () => {}) {
const data = getStorage();
this.setData(
{
historyList: data.sort((a, b) => Number(b.time) - Number(a.time)),
},
() => callback(data)
);
},
// 聚焦事件处理函数
focus: function () {
this.getStorageHistoryList((data) => {
// 如果没有数据则不展示
if (!data.length) return;
this.setData({
historyShow: true,
});
});
},
// 失焦后隐藏
blur: function () {
this.setData({
historyShow: false,
});
},
});

添加历史记录是在搜索之后,所以我将添加记录放到了getData工具函数的回调当中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
const app = getApp();
// 根据接口名字匹配 URL 路径
const typeMap = {
"arrival-report": "/order/psn027/v1",
"customs-clearance": "/order/psn026/v1",
"base-info": "/order/base/info/v1",
"pre-allocated-manifest": "/order/psn004/v1",
};

// 接口请求封装
function getData(type, masterBlNo) {
if (!masterBlNo || masterBlNo.length === 0) {
wx.showModal({
title: "提示",
content: "请输入提运单号",
showCancel: false,
});
return Promise.reject();
}

wx.showLoading({
title: "加载中",
});

return new Promise((resolve, reject) => {
wx.request({
url: app.globalData.baseUrl + typeMap[type],
data: {
masterBlNo,
},
header: { "content-type": "application/json" },
method: "GET",
dataType: "json",
responseType: "text",
success: (result) => {
wx.hideLoading();

if (result.data.code != 200) {
wx.showModal({
showCancel: false,
title: "错误",
content: result.data.msg,
});
}
if (!result.data.data || result.data.code != 200) {
reject();
}

resolve(result.data);
},
fail: (e) => {
console.log(e.message);
wx.showModal({
showCancel: false,
title: "错误",
content: "请检查网络!",
});
reject();
},
complete: () => {
// 在完成之后将单号存储下来
setStorage(masterBlNo);
},
});
});
}

// 从Storage读取数据
function getStorage() {
const data = wx.getStorageSync("history");
if (data === "") return [];
return JSON.parse(data);
}

// 持久化存储数据
function setStorage(value) {
const oldData = getStorage();
// 已经添加过的不再添加
const isExist = oldData.some((item) => item.value === value);
if (isExist) return Promise.reject();

return new Promise((resolve, reject) => {
wx.setStorage({
key: "history",
// 追加数据并记录时间,方便查询最近搜索记录
data: JSON.stringify(oldData.concat([{ time: +new Date(), value }])),
success(r) {
resolve(r);
},
fail(e) {
reject(e);
},
});
});
}
module.exports = {
getData,
setStorage,
getStorage,
};

就这些吧,也挺简单的。

 Comments
Comment plugin failed to load
Loading comment plugin
Powered by Hexo & Theme Keep
This site is deployed on
Total words 89.4k