系列篇
基于微信小程序 + colorUI 做的form表单封装——input
文章目录
前言
上周发了基于微信小程序 + colorUI 做的form表单封装——input之后,喜提三个评论 + 一个码云star,本想尽快整理出其他表单格式,但是年后公司项目开了不少,以至于一直拖到今天,给各位期待更新的小伙伴们(划掉、并没有这样的小伙伴)抱拳了,让你们久等了。
本篇为大家带来的是本系列的第二篇 ——picker(选择器)。表单格式的更新顺序,是按照本公司项目使用表单组件的频率高低更新的,大家更需要怎样的表单组件,请在评论区告诉我,我会提前更新。
由于本插件集成了一部分的业务代码,所以可配置项会少一点,对于与本插件业务符合度高的项目,用着会很方便;但是业务符合度低的,体验肯定会差很多。这个时候,欢迎大家去修改源码,使之符合自己的业务需求,同时我也会尽力将这些组件完善,将代码写的优美一些,让大家可以少走弯路,让我们一起学习、一起进步。
本系列的目的主要是记录学习+交流,非技术科普,大家有什么问题欢迎指出。
求赞求评论求star
一、先看效果
1.picker目前支持的动态配置
/**
* 当且仅当 type === 'picker' 显示该组件
*
* 参数说明
* 公共参数:
* topLine 默认没有上划线,可加
* clearBottomLine 默认有下划线,可删
* label 输入框标题(最大长度为6,溢出隐藏)
* requied 是否必填(显示红星)
* submitName 向后台约定的数据提交字段名,如:姓名 —— name; 性别 —— sex; 年龄 —— age
* disabled 是否禁用
* value 选择的值
* placeholder + noPlaceholder 默认为“‘请选择’ + 输入框标题(label)” 通过placeholder可自定义
* 也可通过noPlaceholder 来清除默认placeholder
*
* 特定参数说明:
* 当mode === 'selector'时, 选择器为单列选择器
* range 范围,目前支持俩种数据类型:
* 第一种:['中国', '美国', '日本']
* 第二种:[{ id: 0, name: '中国' }, { id: 1, name: '美国' }, { id: 2, name: '日本' }]
* rangeKey 当使用第二种jion类型时,需指定展示的字段名称,如该例子就需要指定rangeKey = 'name'
* 第一种类型就不要写这个参数了,切记切记
* dictField 如range是由接口动态获取的,那么在此配置参数,onLoad时会统一查询数据字典(详细代码已封装)
*
* 当mode === 'time'时,选择器为时间选择器
* start - end 有效时间范围的开始or结束 默认不限制
*
* 当mode === 'date'时,选择器为日期选择器
* start - end 有效日期范围的开始or结束 默认不限制
* fields 选择器的粒度,默认为day(天),可改为year(年)、month(月)
*
*/
2.配置代码
{ label: '静态-数组', submitName: 'picker1', type: 'picker', mode: 'selector', value: '', requied: true, range: ['是', '否']},
{ label: '静态json', submitName: 'picker2', type: 'picker', mode: 'selector', value: '', requied: true,
rangeKey: 'name', range: [
{ id: '01', name: '美国' },
{ id: '02', name: '中国' },
{ id: '03', name: '巴西' },
{ id: '04', name: '日本' }
]},
{ label: '动态json', submitName: 'picker3', type: 'picker', mode: 'selector', value: '', requied: true, dictField: 'choose', range: [], rangeKey: 'name'},
{ label: '时间选择', submitName: 'picker4', type: 'picker', mode: 'time', value: '', requied: true, start: '05:05', end: '07:10'},
{ label: '日期选择', submitName: 'picker5', type: 'picker', mode: 'date', value: '', requied: true, start: '2021-01-01', end: '2025-01-01', fields: ''}
3.效果展示
- 配置完成后,只需上述简单的代码,就可以得到下图红框的picker选择器
- picker选择内容后,会自动将内容发送到配置数组的 “value” 字段中,自动做必填验证
- 需要接口请求的数据字典,只需要简单配置,就可实现选择器的动态数据加载
- 目前支持单列选择器(静态数据 + 动态数据)、时间选择器、日期选择器
- 二级、三级联动的选择器会单独开一篇文章细讲
二、详细步骤
1.引入colorUI和aw
- 如果你对这个小插件感兴趣,但是并没有去看第一篇,那我强烈建议先去看一下:基于微信小程序 + colorUI 做的form表单封装——input,本篇代码是在上篇代码的基础上增加的,看完第一篇,使用的会更愉快一些
- 由于本组件的ui主要用的是 colorUI ,所以先将 colorUI 应用到项目中,方法很简单,colorUI 的github描述的也很详细,在这里就不多赘述了
- 去 码云、github项目中下载aw
(1)将utils文件夹下的“WxValidate.js” 、 “formMethods.js”和api文件夹,放入自己项目的utils文件夹下(最好放在根路径utils文件夹下,路径不同则需要在aw_picker.js中修改路径;已经引了的小伙伴可以重新拉取下最新的)
可能出现的bug1:如果你看到这样的报错
那是因为在request.js中使用了async/await,小程序默认是不支持这个特性的,但是要修改也很简单,打开本地配置的“增强编译”就好
(2)将components中的form文件夹拉到你的项目里(不需要根目录,放在components下就可以)
可能出现的bug2:如果路径路径不相同的话,此时控制台会弹一个报错
这个报错是这行代码引起的,可能是获取的地址有问题,修改引入的地址就好
这行代码的作用是当数据为动态获取时,所调的数据字典api接口,在“getRange”方法里有使用
1、目前picker调用动态数据,主流的解决方案是在onshow的时候调接口并放入picker的range里,但是这种方法在实际项目过程中,是存在风险的,如onshow的时候,由于网络或者服务器原因,并没有拿到数据字典,那这时候我们就需要二次获取;
2、针对这个问题,博主首先想到的方法是onshow的时候不做任何处理,点击picker时发起请求,拿到数据后渲染视图,但是这个方法失败了,我在微信开放社区反馈该问题点击 picker 动态获取数据,视图为什么不刷新?得到的回答是微信原生的picker容器并不支持这样做,好在给我指了一条明路——picker-view是支持的,所以我将这部分的逻辑改成了:onshow的时候调接口拿数据,如果数据拿到了,那么使用picker容器;如果因为一些问题,没拿到数据,那么使用我自己封装的picker-view容器;
3、所以就很清楚了,报错的那行代码是点击picker-view时,去后台拿数据字典的。我们公司获取数据字典的接口,只有后面的参数有变化,比如:“abc.com/getdictField?name=choose”、“abc.com/getdictField?name=sex”, 这俩分别是获取“是否”和“性别”的,那我们只需要把后面的字段放到dictField字段中,之后拼接接口,获取数据(这段说的比较细,看着字多,其实很简单)
4、本组件里是这样获取字典的,大家可能还需要微调下“getRange”函数
5、当然,如果你的项目里,数据字典都是前端写的,以上你都可以忽略,直接把引入api的那行报错代码注释掉就可以了 - 最后去app.json中的“usingComponents”里注册该组件(当然,也可以不注册全局组件,哪个页面用,在哪个页面注册也是可以的)
2.使用
- 新建一个页面form(上篇就开始跟的大兄弟就不需要了),这就是要使用该组件的页面
- 在form.wxml中添加如下代码
<!--pages/form/form.wxml--> <view wx:for="{{form}}" wx:key="index"> <aw-input wx:if="{{item.type === 'input'}}" formItem='{{item}}' index='{{index}}'></aw-input> <aw-picker wx:if="{{item.type === 'picker'}}" formItem='{{item}}' index='{{index}}'></aw-picker> </view> <!-- 点击该按钮验证是否符合规范 --> <button style="margin: 200px auto" bindtap="submitForm">提交</button>
-
在form.js中的data里的form数组里增加如下代码
{ label: '静态-数组', submitName: 'picker1', type: 'picker', mode: 'selector', value: '', requied: true, range: ['是', '否']}, { label: '静态json', submitName: 'picker2', type: 'picker', mode: 'selector', value: '', requied: true, rangeKey: 'name', range: [ { id: '01', name: '美国' }, { id: '02', name: '中国' }, { id: '03', name: '巴西' }, { id: '04', name: '日本' } ]}, { label: '动态json', submitName: 'picker3', type: 'picker', mode: 'selector', value: '', requied: true, dictField: 'choose', range: [], rangeKey: 'name'}, { label: '时间选择', submitName: 'picker4', type: 'picker', mode: 'time', value: '', requied: true, start: '05:05', end: '07:10'}, { label: '日期选择', submitName: 'picker5', type: 'picker', mode: 'date', value: '', requied: true, start: '2021-01-01', end: '2025-01-01', fields: ''}
- ok,给自己鼓个掌,我们成功一半了
- 现在第一、第二、第四、第五个选择器已经可以正常工作了,选择数据后也会同步到form.js里data.form中
- 第二条“动态数据”的选择器点击之后,我们看到选择列表是空的,那是因为我们给第二条增加了一个参数“dictField: 'choose'”,因为增加“dictField”字段,我们的组件就会认为它的range是需要动态获取的,所以接下来我们把批量获取数据字典的方法引进来
3.动态获取数据字典
想实现批量获取数据字典,我们只需要在onLoad函数中调用一个事先封装好的getFormDict函数
不需要动态获取数据字典的可跳过这段
- 还记得我们前面在picker.js中引入的formMethods.js嘛?我们在form.js中同样引入formMethods.js。
在这里引入的目的是要在onshow的时候统一批量获取数据字典;picker.js引入是防止onshow的时候有一些接口没有拿到数据,所以在点击picker-view组件的时候再次获取 -
// picker 批量获取动态数据 const getFormDict = function(form, context) { form.forEach((item, index) => { if (item.type === 'picker' && item.dictField && item.dictField !== '') { /** * dictionary.getdictField 是封装好的获取数据字典的请求方法,大家可以使用自己的,也可以用我在request中封装好的 * 目的是根据“dictField”值,取后台获取数据字典,并放入range中,就算成功 * */ dictionary.getdictField({name: item.dictField}).then(res => { if (res.code === 200) { // onshow 获取动态字典请求成功、展示picker单选框 let list = res.data; context.setData({ ['form['+ index +'].range']: list }); } else { // onshow 获取动态字典请求失败、展示自定义picker-view单选框,picker-view可以在点击的时候获取数据 context.setData({ ['form['+ index +'].showPickerView']: true }); } }).catch(err => { // onshow 获取动态字典请求失败、展示自定义picker-view单选框,picker-view可以在点击的时候获取数据 console.log(err); context.setData({ ['form['+ index +'].showPickerView']: true }); }) } }) };
以formMethods中的getFormDict为例(picker.js中的getRange函数类似,只是一个是批量发起请求,一个是单独发请求)
代码逻辑超简单
(1)遍历form,过滤需要发起数据字典的json;
(2)拼接url,发起请求;
①请求成功,将数据字典塞入json的range中,数据覆盖,结束
②请求失败,将 “showPickerView”赋值为true,picker容器改为picker-view容器(俩个容器样式一样,不必担心视图有变化),到了这一步,picker.js中的getRange方法就能用上了,点击picker-view,可以重新发起请求,并渲染到视图中 -
将picker.js的getRange方法与formMethods.js的getFormDict方法修改完后,第三个“动态数据”的选择器也应该成功了,现在只差最后一步,数据提交前的校验
4.数据校验
这个就更简单了,去form.js中复制submitForm函数,放到自己的form.js中就可以了
/**
* 格式为:['中国', '美国'] 等数组类型的,value值为数组里的item
* 格式为:[{name: '中国', id: '01'}, {name: '美国', id: '02'}]等json数组的,value值为json里的id
* 也可以在submitForm函数中修改要放入value的参数
*/
总结
前面的步骤问题不大,主要是动态数据接口封装那,我可能夹带了自己的一些编程思想,以至于很局限,大家可能会看着不是很舒服,当然我只是提供一个思路,大家完全可以根据自己的编码风格封装一套适合自己的插件,重在交流嘛。
好的,到这里就picker的第一篇就正式结束了,二三级联动会在之后的篇幅中放出,大家觉得有用的话,请给我star鼓励一下。
有什么问题欢迎大家指出昂,再次感谢大家!