引言
在开发中经常遇到需要搜素之后在返回的列表中再选择的需求,能便利在大量数据中的选择行为,有一些已有的组件例如select2.js、iview的AutoComplete组件等等。由于小程序没有类似的组件,只能自己写一个,其实比较基础,欢迎阅读。
分析思路
思路是这样的:
- 为了适应各种返回格式不同的接口,组件应该直接接收一个数组,数据请求最好由父页面完成,后台返回的数据可能不是字符串数组,更有可能是对象数组,因此还要有参数指定显示的属性名;
- 搜索却是在组件中进行的,所以搜索内容要传给父级页面作为接口参数,接口需要做节流;
- 选中后将选中的下标返回父页,然后执行回调,因为很多选中后还会联动其余值的填入,其他数据一般也在选中的对象中,在父页面用下标直接从数组中获取就可以了;
效果图如下,截图是开发工具里的,手机上滚动条没这么丑^ ^
组件编写
组件名为search-picker,在开发工具右键新建Components,由于组件内及父页面都能控制组件的显示隐藏(组件内是选中后直接隐藏),所以隐藏状态要保持一致,否则会出现父页面触发了却不显示的问题。
1、组件的js
//components/search-picker/search-picker.js
Component({
properties: {
list:{
type:Array,
value:[]
},//可选列表
placeholder:{
type:String,
value:'请输入内容进行选择'
},
key:{
type:String,
value:'title'
},//列表显示的字段名,默认是title
show:{
type:Boolean,
value:false
},//是否显示组件
},
data: {
inputVal:'',//输入内容
},
methods: {
//获取组件输入的内容传递给父页面
getInput: function (e) {
this.setData({
inputVal:e.detail.value
});
this.triggerEvent('getInput', this.data.inputVal);
},
//选中结果后,将下标传递给父页面,并隐藏组件
select: function (e) {
let index = e.currentTarget.dataset.index;
let key = this.data.key;
this.setData({
show:false
});
this.triggerEvent('getSelect',index)
},
//清空输入
clearSelect: function () {
this.setData({
inputVal:'',
});
},
//隐藏组件,必须将隐藏状态传递给父页面,因为父页面也有控制隐藏显示的属性,不传递的话,该属性还是true
hidePicker: function () {
this.setData({
show:false,
});
this.triggerEvent('showFn',false)
}
}
});
2、组件的wxml
<!--components/search-picker/search-picker.wxml-->
<!--搜索选择组件,父级包含组件的元素要相对定位,否则组件无法定位-->
<view class="searchPicker" hidden="{{!show}}">
<view class="inputView">
<input type="text"
value="{{inputVal}}"
placeholder="{{placeholder}}"
placeholder-class="placeholder"
bindinput="getInput"
/>
<!--清空输入-->
<icon type="clear" size="18" hidden="{{inputVal==''}}" bindtap="clearSelect"></icon>
</view>
<scroll-view class="list" scroll-y>
<!--有结果显示列表-->
<block wx:if="{{list.length!=0}}">
<view wx:for="{{list}}"
wx:key="{{index}}"
class="item"
bindtap="select"
data-index="{{index}}">
<!--如果没有传key,说明是字符串数组,直接访问item-->
<text class="item">{{item[key]||item}}</text>
</view>
<text class="tips">没有想要的结果?请输入更精确的关键字~</text>
</block>
<!--没有结果-->
<text wx:if="{{inputVal!='' && list.length==0}}" class="tips">抱歉,没有结果哦~</text>
</scroll-view>
</view>
<!--用来点击组件外部隐藏-->
<view class="closePicker" hidden="{{!show}}" bindtap="hidePicker"></view>
组件使用
1、使用页面的json中要声明
"usingComponents": {
"search-picker":"/components/search-picker/search-picker"
}
2、组件标签的使用
<!--组件使用页面.wxml-->
<view class="formItem" style="position: relative">
<text class="itemTitle">**名称<text class="red">*</text></text>
<input type="text" disabled value="{{clientname}}" bindtap="showPickerFn"
placeholder="请选择**名称" placeholder-class="placeholder"/>
<search-picker
placeholder="请输入名称进行选择"
key="{{clientKey}}"
list="{{clientList}}"
show="{{showSearch}}"
bindgetInput="getInput"
bindgetSelect="getSelect"
bindshowFn="showFn"
class="searchPicker"
></search-picker>
</view>
3、组件所需参数及回调
//组件使用页面.js
...
data:{
clientname: '',//选中名称
clientList: [],//机构可选列表
showSearch:false,//是否显示
clientKey:'name',//列表中显示的字段名
timeout:'',//计时器
...
},
//显示搜索选择框
showPickerFn:function(){
this.setData({
showSearch:!this.data.showSearch
});
//可以在这里提前传空值请求一次列表,可返回一个初始的列表
this.getClientList('');
},
//获取组件中输入的内容
getInput: function(e){
let that = this;
// 若已经有定时任务,将其清除,重新定义新的计时器,在输入长时间停顿之前不请求接口
if(this.data.timeout!=''){
clearTimeout(this.data.timeout);
}
let timeout = setTimeout(function () {
that.getClientList(e.detail)
},800);
this.setData({
timeout:timeout
});
},
//根据输入的内容请求数据,搜索数据列表
getClientList: function(key){
let that = this;
<!--这里是项目里封装好的wx.request,可直接用wx.request-->
app.ajax({
method:'post',
url:'/url/clients',
data:{
key:key
}
}).then(resp=>{
that.setData({
clientList:resp.list,
})
});
},
//将组件选中的项回填
getSelect: function(e){
let index = e.detail;
let that = this;
this.setData({
clientname:that.data.clientList[index].title,
clientid:that.data.clientList[index].id,
showSearch:false
})
//把选中的数据重置为空
this.resetData();
//根据id做其他数据请求
this.getCompany(that.data.clientList[index].id);
···
},
// 隐藏回调,即组件中隐藏了组件后,父级也要同步
showFn: function(e){
this.setData({
showSearch:e.detail,
})
},
···
样式就不粘了,需要的话可以去github。 以上就是全部啦,有问题的话,欢迎指正~