效果图
需求
由于移动端iOS和安卓原生select样式和效果不同,同一个控件在不同系统上效果不同。
所以决定制作一个跟iOS风格类似的,可以滚动,选择器插件。
之后看到了antd-mobile里面的picker插件符合我们的要求,使用了一段时间感觉其效果不错,隧查看源码,探究其制作过程。
但是antd-mobile是Typescript编写的,跟React类似,但是又不太一样。所以基本是关键问题查看其做参考,剩下的自己实现。
Step1 组件分析
经过查看和分析后 可以得出结论(如下图)
该组件(Picker)大致分成3个部分
children 触发组件弹出的部分,一般为List Item。其实就是该组件的this.props.children。
mask 组件弹出之后的遮罩,点击遮罩组件消失,值不变(相当于是点击取消)。
popup 组件弹出之后的内容,分成上下两个部分,其中下半部分是核心(antd-mobile中将其单独提出来 叫做PickerView)。
第3部分PickerView即为极为复杂,考虑到扩展性:
这里面的列数是可变的(最多不能超过5个);
每一列滚动结束 其后面的列对应的数组和默认值都要发生改变;
每一列都是支持滚动操作的(手势操作)。
组件化之后如图:
分析之后可以看出 第3部分是该组件的核心应该优先制作。
Step 2 使用方法确定
在做之前应该想好输入和输出。
该组件需要哪些参数,参数多少也决定了功能多少。
参照antd-mobile的文档 确定参数如下:
data:组件的数据源 每列应该显示的数据的一个集合 有固定的数据结构
col:组件应该显示的列数
value:默认显示的值 一个数组 每一项对应各个列的值
text:popup组件中间的提示文字
cancelText:取消按钮可自定义的文字 默认为取消
confirmText:确定按钮自定义的文字 默认为确定
cascade:是否级联 就是每一列的值变化 是否会影响其后面的列对应数组和值得变化 是否级联也会影响到数据源数据结果的不同
onChange:点击确定之后 组件值发生变化之后的回调
onPickerChange:每一列的值变化之后的回调
onCancel:取消之后的回调
参数确定之后要确定两个核心参数的数据结构
级联时候data的数据结构
const areaArray = [
{label: '北京市', value: '北京市', children: [
{label: '北京市', value: '北京市', children: [
{label: '朝阳区', value: '朝阳区'}, {label: '海淀区', value: '朝阳区'}, {label: '东城区', value: '朝阳区'}, {label: '西城区', value: '朝阳区'}
]}
]}, {label: '辽宁省', value: '辽宁省', children: [
{label: '沈阳市', value: '沈阳市', children: [
{label: '沈河区', value: '沈河区'}, {label: '浑南区', value: '浑南区'}, {label: '沈北新区', value: '沈北新区'}, ]}, {label: '本溪市', value: '本溪市', children: [
{label: '溪湖区', value: '溪湖区'}, {label: '东明区', value: '东明区'}, {label: '桓仁满族自治县', value: '桓仁满族自治县'}, ]}
]}, {label: '云南省', value: '云南省', children: [
{label: '昆明市', value: '昆明市', children:[
{label: '五华区', value: '五华区'}, {label: '官渡区', value: '官渡区'}, {label: '呈贡区', value: '呈贡区'}, ]}
]},];
对应value的数据结构:['辽宁省', '本溪市', '桓仁满族自治县’]
不级联的时候 data则为
const numberArray = [
[
{label: '一', value: '一'}, {label: '二', value: '二'}, {label: '三', value: '三'}
], [
{label: '1', value: '1'}, {label: '2', value: '2'}, {label: '3', value: '3'}, {label: '4', value: '4'}
], [
{label: '壹', value: '壹'}, {label: '貮', value: '貮'}, {label: '叁', value: '叁'}
]
];
此时value为:['一', '