省市区联动组件开发攻略
2023-09-03 17:52:20
如何编写省市区联动组件
省市区联动这种插件应该很多人用过,在我第一次写这种功能的时候,第一时间就是找插件,尤其是移动端,对当时的我来说从来没有想过自己写。
最近看了同事写的省市区的组件,发现几乎所有的picker组件都是根据手指移动距离来滑动,但是有个问题,就是我快速的滑动一下,组件是没办法像原生scroll那样回弹的,但是会重新定位到距离最近的某一项,如果此时有3列,那点击列表的时候肯定会很不舒服。
接下来讲讲我们是怎么做的,包括滚动组件的原理,省市区数据的组织方式。
滚动组件的原理
用react写滚动组件,大家想到的一般是onTouchStart onTouchMove onTouchEnd这样的原生事件,但是react封装的TouchEvent API有点奇怪,触摸事件回调的参数是一个对象,里边就有很多常见的方法和属性,比如clientX,clientY。
刚开始我天真的以为官方已经把这些事件想好了,所以一开始就用了官方的API,然后问题就出现了。
onTouchStart和onTouchMove事件是源源不断触发的,如果是快速的滑动的话,可能会在很短的时间内触发非常多的onTouchMove事件,这样我们拿到这些事件后,一个个处理的话,必然会造成性能问题,事实上也确实是如此。
后来同事发现了这个问题,经过一番思考后决定用requestAnimationFrame来控制onTouchMove事件的触发次数,并且在其中做了一些复杂的运算,实现了回弹效果,同时解决了性能问题,这种思路还是比较常见的,大家也可以借鉴下。
省市区数据的组织方式
前端获取省市区的数据来源很多,比如:
- 接口
- json文件
- 本地存储
为了省事,我一开始是用了后两个方案。
用json文件的话可以直接将json文件拖进编辑器,用本地存储的话就 需要先把一个json文件上传到服务器上,然后通过接口请求的方式拿到数据,前端获取省市区数据的方式可能还有很多,这里就不细说了。
无论如何,拿到的数据都是一个json文件,格式一般是:
{
"省份": [{
"省份名称": "",
"城市": [{
"城市名称": "",
"区县": [{
"区县名称": ""
}]
}]
}]
}
一开始我看这数据的格式感觉非常坑,因为在获取一个省份的子项的时候需要遍历很多层,所以我一开始自己写了一个比较扁平的json格式,大概是这样:
[
{
"value": 1,
"label": "北京",
"children": [
{
"value": 11,
"label": "北京市",
"children": [
{
"value": 1101,
"label": "东城区"
},
{
"value": 1102,
"label": "西城区"
}
]
}
]
}
]
这样虽然数据结构看起来很直观,但是由于省市区的子项过多,导致整个数组非常大,还很容易造成数据冗余。
后面又查了官方文档,发现他们使用的是一个叫做flat-map的方法,这个方法可以把多维数组“拉平”成一维数组,还能自动给子项加上一个父节点的标识,而这就是我们想要的:
[
{
"value": 1,
"label": "北京",
"parent": null
},
{
"value": 11,
"label": "北京市",
"parent": 1
},
{
"value": 1101,
"label": "东城区",
"parent": 11
},
{
"value": 1102,
"label": "西城区",
"parent": 11
}
]
省事的人可以直接用flat-map这个方法,但是要手写的话,也可以写个递归函数,不过手写的话就需要注意一下递归的出口,否则会出问题的。