微信小程序自定义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 相关文章推荐
DWR Ext 加载数据
Mar 22 Javascript
基于jQuery的仿flash的广告轮播代码
Nov 04 Javascript
JS记录用户登录次数实现代码
Jan 15 Javascript
原生javascript实现DIV拖拽并计算重复面积
Jan 02 Javascript
网页收藏夹显示ICO图标(代码少)
Aug 04 Javascript
JavaScript实现跑马灯抽奖活动实例代码解析与优化(二)
Feb 16 Javascript
AngularJS 自定义指令详解及示例代码
Aug 17 Javascript
AngularJS模态框模板ngDialog的使用详解
May 11 Javascript
Vue配合iView实现省市二级联动的示例代码
Jul 27 Javascript
react写一个select组件的实现代码
Apr 03 Javascript
js实现ajax的用户简单登入功能
Jun 18 Javascript
浅谈react路由传参的几种方式
Mar 23 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计划任务之关闭浏览器后仍然继续执行的函数
2010/07/22 PHP
PHP使用Mysql事务实例解析
2014/09/08 PHP
php查看当前Session的ID实例
2015/03/16 PHP
PHP使用gmdate实现将一个UNIX 时间格式化成GMT文本的方法
2015/03/19 PHP
php搜索文件程序分享
2015/10/30 PHP
php反射类ReflectionClass用法分析
2016/05/12 PHP
PHP培训要多少钱
2017/06/06 PHP
Yii2.0建立公共方法简单示例
2019/01/29 PHP
Laravel 自定命令以及生成文件的例子
2019/10/23 PHP
tagName的使用,留一笔
2006/06/26 Javascript
从父页面读取和操作iframe中内容方法
2009/07/25 Javascript
EXT中xtype的含义分析
2010/01/07 Javascript
基于PHP+Jquery制作的可编辑的表格的代码
2011/04/10 Javascript
JS图片预加载 JS实现图片预加载应用
2012/12/03 Javascript
JavaScript动态加载样式表的方法
2015/03/21 Javascript
基于JavaScript实现仿京东图片轮播效果
2015/11/06 Javascript
js省市联动效果完整实例代码
2015/12/09 Javascript
jquery+json实现动态商品内容展示的方法
2016/01/14 Javascript
AngularJS入门教程之ng-class 指令用法
2016/08/01 Javascript
js倒计时简单实现代码
2016/08/11 Javascript
实现easyui的datagrid导出为excel的示例代码
2016/11/10 Javascript
原生js实现图片放大缩小计时器效果
2017/01/20 Javascript
Vue实战教程之仿肯德基宅急送App
2019/07/19 Javascript
使用Vant完成DatetimePicker 日期的选择器操作
2020/11/12 Javascript
在python的类中动态添加属性与生成对象
2016/09/17 Python
python实现爬山算法的思路详解
2019/04/09 Python
Python 面向对象之类class和对象基本用法示例
2020/02/02 Python
Python-jenkins模块之folder相关操作介绍
2020/05/12 Python
台湾最大网路书店:博客来
2018/03/18 全球购物
C#笔试题集合
2013/06/21 面试题
个人找工作自荐信格式
2013/09/21 职场文书
毕业生的自我评价分享
2013/12/18 职场文书
个人廉洁自律总结
2015/03/06 职场文书
2015年机械设备管理工作总结
2015/05/04 职场文书
2015年中学团委工作总结
2015/07/22 职场文书
Python读写yaml文件
2022/03/20 Python