微信小程序自定义yPicker组件实现省市区三级联动功能


Posted in Javascript onOctober 29, 2020

自从上一篇文章:微信小程序自定义日历组件及flex布局最后一行对齐问题分析 出来以后,有人私聊我说能不能从头分析一下我开源的自定义组件?一直没时间。这不,最近项目中有个需求是 省市区三级联动 ,我就顺便从组件库中的第一个 「扩展日期-时间picker(点此直接至GitHub,欢迎star)」组件开始说一下这两个功能的实现。


简单说一下“自定义日期-时间组件”

它的背景是项目的第一版当时发现微信小程序内置的日期组件:picker只能精确到某一天(年月日),但是我们很多时候需要年月日时分甚至是年月日时分秒(如结束时间/发布时间)。

微信小程序自定义yPicker组件实现省市区三级联动功能

笔者仔细翻阅了官方文档和许多博主文章发现提出了各种各样的解决方案(但很遗憾没发现有博主详细公开代码),但是对于这样一个其实并不需要“联动”、列数也不固定的功能,用多列picker模拟多列选择器 即可。

<picker mode="multiSelector" bindchange="bindMultiPickerChange" bindcolumnchange="bindMultiPickerColumnChange" value="{{multiIndex}}" range="{{multiArray}}">
	<input value='{{time}}' readonly="" disabled="true" placeholder='{{defaulttext}}' />
</picker>

其中 readonly="" disabled="true" 的作用是使“input聚焦时软键盘不弹出”(两个属性作用一样,都写是因为Android和iOS的兼容性问题)。

用input代替view是因为input的placeholder方便实现“无选中时默认提示”的效果。

主要实现策略

如上所示,监听了两个事件,分别是:日期选择窗口弹出时以及点击“确定”按钮时触发函数change、多列选择器中每一列滑动时触发事件columnchange。

  • change中很简单:只需要把选中的数据暴露给页面中(或者通过 triggerEvent 返回给调用页面)即可;
  • columnchange中要做的就是当前选中的每一列的值填充到data中对应数组的某一项。比如:e.detail.column==1 时表示当前滑动的是第二列(月份),此时需要判断的是每一月有几天:
if (e.detail.column == 1) {
 let num = parseInt(this.data.multiArray[e.detail.column][e.detail.value]);
 let temp = [];
 if (num == 1 || num == 3 || num == 5 || num == 7 || num == 8 || num == 10 || num == 12) { //判断31天的月份
 for (let i = 1; i <= 31; i++) {
  if (i < 10) {
  i = "0" + i;
  }
  temp.push("" + i);
 }
 this.setData({
  ['multiArray[2]']: temp //第三列天数更新(根据月份)
 });
 }
}

注意: 多列picker组件监听两个参数:multiArray和multiIndex,他们都是数组!
multiArray主要用来表示监听几列,其元素都是一个个数组,如:[years, months, days, hours, minutes]
multiIndex是当前每一列(点开时的)初始值!如:[10, meng_date.getMonth(), meng_date.getDate()-1, meng_date.getHours(), meng_date.getMinutes()]
一般来说,multiIndex中的值也被用来当做取multiArray中元素时的第二个索引!


说说省市区三级联动实现

先将城市列表文件发出来:(永久免费下载)

链接: https://pan.baidu.com/s/1tPabuqSY6SfBNfOEMkjPVA

提取码: wc3g

使用时按如下引入即可:(是一个citysearch.js文件)

import placeArrays from 'citysearch文件路径';
const placeArray=placeArrays.placeArray

微信小程序自定义yPicker组件实现省市区三级联动功能

正式开始

不知大家有没有使用过,或听过小程序的 picker-view 组件,其定位就是:嵌入页面的滚动选择器
它有三个参数:

参数 类型 说明
value Number Array 数组中的数字依次表示 picker-view 内的 picker-view-colume 选择的第几项(下标从 0 开始),数字大于 picker-view-column 可选项长度时,选择最后一项。
indicator-style String 设置选择器中间选中框的样式
bindchange EventHandle 当滚动选择,value 改变时触发 change 事件,event.detail = {value: value} value为数组,表示 picker-view 内的 picker-view-column 当前选择的是第几项(下标从 0 开始)

需要注意的是:其中只可放置<picker-view-column/>组件,其他节点不会显示,其孩子节点的高度会自动设置成与picker-view的选中框的高度一致。

有了这个组件,我们是不是能想到:在一个弹出view中设置三个picker-view组件,每个组件中放一个picker-view-column组件用于展示当前列?

value中也可以只放一个number(通常可以放数组元素下标),picker-view会自动将其转为 [下标值]

就像这样:

<view style="width:100%;position:fixed;bottom:0;left:0;z-index:10000;height:500rpx;background-color:white">
 <!-- 仿原生picker的“确定”和“取消”按钮 -->
 <view style="display:flex;width:100%;height:100%">
 <view
 style="position: absolute;top:0;width:100%;height:100rpx;z-index:1000000;display:flex;justify-content:space-between;align-items:center;">
 <view style="width:calc(100% / 3);text-align:center;color:rgba(0,0,0,.6);font-size:39rpx" bindtap="displayer">取消
 </view>
 <view style="width:calc(100% / 3);text-align:center;color:rgb(63,142,255);font-size:39rpx" bindtap="confirm">确定
 </view>
 </view>
 
 <picker-view indicator-style="height: 200rpx;"
 style="width: 100%;height: 300rpx;text-align: center;margin-top:150rpx" value="{{pIndex}}"
 bindchange="changeProvince">
 <picker-view-column>
 <view wx:for="{{placeArray}}" wx:key="name" style="line-height: 77rpx">{{item.name}}</view>
 </picker-view-column>
 </picker-view>
 <picker-view indicator-style="height: 200rpx;"
 style="width: 100%;height: 300rpx;text-align: center;margin-top:150rpx" value="{{cIndex}}"
 bindchange="changeCity">
 <picker-view-column>
 <view wx:for="{{placeArray[pIndex].city}}" wx:key="name" style="line-height: 77rpx">{{item.name}}</view>
 </picker-view-column>
 </picker-view>
 <picker-view indicator-style="height: 200rpx;"
 style="width: 100%;height: 300rpx;text-align: center;margin-top:150rpx" value="{{aIndex}}"
 bindchange="changeArea">
 <picker-view-column>
 <view wx:for="{{placeArray[pIndex].city[cIndex].area}}" wx:key="*this" style="line-height: 77rpx">{{item}}
 </view>
 </picker-view-column>
 </picker-view>
 
 </view>
</view>

可以看到,每一个picker-view-column中做的唯一一件事就是:遍历固定的某一列(某一个数组)并渲染出来。

微信小程序自定义yPicker组件实现省市区三级联动功能

然后如

// js-data
data:{
	placeArray: placeArray,
 province: "",//placeArray[0].name - 省
 pIndex: 0,
 city: "",//placeArray[0].city[0].name - 市
 cIndex: 0,
 area: "",//placeArray[0].city[0].area[0] - 区
 aIndex: 0,
}

上wxml中为每一列(picker-view)都绑定了一个change函数——滑动时触发:

changeProvince: function(e){
 const val = e.detail.value
 this.setData({
 pIndex: val,
 cIndex: 0,
 aIndex: 0,
 province: placeArray[val].name,
 city: placeArray[val].city[0].name,
 area: placeArray[val].city[0].area[0]
 })
},
changeCity: function(e){
 const val = e.detail.value
 this.setData({
 cIndex: val,
 aIndex: 0,
 city: placeArray[this.data.pIndex].city[val].name,
 area: placeArray[this.data.pIndex].city[val].area[0]
 })
},
changeArea: function(e){
 const val = e.detail.value
 this.setData({
 aIndex: val,
 area: placeArray[this.data.pIndex].city[this.data.cIndex].area[val]
 })
},

他们的作用就是把当前选择列的选中元素(出现在indicator-style视野中的元素)暴露到页面上,并将下标定位到这里 —— 以便在页面无刷新下的下一次点开时从这里开始找!
然后最重要的一点就是:在滑动停止时,将另外两列的数据重新定位到第一个!
——当然,你也可以选择在一个picker-view中放置多个picker-view-column组件,这样的话就和上面多列picker一样,需要多个数组联动来传递数据了!

总结

到此这篇关于微信小程序自定义yPicker组件实现省市区三级联动功能的文章就介绍到这了,更多相关微信小程序自定义yPicker组件内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
Mootools 1.2教程 滑动效果(Slide)
Sep 15 Javascript
functional继承模式 摘自javascript:the good parts
Jun 20 Javascript
jquery $.fn $.fx是什么意思有什么用
Nov 04 Javascript
jquery限定文本框只能输入数字即整数和小数
Nov 29 Javascript
jQuery向上遍历DOM树之parents(),parent(),closest()之间的区别
Dec 02 Javascript
jquery制作漂亮的弹出层提示消息特效
Dec 23 Javascript
jQuery中replaceWith()方法用法实例
Dec 25 Javascript
JavaScript每天定时更换皮肤样式的方法
Jul 01 Javascript
tuzhu_req.js 实现仿百度图片首页效果
Aug 11 Javascript
基于bootstrap页面渲染的问题解决方法
Aug 09 Javascript
Vue记住滚动条和实现下拉加载的完美方法
Jul 31 Javascript
javaScript Array api梳理
Mar 31 Javascript
解决ant Design Search无法输入内容的问题
Oct 29 #Javascript
js实现随机圆与矩形功能
Oct 29 #Javascript
在vue中使用jsonp进行跨域请求接口操作
Oct 29 #Javascript
基于react项目打包css引用路径错误解决方案
Oct 28 #Javascript
design vue 表格开启列排序的操作
Oct 28 #Javascript
ant design vue导航菜单与路由配置操作
Oct 28 #Javascript
JS实现多功能计算器
Oct 28 #Javascript
You might like
写php分页时出现的Fatal error的解决方法
2011/04/18 PHP
PHP中函数rand和mt_rand的区别比较
2012/12/26 PHP
PHP上传图片进行等比缩放可增加水印功能
2014/01/13 PHP
SESSION存放在数据库用法实例
2015/08/08 PHP
ThinkPHP6.0如何利用自定义验证规则规范的实现登陆
2020/12/16 PHP
网页中CDATA标记的说明
2010/09/12 Javascript
jquery cookie的用法总结
2013/11/18 Javascript
2014年50个程序员最适用的免费JQuery插件
2014/12/15 Javascript
JavaScript使用Math.Min返回两个数中较小数的方法
2015/04/06 Javascript
jQuery解析XML文件同时动态增加js文件的方法
2015/06/01 Javascript
理解javascript中Map代替循环
2016/02/26 Javascript
初步使用Node连接Mysql数据库
2016/03/03 Javascript
NodeJs之word文件生成与解析的实现代码
2019/04/01 NodeJs
Vue-Cli 3.0 中配置高德地图的两种方式
2019/06/19 Javascript
使用Node.js在深度学习中做图片预处理的方法
2019/09/18 Javascript
详解vue页面首次加载缓慢原因及解决方案
2019/11/06 Javascript
js实现网页随机验证码
2020/10/19 Javascript
vue+swiper实现左右滑动的测试题功能
2020/10/30 Javascript
vue-video-player 断点续播的实现
2021/02/01 Vue.js
[02:41]《西雅图我们来了》2015国际邀请赛出征全记录
2015/07/23 DOTA
[01:01:31]2018DOTA2亚洲邀请赛3月29日小组赛B组 Mineski VS paiN
2018/03/30 DOTA
[50:22]完美盛典-2018年度红毯走秀
2018/12/16 DOTA
[32:30]夜魇凡尔赛茶话会 第一期01:谁是卧底
2021/03/11 DOTA
python调用fortran模块
2016/04/08 Python
Windows系统下多版本pip的共存问题详解
2017/10/10 Python
详解python3中用HTMLTestRunner.py报ImportError: No module named 'StringIO'如何解决
2019/08/27 Python
详解用Python进行时间序列预测的7种方法
2020/03/13 Python
python批量生成条形码的示例
2020/10/10 Python
python 实现超级玛丽游戏
2020/11/25 Python
HTML5 对各个标签的定义与规定:body的介绍
2012/06/21 HTML / CSS
深入理解HTML的FormData对象
2016/05/17 HTML / CSS
HTML5中的Web Notification桌面通知功能的实现方法
2019/07/29 HTML / CSS
初中同学聚会感言
2014/02/11 职场文书
大学团日活动总结书
2015/05/11 职场文书
2016年小学圣诞节活动总结
2016/03/31 职场文书
python DataFrame中stack()方法、unstack()方法和pivot()方法浅析
2022/04/06 Python