微信小程序-自定义日期组件实现
今日份跟大佬聊到说前端基础架构平台的东西、涉及到基础组件库、公共工具类等内容, 然后期望能自我驱动带头去做, 陷入深深滴沉思, 该考虑如何做?
思绪一片混乱, 那就写篇文章冷静冷静,故有了此篇, 仅供参考。
微信小程序原生有提供一套日期组件, 大概如下:
跟UI预期不一致的点有如下几个:
A. 期望弹窗居中显示、而不是从底部弹出;
B. 期望小于10的展示为1月,1日这种, 而不是01月, 01日;
C. UI样式跟微信原生差别有点大;
D. 不需要头部的取消&确定按钮、预期底部整个确定按钮即可;
想着让产品接受原生日期组件的, But拗不过产品的思维, 只能开干、自己撸一个自定义日期组件, 造轮子=.=
A. 期望弹窗居中显示、而不是从底部弹出;
B. 期望小于10的展示为1月,1日这种, 而不是01月, 01日;
C. UI样式跟微信原生差别有点大;
D. 不需要头部的取消&确定按钮、预期底部整个确定按钮即可;
想着让产品接受原生日期组件的, But拗不过产品的思维, 只能开干、自己撸一个自定义日期组件, 造轮子=.=
既然原生的不能用, 那么我们看看小程序是否有提供这种类似的滚动器, 查看官方文档发现:
那就开干, 为尽可能保持代码的最小颗粒度(这里不考虑弹窗外壳的封装、纯日期组件).
话不多说、这里直接贴上代码、预留的坑位都会在代码内有备注, 请参考:
// 组件wxml
<!-- 预留坑位: 按道理该日期组件应该是做在弹窗上的、这里为了简化代码故直接写在了页面上;
后期使用者烦请自己做个弹窗套上、用showModal属性控制其显示隐藏-->
<view class="picker" wx:if="{{showModal}}">
<picker-view indicator-class="picker-indicator" value="{{pickerIndexList}}" bindchange="bindChangeDate">
<picker-view-column>
<view wx:for="{{yearList}}" wx:key="index" class="{{pickerIndexList[0]==index?'txt-active':''}}">{{item}}年</view>
</picker-view-column>
<picker-view-column>
<view wx:for="{{monthList}}" wx:key="index" class="{{pickerIndexList[1]==index?'txt-active':''}}">{{item}}月</view>
</picker-view-column>
<picker-view-column>
<view wx:for="{{dayList}}" wx:key="index" class="{{pickerIndexList[2]==index?'txt-active':''}}">{{item}}日</view>
</picker-view-column>
</picker-view>
<!-- 预留坑位: 日期组件可能仅允许数据回选、不允许修改。
思路: 通过自定义蒙层盖在日期控件上从而达到禁止控件滚动的效果.
-->
<view wx:if="{{!canEdit}}" class="disabled-picker"></view>
</view>
// 组件wxss
.picker{
position: relative;
height: 300rpx;
width: 600rpx;
margin: 0 auto;
border: 1rpx solid red;
}
.picker picker-view {
width: 100%;
height: 100%;
}
.picker-indicator {
height: 60rpx;
line-height: 60rpx;
}
.picker picker-view-column view {
font-size: 40rpx;
line-height: 60rpx;
text-align: center;
}
.txt-active {
color: #2c2c2c;
}
/* 预留坑位: 为便于区分真的有遮罩层盖住、特意加了个背景色、实际使用过程可改成透明色 */
.disabled-picker{
width: 600rpx;
position: absolute;
top: 0;
left: 0;
height: 300rpx;
z-index: 999;
background: rgb(255,222,173,0.7);
}
// 组件js
Component({
properties: {},
data: {
yearList: [],
monthList: [],
dayList: [],
pickerIndexList: [0, 0, 0]
},
methods: {
// dateString格式: 'YYYY-MM-DD'
initPicker (dateString) {
let nowDate = new Date()
// 预留个坑位: 若需要指定某一日期则从外面传入、否则默认当天
if(dateString){
// 预留个坑位: 判定传入的数据类型是否符合要求、若不符合该报错的报错
nowDate = new Date(dateString)
}
// 预留个坑位: 因为下面的日期指定在1900.01.01-2100.12.31、故这里最好校验下传入日期是否在区间内.
let nowYear = nowDate.getFullYear()
let nowMonth = nowDate.getMonth() + 1
let yearList = this.getYearList(nowYear)
let monthList = this.getMonthList()
let dayList = this.getDayList(nowYear, nowMonth)
// 获取多列选择器的选中值下标
let pickerIndexList = []
pickerIndexList[0] = yearList.findIndex(o => o === nowDate.getFullYear())
pickerIndexList[1] = monthList.findIndex(o => o === nowDate.getMonth()+1)
pickerIndexList[2] = dayList.findIndex(o => o === nowDate.getDate())
this.setData({
yearList,
monthList,
dayList,
pickerIndexList,
showModal: true
})
},
// 获取年份
getYearList (nowYear) {
let yearList = []
if(nowYear < 1900 || nowYear > 2100){
return false
}
for (let i = 1900; i <= 2100; i++) {
yearList.push(i)
}
return yearList
},
// 获取月份
getMonthList () {
let monthList = []
for (let i = 1; i <= 12; i++) {
monthList.push(i)
}
return monthList
},
// 获取日期 -> 根据年份&月份
getDayList (year, month) {
let dayList = []
month = parseInt(month, 10)
// 特别注意: 这里要根据年份&&月份去计算当月有多少天[切记切记]
let temp = new Date(year, month, 0)
let days = temp.getDate()
for (let i = 1; i <= days; i++) {
dayList.push(i)
}
return dayList
},
// 日期选择改变事件
bindChangeDate (e) {
let pickerColumnList = e.detail.value
const { yearList=[], monthList=[] } = this.data
const nowYear = yearList[pickerColumnList[0]]
const nowMonth = monthList[pickerColumnList[1]]
this.setData({
dayList: this.getDayList(nowYear, nowMonth),
pickerIndexList: pickerColumnList
})
},
show (birthday) {
// 预留坑位: 这里也许会有一定的逻辑判定是否允许编辑日期控件, 故预留canEdit属性去控制
this.setData({
canEdit: true
})
this.initPicker(birthday)
},
// 预留坑位、点击确定按钮获取到选中的日期
surePicker () {
const { pickerIndexList, yearList, monthList, dayList } = this.data
// 预留坑位: 月份&日期补0
let txtDate = `${yearList[pickerIndexList[0]]}-${monthList[pickerIndexList[1]]}-${dayList[pickerIndexList[2]]}`
console.log(txtDate)
},
}
})
接下来我们看看使用方是怎么使用的?
// 页面wxml
<!-- 预留坑位: 这里仅展示触发事件、开发者替换成实际业务即可-->
<view bind:tap="openPicker" style="margin:20rpx; text-align:center;">打开日期控件</view>
// 页面json: 记得在使用页面的json处引入该组件、配置组件路径
// 页面js
methods: {
openPicker (){
// 获取组件实例、这里可选择是否传入日期
this.date_picker = this.selectComponent && this.selectComponent('#date_picker')
this.date_picker && this.date_picker.show()
},
}
一切准备就绪、我们看看效果图!
这是日期可编辑时、你是可滚动选择器的:
我们看看日期不可编辑时、仅可查看的效果图:
样式是稍微有点丑、到时开发者按照实际UI去做微调即可、这不难的=.=.
这里预留了几个扩展点:
1.支持外部传入日期、默认选中预设值;
2.支持在弹窗内显示日期控件、需要使用者自行开发弹窗;
3.支持日期控件仅可查看、不可编辑;
4.支持日期控件的关闭、一般是弹窗上有个关闭按钮或者是点击弹窗的蒙层可关闭、使用者自行开发;
Tips: 具体的代码改动点都有在上面的code中有备注、欢迎对号改代码, 若有任何不懂的欢迎留言或者私信、很愿意帮您解答。
这里预留了几个扩展点:
1.支持外部传入日期、默认选中预设值;
2.支持在弹窗内显示日期控件、需要使用者自行开发弹窗;
3.支持日期控件仅可查看、不可编辑;
4.支持日期控件的关闭、一般是弹窗上有个关闭按钮或者是点击弹窗的蒙层可关闭、使用者自行开发;
Tips: 具体的代码改动点都有在上面的code中有备注、欢迎对号改代码, 若有任何不懂的欢迎留言或者私信、很愿意帮您解答。
链接:https://juejin.cn/post/6967201721265160199