微信小程序自定义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 相关文章推荐
juqery 学习之五 文档处理 包裹、替换、删除、复制
Feb 11 Javascript
Javascript倒计时页面跳转实例小结
Sep 11 Javascript
JS(JQuery)操作Array的相关方法介绍
Feb 11 Javascript
js 触发select onchange事件代码
Mar 20 Javascript
JavaScript开发Chrome浏览器扩展程序UI的教程
May 16 Javascript
Javascript之Math对象详解
Jun 07 Javascript
JS实现table表格固定表头且表头随横向滚动而滚动
Oct 26 Javascript
js断点调试心得分享(必看篇)
Dec 08 Javascript
封装微信小程序http拦截器过程解析
Aug 13 Javascript
JavaScript进阶(四)原型与原型链用法实例分析
May 09 Javascript
JavaScript中ES6规范中let和const的用法和区别
Aug 06 Javascript
elementUI同一页面展示多个Dialog的实现
Nov 19 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中判断文件存在是用file_exists还是is_file的整理
2012/09/12 PHP
PHP关于htmlspecialchars、strip_tags、addslashes的解释
2014/07/04 PHP
Redis构建分布式锁
2017/03/28 PHP
PHP学习记录之数组函数
2018/06/01 PHP
PHP下载文件函数与用法示例
2019/09/27 PHP
Jquery动态改变图片IMG的src地址示例
2013/06/25 Javascript
js解决select下拉选不中问题
2014/10/14 Javascript
JavaScript之浏览器对象_动力节点Java学院整理
2017/07/03 Javascript
Vue.js中组件中的slot实例详解
2017/07/17 Javascript
AngularJs 终极购物车(实例讲解)
2017/11/08 Javascript
通过vue-router懒加载解决首次加载时资源过多导致的速度缓慢问题
2018/04/08 Javascript
vue组件实现弹出框点击显示隐藏效果
2020/10/26 Javascript
对node.js中render和send的用法详解
2018/05/14 Javascript
微信小程序收货地址API兼容低版本解决方法
2019/05/18 Javascript
javscript 数组扁平化的实现
2020/02/03 Javascript
Vue 实现创建全局组件,并且使用Vue.use() 载入方式
2020/08/11 Javascript
[00:57]辉夜杯战队访谈宣传片—VG
2015/12/25 DOTA
python多进程操作实例
2014/11/21 Python
Python中异常重试的解决方案详解
2017/05/05 Python
Python探索之修改Python搜索路径
2017/10/25 Python
Python判断是否json是否包含一个key的方法
2018/12/31 Python
用OpenCV将视频分解成单帧图片,图片合成视频示例
2019/12/10 Python
windows下的pycharm安装及其设置中文菜单
2020/04/23 Python
python用什么编辑器进行项目开发
2020/06/17 Python
如何利用python正则表达式匹配版本信息
2020/12/09 Python
使用css3匹配手机屏幕横竖状态
2014/01/27 HTML / CSS
CSS3制作圆角图片和椭圆形图片
2016/07/08 HTML / CSS
利用纯CSS3实现动态的自行车特效源码
2017/01/20 HTML / CSS
澳大利亚运动鞋商店:Platypus Shoes
2019/09/27 全球购物
中学生自我评价范文
2014/02/08 职场文书
报关员个人职业生涯规划书
2014/03/12 职场文书
高中生班主任评语
2014/04/25 职场文书
安全责任书怎么写
2014/07/28 职场文书
公务员学习习总书记“三严三实”思想汇报
2014/09/19 职场文书
出纳试用期工作总结2015
2015/05/28 职场文书
新手,如何业余时间安排好写作、提高写作能力?
2019/10/21 职场文书