自从上一篇文章:微信小程序自定义日历组件及flex布局最后一行对齐问题分析 出来以后,有人私聊我说能不能从头分析一下我开源的自定义组件?一直没时间。这不,最近项目中有个需求是 省市区三级联动 ,我就顺便从组件库中的第一个 「扩展日期-时间picker(点此直接至GitHub,欢迎star)」组件开始说一下这两个功能的实现。
简单说一下“自定义日期-时间组件”
它的背景是项目的第一版当时发现微信小程序内置的日期组件:picker只能精确到某一天(年月日),但是我们很多时候需要年月日时分甚至是年月日时分秒(如结束时间/发布时间)。
笔者仔细翻阅了官方文档和许多博主文章发现提出了各种各样的解决方案(但很遗憾没发现有博主详细公开代码),但是对于这样一个其实并不需要“联动”、列数也不固定的功能,用多列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中元素时的第二个索引!
说说省市区三级联动实现
先将城市列表文件发出来:(永久免费下载)
提取码: wc3g
使用时按如下引入即可:(是一个citysearch.js文件)
import placeArrays from 'citysearch文件路径'; const placeArray=placeArrays.placeArray
正式开始
不知大家有没有使用过,或听过小程序的 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中做的唯一一件事就是:遍历固定的某一列(某一个数组)并渲染出来。
然后如
// 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一样,需要多个数组联动来传递数据了!
总结
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。