设想
小程序名《小小工具集合》,欢迎试用与建议
一直以来,我都在考虑是不是有一种集大成的查询工具,可以实现很多的查询功能,于是在很久以前,我就写了这个网站:
嗯,就是你输入内容,然后就可以自动匹配搜索引擎,如:“秋装 淘宝”,会根据最后空格后的淘宝,自动进入淘宝页面,如下:
我猜没几个人用,所以就自娱自乐。
忽然间,我想到,弄个小程序,类似。但是小程序调用 webview 很麻烦,便打算做一个功能型小程序。
预览
上面这个是当前版本,本文只讨论第一版。
初版构思
初版功能就是检索我私藏的数据,至于数据嘛,这么多年的 Excel,网上找到后,转成 JSON 就妥了。
所以初版功能:邮编号、机场三字码、车牌简写与省市区匹配。
初版的 UI 是根据计算器来的,我在想,是不是一个显示屏就可以显示所有的内容……
初版实现
wxml
<text id='total'>{{totalCount}}条</text>
<scroll-view id='result-display' scroll-y>
<text wx:for="{{results}}" wx:key="{{index}}">{{item + '
'}}</text>
</scroll-view>
<view id='input-container'>
<input id='main-input' placeholder='输入搜索内容' focus="{{true}}" bindconfirm='search' bindinput='input' value="{{inputValue}}"></input>
<button id='clear-button' bindtap='clear'>X</button>
</view>
<view id='buttons'>
<button class='search-button' bindtap='search' wx:for="{{engines}}" wx:key="{{index}}" data-engine="{{item}}">{{item.name}}</button>
</view>
从上到下,检索条目、显示屏、输入框与功能按钮。
个人不喜欢太多层级的树,所以没有套个 container,算是 Web 的习惯吧。
wxss
/**index.wxss**/
#result-display {
position: relative;
height: 400rpx;
padding: 40rpx;
box-sizing: border-box;
margin-top: 20rpx;
border: 2rpx solid #999;
}
#total {
position: absolute;
top: 20rpx;
right: 20rpx;
display: block;
color: #999;
font-size: 24rpx;
}
#input-container {
position: relative;
margin-top: 20rpx;
}
#main-input {
width: calc(100% - 140rpx);
height: 80rpx;
border: 2rpx solid #d8d8d8;
padding-left: 40rpx;
border-radius: 10rpx;
}
#clear-button {
position: absolute;
top: 10rpx;
right: 18rpx;
width: 64rpx;
height: 64rpx;
padding: 0;
font-size: 26rpx;
}
#engines {
height: calc(100% - 550rpx);
margin-top: 20rpx;
}
.title {
font-size: 32rpx;
color: #999;
margin-left: 20rpx;
}
#buttons {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
}
.search-button {
position: relative;
width: 30%;
margin-bottom: 20rpx;
font-size: 28rpx;
font-weight: 900;
}
wxss 没啥可说的,看效果:
js
//index.js
//获取应用实例
const app = getApp()
const AV = app.globalData.AV
let currentEngine = null // 当前锁定的引擎
Page({
data: {
engines: [],
inputValue: '', // 搜索字符
results: [], // 搜索出来的结果
totalCount: 0, // 总数
},
//事件处理函数
bindViewTap: function() {
},
clear() {
this.setData({
inputValue: '',
results: [],
totalCount: 0,
})
},
input(e) {
this.setData({
inputValue: e.detail.value
})
},
// 搜索
search(e) {
if (!this.data.inputValue) {
wx.showToast({
title: '请输入内容',
icon: 'none'
})
return
}
this.setData({
results: [], // 习惯性清空之前数据
})
const engine = e.target.dataset.engine
// 按钮点击赋值新的引擎
if (engine) currentEngine = engine
this.getResult()
},
// 获取搜索结果
getResult() {
const value = this.data.inputValue
const className = currentEngine.className
this.localEngine(value, className)
},
// LeanCloud 自有的数据
localEngine(value, className) {
let querys = [] // 或条件
for (const item of currentEngine.keys) {
querys.push(new AV.Query(className)
.contains(item, value))
}
wx.showLoading({
title: '努力检索数据库中……',
})
AV.Query.or(...querys)
.find()
.then(res => {
wx.hideLoading()
if (!res.length) {
wx.showToast({
title: '没有找到相关结果',
icon: 'none'
})
return
}
let results = []
for (const item of res) {
const resultObj = item.attributes
resultObj.next = '-----------------'
for (const key in resultObj) {
results.push(`${key}: ${resultObj[key]};`)
}
}
const totalCount = res.length
this.setData({
results,
totalCount
})
if (totalCount > 99) wx.showModal({
title: '内容超出100条',
content: '建议检索条件更加丰富。',
showCancel: false,
})
})
.catch(err => {
wx.hideLoading()
console.log(err)
})
},
// 获取所有可搜索引擎
getEngines() {
wx.showLoading({
title: '加载引擎中……',
})
new AV.Query('Engines')
.find()
.then(res => {
wx.hideLoading()
this.setData({
engines: Array.from(res, item => {
return {
name: item.get('name'),
className: item.get('className'),
keys: item.get('keys'),
url: item.get('url')
}
})
})
})
.catch(err => {
console.log(err)
wx.hideLoading()
})
},
onLoad() {
this.getEngines()
},
onShareAppMessage(res) {
if (res.from === 'button') {
console.log(res.target)
}
return {
title: '实用的工具集合,你也来一个吧。',
}
}
})
分析代码
onLoad() {
this.getEngines()
}
这句说明落地先获取引擎列表(这里说是引擎,只是命名,其实就是数据库表)。
获取到引擎对象后,转成我们需要的数据结构,在后续使用:
this.setData({
engines: Array.from(res, item => {
return {
name: item.get('name'),
className: item.get('className'),
keys: item.get('keys'),
url: item.get('url')
}
})
})
这些整理后的引擎,都会绑定在每个 button 的 data 数据上,好在后面点击的时候直接获取到。
每一个 button 都有这么个东西:data-engine="{{item}}"
然后此时页面就已经渲染好了,接下来就是交互了。
input(e) {
this.setData({
inputValue: e.detail.value
})
},
这句是在输入内容的时候,把输入的值放到 data 的 inputValue 上,并且通过 wxml 我们知道,这个 inputValue 是绑定在 input 的 value 上的,这样就可以在后面使用的时候直接调用:this.data.inputValue
来直接获取 input 的 value,不用每次都 e.detail.value
了。
下面就是点击了。
search(e) {
if (!this.data.inputValue) {
wx.showToast({
title: '请输入内容',
icon: 'none'
})
return
}
this.setData({
results: [], // 习惯性清空之前数据
})
const engine = e.target.dataset.engine
// 按钮点击赋值新的引擎
if (engine) currentEngine = engine
this.getResult()
}
这里不说上面那个 X 按钮,那就是清空 input 的 value 以及上面显示屏内容功能。
search 是下面功能按钮的点击事件,做了这么几件事:
- 如果 input 没有 value,就直接提示并返回。
- 清空当前显示屏数据,避免用户郁闷数据串了。
- 将点击的引擎赋予到一个当前页面的全局变量中(当前页面的全局,不是 App 全局)。
- 一切正常,开始搜索结果。
getResult() {
const value = this.data.inputValue
const className = currentEngine.className
this.localEngine(value, className)
}
这里主要是获取两个关键变量,value 自不用说,className 是我所用的云后端相关,无视即可。
localEngine 以及这个中间步 getResult 是为了后期拓展使用。
localEngine 内容看似很多,其实就是向服务器获取数据,然后排列展示在显示屏上,所以这里不占用篇幅多说,因为每个人的服务器或获取数据方式不同,无法概论。
到此,这个小程序就完成了,是不是还是蛮简单的。
终极效果
这里尴尬的那个不是 bug 哦,那是输入框右下角确认(PC 是回车,我顺手点了回车)会默认使用当前引擎搜索内容,里面是输入了“粤D”回车,搜索的是之前的邮编号,当然没有东西了。
欢迎关注,如有需要 Web,App,小程序,请留言联系。