引言
在开发中经常遇到需要搜素之后在返回的列表中再选择的需求,能便利在大量数据中的选择行为,有一些已有的组件例如select2.js、iview的AutoComplete组件等等。由于小程序没有类似的组件,只能自己写一个,其实比较基础,欢迎阅读。
分析思路
思路是这样的:
- 为了适应各种返回格式不同的接口,组件应该直接接收一个数组,数据请求最好由父页面完成,后台返回的数据可能不是字符串数组,更有可能是对象数组,因此还要有参数指定显示的属性名;
- 搜索却是在组件中进行的,所以搜索内容要传给父级页面作为接口参数,接口需要做节流;
- 选中后将选中的下标返回父页,然后执行回调,因为很多选中后还会联动其余值的填入,其他数据一般也在选中的对象中,在父页面用下标直接从数组中获取就可以了;
效果图如下,截图是开发工具里的,手机上滚动条没这么丑^ ^
组件编写
组件名为search-picker,在开发工具右键新建Components,由于组件内及父页面都能控制组件的显示隐藏(组件内是选中后直接隐藏),所以隐藏状态要保持一致,否则会出现父页面触发了却不显示的问题。
1、组件的js
//components/search-picker/search-picker.jsComponent({ 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。以上就是全部啦,有问题的话,欢迎指正~














