微信小程序自定义日期选择器

日期选择器是我们在写项目的过程中经常遇到的,有需要标题的选择器,也有不需要标题的选择器

今天给大家带来一个自定义的时间选择器,废话不多说,直接上代码

第一步:先创建一个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,
}

完成上述步骤后,一个自定义的日期选择器就完成了

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 微信小程序的日期选择器的实例详解

    微信小程序的日期选择器的实例详解 前言: 关于微信小程序中的日期选择器大家用过都会发现有个很大的问题,就是在2月的时候会有31天,没有进行对闰年的判断等各种情况.看了官方文档提供的源码后进行了一些修改,测试修复了上面所说的bug! 下面源码: <!---js---> const date = new Date();//获取系统日期 const years = [] const months = [] const days = [] const bigMonth = [1,3,5,7,8,10,

  • 微信小程序 选择器(时间,日期,地区)实例详解

    微信小程序 选择器(时间,日期,地区) 微信小程序 开发由于本人最近学习微信小程序的开发,根据自己的实践结果整理了下结果,对日期选择器,时间选择器,地区选择器做的实例,有不对的地方,希望大家指正. 用微信封装好的控件感觉很好,为我们开发人员省去了很多麻烦.弊端就是不能做大量的自定义.今天试用了选择器. 上gif: 上代码: 1.index.js //index.js //获取应用实例 var app = getApp() Page({ data: { date: '2016-11-08', ti

  • 微信小程序如何实现精确的日期时间选择器

    这篇文章主要介绍了微信小程序如何实现精确的日期时间选择器,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 声明 bug:由于此篇博客是在bindcolumnchange事件中做的值的改变处理,因此会出现当你选择时,没有点击确定,直接取消返回后,会发现选择框的值依然改变. 造成原因:这一点就是由于在bindcolumnchange事件做的值改变处理造成. 处理方法:如果需要确定后再改变值,请将bindcolumnchange事件中的处理操作放到bi

  • 微信小程序日期选择器实例代码

    /* JS代码部分 */ 3 const date = new Date() const years = [] const months = [] const days = [] const hours = [] const minutes = [] var thisMon = date.getMonth(); var thisDay = date.getDate(); for (let i = 2017; i <= date.getFullYear() + 1; i++) { years.pu

  • 微信小程序三级联动选择器使用方法

    本文实例为大家分享了微信小程序三级联动选择器的具体代码,供大家参考,具体内容如下 效果图 实现原理 利用微信小程序的picker组件,其中: 1,普通选择器:mode = selector实现一级选择实例: 2,省市区选择器:mode = region实现省市区三级联动: 3, 多列选择器:mode = multiSelector实现二级和三级联动的10以内数字的乘法. WXML <view class="tui-picker-content"> <view clas

  • 微信小程序 滚动选择器(时间日期)详解及实例代码

    微信小程序  滚动选择器(时间日期)详解 微信小程序自己封装了很多控件,用起来确实很方便,如果这是Android里面,还需要自己去定义,不废话,效果图: 一起来看看怎么实现的呢?看完你应该就该说,尼玛,这就行啦-. 这个效果呢,要用到picker组件,动画从底部弹起的滚动选择器,现支持三种选择器,通过mode来区分,分别是普通选择器,时间选择器,日期选择器,默认是普通选择器. 看下相应的属性: 具体的来看看代码,布局: <view class="section" > <

  • 微信小程序之picker日期和时间选择器

    下面来介绍小picker,分三种样式: 默认的自己可以定义数据的 mode="time"是时间选择器 mode="date"是日期选择器 跟其他的一样先来看下picker.wxml <view class="page"> <view class="page__hd"> <text class="page__title">picker</text> <te

  • 微信小程序switch开关选择器使用详解

    本文为大家分享了微信小程序switch开关选择器使用方法,供大家参考,具体内容如下 效果图 WXML <view class="tui-list-box"> <view class="tui-menu-list"> <text>状态:{{isChecked1}}</text> <switch class="tui-fr" checked="{{isChecked1}}" b

  • 微信小程序实现自定义picker选择器弹窗内容

    微信小程序中定义好的几种picker选择器,不管是日期选择器还是地区选择器,或是其他的都有定死的样式和内容. 例如: 但是大多数开发程序的情况下还是需要自己写样式的,或是内容的. 例如: wxml <view class="free-btns" style="margin-top: 10vh;background:none;"> <button class="free-btn" bindtap="toggleDialo

  • 微信小程序日期时间选择器使用方法

    本文实例为大家分享了精确到秒的微信小程序日期时间选择器,供大家参考,具体内容如下 效果图 实现原理 利用微信小程序的picker组件的多列选择器实现! WXML <view class="tui-picker-content"> <view class="tui-picker-name">时间选择器(选择时分)</view> <picker mode="time" value="{{time}}

随机推荐