微信小程序自定義日期選擇器
日期選擇器是我們在寫項目的過程中經常遇到的,有需要標題的選擇器,也有不需要標題的選擇器
今天給大傢帶來一個自定義的時間選擇器,廢話不多說,直接上代碼
第一步:先創建一個picker的文件夾
第二步 :在wxml中寫佈局樣式
<!--picker/picker.wxml--> <view class="full-box {{isOpen?'cur':''}}"> <!--<view class="modal" bindtap="tapModal"></view>--> <view class="picker"> <view class="picker-header"> <view bindtap="cancle" > <text>{{cancelText}}</text> </view> <text style="font-weight: bold;">{{titleText}}</text> <view bindtap="sure"> <text style="color:aqua;">{{sureText}}</text> </view> </view> <picker-view value="{{value}}" class="picker-content" bindpickstart="_bindpickstart" bindchange="_bindChange" bindpickend="_bindpickend" indicator-style="{{indicatorStyle}}" mask-style="{{maskStyle}}" > <picker-view-column wx:for="{{columnsData}}" wx:key="{{index}}"> <view wx:for="{{item}}" wx:for-item="itemIn" class="picker-line" wx:key="{{index}}"> <text class="line1">{{isUseKeywordOfShow?itemIn[keyWordsOfShow]:itemIn}}</text> </view> </picker-view-column> </picker-view> </view> </view>
第三步:wxss中添加樣式
/* picker/picker.wxss */ .full-box{ position: fixed; left: 0; right: 0; bottom: 0; top: 0; z-index: 9999; opacity: 0; background:rgba(0,0,0,.4); transition:all .4s ease-in-out 0; pointer-events:none; } .full-box.cur{ opacity:1; pointer-events:auto } .modal{ position: absolute; width: 100%; height: 50%; bottom:-50%; left: 0; background: transparent; transition:all .4s ease-in-out 0; } .picker{ position: absolute; width: 100%; height: 235px; bottom: -235px; left: 0; background: #fff; display: flex; flex-direction: column; transition:all .4s ease-in-out 0; } .cur .picker{ bottom:0; } .cur .modal{ bottom:50%; } .picker-line{ display: flex; justify-content: center; align-items: center; } .picker-header { height: 20%; box-sizing: border-box; padding: 0 20rpx; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #eeeeee; } .picker-header view { height: 100%; display: flex; justify-content: center; align-items: center; } .picker-header view text{ font-size: 36rpx; } .picker-content { flex-grow: 1; } .line1{ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; lines:1 }
第四步:在js中寫組件的屬性
// picker/picker.js import { isPlainObject } from './tool' Component({ /** * 組件的屬性列表 */ properties: { scrollType: { type: String, value: 'normal'// "link": scroll間聯動 "normal": scroll相互獨立 }, listData: { type: Array, value: [], observer: function(newVal) { if (newVal.length === 0 || this._compareDate()) return this._setTempData() const tempArr = [...new Array(newVal.length).keys()].map(() => 0) this.data.lastValue = this.data.tempValue = tempArr this._setDefault() // let {defaultPickData} = this.properties; // if(newVal.length === 0) return; // // this._setDefault(newVal, defaultPickData) } }, defaultPickData: { type: Array, value: [], observer: function(newVal) { if (newVal.length === 0 || this._compareDate()) return this._setTempData() this._setDefault() } }, keyWordsOfShow: { type: String, value: 'name' }, isShowPicker: { type: Boolean, value: false, observer: function(newVal) { if (newVal) { this._openPicker() } else { this._closePicker() } } }, titleText: {// 標題文案 type: String, value: '請選擇到館日期' }, cancelText: {// 取消按鈕文案 type: String, value: '取消' }, sureText: {// 確定按鈕文案 type: String, value: '確定' }, }, /** * 組件的初始數據 */ data: { columnsData: [], value: [], backData: [], height: 0, isOpen: false, isUseKeywordOfShow: false, scrollEnd: true, // 滾動是否結束 lastValue: [], // 上次各個colum的選擇索引 tempValue: [], isFirstOpen: true, onlyKey: '', defaultPickDataTemp: '', listDataTemp: '' }, /** * 組件的方法列表 */ methods: { tapModal() { this.properties.isShowPicker = false this._closePicker() }, cancle() { this.triggerEvent('cancle') this._closePicker() }, sure() { const { scrollEnd, tempValue } = this.data if (!scrollEnd) return const backData = this._getBackDataFromValue(tempValue) this.setData({ backData }) this.triggerEvent('sure', { choosedData: backData, choosedIndexArr: tempValue }) this._closePicker() }, _bindChange(e) { const { scrollType } = this.properties const { lastValue } = this.data let val = e.detail.value switch (scrollType) { case 'normal': this.data.tempValue = val.concat() this.data.tempValue = val.concat() break case 'link': // let column_02 = this._getColumnData(this.properties.listData[val[0]].children); // let column_03 = this._getColumnData(this.properties.listData[val[0]].children[val[1]].children); var tempArray = [] if (val.length > 1) { val.slice(0, val.length - 1).reduce((t, c, i) => { const v = t[c].children tempArray.push(this._getColumnData(v)) return v }, this.properties.listData) } // let columnsData = [this.data.columnsData[0],column_02,column_03]; var columnsData = [this.data.columnsData[0], ...tempArray] // 設置value關聯 var compareIndex = this._getScrollCompareIndex(lastValue, val) if (compareIndex > -1) { let tempI = 1 while (val[compareIndex + tempI] !== undefined) { val[compareIndex + tempI] = 0 tempI++ } } val = this._validate(val) this.data.lastValue = val.concat() this.data.tempValue = val.concat() this.setData({ columnsData // value: val }) } }, _validate(val) { const { columnsData } = this.data columnsData.forEach((v, i) => { if (columnsData[i].length - 1 < val[i]) { val[i] = columnsData[i].length - 1 } }) this.setData({ value: val }) return val }, _bindpickend() { this.data.scrollEnd = true }, _bindpickstart() { this.data.scrollEnd = false }, _openPicker() { if (!this.data.isFirstOpen) { if (this.properties.listData.length !== 0) { this._setDefault(this._computedBackData(this.data.backData)) } } this.data.isFirstOpen = false this.setData({ isOpen: true }) }, _closePicker() { this.setData({ isOpen: false }) }, _getColumnData(arr) { return arr.map((v) => this._fomateObj(v)) }, _fomateObj(o) { const tempO = {} for (const k in o) { k !== 'children' && (tempO[k] = o[k]) } return tempO }, _getScrollCompareIndex(arr1, arr2) { let tempIndex = -1 for (let i = 0, len = arr1.length; i < len; i++) { if (arr1[i] !== arr2[i]) { tempIndex = i break } } return tempIndex }, // 根據id獲取索引 _getIndexByIdOfObject(listData, idArr, key, arr) { if (!Array.isArray(listData)) return for (let i = 0, len = listData.length; i < len; i++) { if (listData[i][key] === idArr[arr.length][key]) { arr.push(i) return this._getIndexByIdOfObject(listData[i].children, idArr, key, arr) } } }, _setDefault(inBackData) { const { scrollType } = this.properties let { listData, defaultPickData } = this.properties const { lastValue } = this.data if (inBackData) { defaultPickData = inBackData } let backData = [] switch (scrollType) { case 'normal': if (isPlainObject(listData[0][0])) { this.setData({ isUseKeywordOfShow: true }) } if (Array.isArray(defaultPickData) && defaultPickData.length > 0) { backData = listData.map((v, i) => v[defaultPickData[i]]) this.data.tempValue = defaultPickData this.data.lastValue = defaultPickData } else { backData = listData.map((v) => v[0]) } this.setData({ columnsData: listData, backData: backData, value: defaultPickData }) break case 'link': // let column_01 = this._getColumnData(newVal); // let column_02 = this._getColumnData(newVal[0].children); // let column_03 = this._getColumnData(newVal[0].children[0].children); // let columnsData = [column_01,column_02,column_03]; var columnsData = [] // 如果默認值 if (Array.isArray(defaultPickData) && defaultPickData.length > 0 && defaultPickData.every((v, i) => isPlainObject(v))) { const key = this.data.onlyKey = Object.keys(defaultPickData[0])[0] const arr = [] this._getIndexByIdOfObject(listData, defaultPickData, key, arr) defaultPickData = arr let tempI = 0 do { lastValue.push(defaultPickData[tempI]) columnsData.push(this._getColumnData(listData)) listData = listData[defaultPickData[tempI]].children tempI++ } while (listData) backData = columnsData.map((v, i) => v[defaultPickData[i]]) // 如果沒有默認值 } else { this.data.onlyKey = this.properties.keyWordsOfShow || 'name' do { lastValue.push(0) columnsData.push(this._getColumnData(listData)) listData = listData[0].children } while (listData) backData = columnsData.map((v) => v[0]) } this.data.tempValue = defaultPickData this.data.lastValue = defaultPickData this.setData({ isUseKeywordOfShow: true, columnsData, backData }) setTimeout(() => { this.setData({ value: defaultPickData }) }, 0) break } }, _computedBackData(backData) { const { scrollType, listData } = this.properties const { onlyKey } = this.data if (scrollType === 'normal') { return backData.map((v, i) => listData[i].findIndex((vv, ii) => this._compareObj(v, vv))) } else { const t = backData.map((v, i) => { const o = {} o[onlyKey] = v[onlyKey] return o }) return t } }, _compareObj(o1, o2) { const { keyWordsOfShow } = this.properties if (typeof o1 !== 'object') { return o1 === o2 } else { return o1[keyWordsOfShow] === o2[keyWordsOfShow] } }, _getBackDataFromValue(val) { let tempArr = [] if (val.length > 0) { tempArr = this.data.columnsData.reduce((t, v, i) => { return t.concat(v[val[i]]) }, []) } else { tempArr = this.data.columnsData.map((v, i) => v[0]) } return tempArr }, _compareDate() { // 完全相等返回true const { defaultPickDataTemp, listDataTemp } = this.data const { defaultPickData, listData } = this.properties return defaultPickDataTemp === defaultPickData && listDataTemp === listData }, _setTempData() { const { defaultPickData, listData } = this.properties this.data.defaultPickDataTemp = defaultPickData this.data.listDataTemp = listData } } })
第五步:創建一個tool.js文件
function _typeof(obj) { return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase(); } function isString(obj) { //是否字符串 return _typeof(obj) === 'string' } function isPlainObject(obj) { return _typeof(obj) === 'object'; } module.exports = { isString, isPlainObject }
第六步:在所需的頁面的json中進行引用
{ "usingComponents": { "picker": "../../picker/picker" } }
第七步:在所需的頁面的wxml中寫入佈局
<button bindtap="showPicker_11">時間的五列聯動picker</button> <view>選擇數據:{{picker_11_data}}</view> <view>選擇索引:{{picker_11_index}}</view> <picker isShowPicker="{{isShow_11}}" keyWordsOfShow="name" bindsure="sureCallBack_11" bindcancle="cancleCallBack_11" scrollType="link" listData="{{listData_11}}"></picker>
第八步:在所需的頁面的js中調用我們的自定義選擇器
// pages/index/index.js import { times } from './time.js'; Page({ /** * 頁面的初始數據 */ data: { isShow_11: false, listData_11:times, picker_11_data:[], }, onLoad () { setTimeout(() => { this.setData({ defaultPickData_08:[ {code:'110000'},{code:'110100'},{code:'110101'} ] }) },3000) }, showPicker_11: function () { this.setData({ isShow_11: true, }) }, sureCallBack_11 (e) { let data = e.detail console.log("data",data); this.setData({ isShow_11: false, picker_11_data: JSON.stringify(e.detail.choosedData), picker_11_index:JSON.stringify(e.detail.choosedIndexArr) }) }, cancleCallBack_11 () { this.setData({ isShow_11: false }) }, })
第九步:創建一個time.js的文件
const times =[ { name:'2021年', id:1, children:[ { name:'1月', id:11, children:[ { name:'1日', id:111, children:[ { name:'1時', id:1111, children:[ { name:'1分', id:11111, }, { name:'2分', id:11112, }, ] }, ] }, { name:'2日', id:112, children:[ { name:'1時', id:1121, children:[ { name:'1分', id:11111, }, { name:'2分', id:11112, }, ] }, { name:'2時', id:1121, }, ] }, { name:'3日', id:113, children:[ { name:'小', id:1131, }, { name:'大', id:1132 }, ] } ] }, { name:'2月', id:12, children:[ { name:'1日', id:121, children:[ { name:'1時', id:1121, children:[ { name:'1分', id:11111, }, { name:'2分', id:11112, }, ] }, { name:'2時', id:1121, }, ] }, { name:'2日', id:122, children:[ { name:'1時', id:1121, children:[ { name:'1分', id:11111, }, { name:'2分', id:11112, }, ] }, { name:'2時', id:1121, }, ] }, { name:'3日', id:123, children:[ { name:'1時', id:1121, children:[ { name:'1分', id:11111, }, { name:'2分', id:11112, }, ] }, { name:'2時', id:1121, }, ] } ] } ] }, { name:'2022年', id:1, children:[ { name:'1月', id:11, children:[ { name:'1日', id:111, children:[ { name:'1時', id:1111, children:[ { name:'1分', id:11111, }, { name:'2分', id:11112, }, ] }, ] }, { name:'2日', id:112, children:[ { name:'1時', id:1121, children:[ { name:'1分', id:11111, }, { name:'2分', id:11112, }, ] }, { name:'2時', id:1121, }, ] }, { name:'3日', id:113, children:[ { name:'小', id:1131, }, { name:'大', id:1132 }, ] } ] }, { name:'2月', id:12, children:[ { name:'1日', id:121, children:[ { name:'1時', id:1121, children:[ { name:'1分', id:11111, }, { name:'2分', id:11112, }, ] }, { name:'2時', id:1121, }, ] }, { name:'2日', id:122, children:[ { name:'1時', id:1121, children:[ { name:'1分', id:11111, }, { name:'2分', id:11112, }, ] }, { name:'2時', id:1121, }, ] }, { name:'3日', id:123, children:[ { name:'1時', id:1121, children:[ { name:'1分', id:11111, }, { name:'2分', id:11112, }, ] }, { name:'2時', id:1121, }, ] } ] } ] },] module.exports = { times, }
完成上述步驟後,一個自定義的日期選擇器就完成瞭
以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 微信小程序頁面返回傳值的4種解決方案匯總
- 微信小程序picker多列選擇器(mode = multiSelector)
- 微信小程序自定義地址組件
- 微信小程序自定義滾動選擇器
- 微信小程序實現日期范圍選擇