微信小程序自定义picker
前言实现蒙层底部内容内容顶部picker布局实现js实现样式使用姿势代码获取尾巴前言
之前UI丢了一张类似这样的效果图(当然这个是本文的效果图,不是原图,不过差不多)给我:
当时看到图就想这个还不简单,直接使用picker就行了。然后就是一顿操作,选择mode为date,最终出现了效果图:
正当我沉浸在完成功能的喜悦中的时候,心里有个声音一直在提醒我:你没有达到UI需求效果,你没有达到UI需求效果,你没有达到UI需求效果…
定睛一看果然和UI效果图有些许区别,UI左上角显示的是【全部】,而我们现在是【取消】,顶部是圆角,而我们现在是直角。第二个问题影响显然比第一个问题影响小,我们直接通过微信提供的picker相关API把左上角的字修改成【全部】勉强也能用,那我们就去查看下相关API。
查遍picker这货的所有API,竟然不支持修改左上角的文字。然后我们会妥协,让UI把这个全部功能去掉或者移动到其他地方么?不,这辈子都不可能妥协,程序猿永不为奴!!!既然这样,那我们就自己来实现个picker把,开干~~
实现
通过分析UI图可以发现,整个是由四部分组成:
蒙层底部内容内容顶部按钮picker滚动区域
蒙层
.mask {position: fixed;width: 100%;height: 100%;left: 0;right: 0;top: 0;bottom: 0;display: flex;background-color: rgba(0,0,0,0.7);z-index: 9999;flex-direction: column;justify-content: flex-end;}
z-index是设置显示层级,为了让内容显示在底部,使用column布局方式,并且justify-content为flex-end。这些知识在我之前系列的文章微信小程序布局技巧里面有提到,不太清楚的可以看之前的文章。
底部内容
.content {display: flex;flex-direction: column;width: 100%;background: white;border-top-right-radius: 20rpx;border-top-left-radius: 20rpx;}
布局是上下排列,所以使用column布局方式,然后通过border-top-right-radius和border-top-left-radius来实现左上角和右上角的圆角。
内容顶部
.top {display: flex;flex-direction: row;justify-content: space-between;align-items: center;height: 100rpx;border-bottom: 1rpx solid #d3cfcf;}.top-text {font-size: 30rpx;width: 150rpx;height: 100rpx;display: flex;flex-direction: row;justify-content: center;align-items: center;}
横向排列按钮,所以选用row布局,然后设置字体样式。
picker
这里主要是使用的系统提供的picekr-view实现,后面会给出完整代码。
布局实现
<view class='mask' wx:if="{{isShow}}" catchtap="cancel"><view class="content" style="height:500rpx" animation="{{animation}}"><view class="top"><view class="top-text top-left-color" hover-class="top-left-color-hover" catchtap="lefttap">全部</view><view class="top-text top-right-color" hover-class="top-right-color-hover" catchtap="righttap">确定</view></view><picker-view style="width: 100%; height: 400rpx;" value="{{value}}" bindchange="bindChange" catchtap="no"><picker-view-column><view wx:for="{{years}}" style="line-height: 50px" class="item">{{item}}年</view></picker-view-column></picker-view></view></view>
js实现
我们这里为了更好的封装采用component形式:
var thatComponent({/*** 组件的属性列表*/properties: {//开始年份start: {type: Number,value: 1900},//结束年份end: {type: Number,value: 9999}},/*** 组件的初始数据*/data: {isShow: false,value: [0],//设置picker-view默认哪项选中years: [],year: 1900,current: 1900,dialogh: 0},attached: function () {console.log('attached')that = this//动画that.animation = wx.createAnimation({duration: 300})//500rpx转成pxvar dialoghpx = 500 / 750 * wx.getSystemInfoSync().windowWidththat.setData({dialogh: dialoghpx})},detached: function () {console.log('detached')},pageLifetimes: {//组件所在的页面被展示时执行 最低版本2.2.3show: function () {console.log('页面show')var yearstemp = []for(var i = that.properties.start; i <= that.properties.end; i ++){yearstemp.push(i)}//通过配置属性获取yearsthat.setData({years: yearstemp})},//组件所在的页面被隐藏时执行 最低版本2.2.3hide: function () {console.log('页面被隐藏')},//这个函数一般使用场景较少,了解就可以了 最低版本2.4.0resize: function (size) {console.log('页面尺寸变化')}},/*** 组件的方法列表*/methods: {bindChange: function (e) {const val = e.detail.valuethat.setData({year: this.data.years[val[0]]})},//这个current不放properties中是因为properties中的属性只会初始化一次,而这里需要动态改变showDialog(current){that.setData({isShow: true})var currentindex = 0//筛选出默认选择项目that.data.years.forEach(function(v,i,s){if(current == v){currentindex = i}})that.setData({[`value[0]`] : currentindex,year: that.data.years[currentindex],current: current})//先向下移动dialog高度,然后恢复原位从而形成从下向上弹出效果that.animation.translateY(that.data.dialogh).translateY(0).step()that.setData({animation: that.animation.export()})},cancel(){//绑定cancel事件this.triggerEvent("cancel")that.dimsss()},dimsss(){//从原位向下移动dailog高度,形成从上向下的收起效果that.animation.translateY(that.data.dialogh).step()that.setData({animation: that.animation.export()})//动画结束后蒙层消失setTimeout(() => {that.setData({isShow: false})}, 300)},lefttap(){//绑定lefttap事件this.triggerEvent("lefttap")that.dimsss()},righttap(){//绑定righttap事件this.triggerEvent("righttap",{year: that.data.year})that.dimsss()}}})
样式
.mask {position: fixed;width: 100%;height: 100%;left: 0;right: 0;top: 0;bottom: 0;display: flex;background-color: rgba(0,0,0,0.7);z-index: 9999;flex-direction: column;justify-content: flex-end;}.content {display: flex;flex-direction: column;width: 100%;background: white;border-top-right-radius: 20rpx;border-top-left-radius: 20rpx;}.top {display: flex;flex-direction: row;justify-content: space-between;align-items: center;height: 100rpx;border-bottom: 1rpx solid #d3cfcf;}.top-text {font-size: 30rpx;width: 150rpx;height: 100rpx;display: flex;flex-direction: row;justify-content: center;align-items: center;}.top-left-color {color: #878787;}.top-left-color-hover {color: #f1eaea;}.top-right-color {color: #1296DB;}.top-right-color-hover {color: #82ccf3;}.item {width: 100%;align-items: center;justify-content: center;display: flex;flex-direction: row;font-size: 35rpx;}
使用姿势
json中引用组件:
"usingComponents": {"custom-picker":"../component/datepickerview/datepickerview"}
布局文件:
<button bindtap="showpicker">自定义picker</button><custom-picker id="custom-picker" start="" end="" bind:lefttap='_lefttap' bind:righttap='_righttap' bindcancel="_cancel"/>
js文件:
const app = getApp()var thatPage({data: {current: },onLoad: function () {that = this},onReady: function () {that.picker = that.selectComponent("#custom-picker")},showpicker(){that.picker.showDialog(that.data.current)},_lefttap(){wx.showToast({title: '左边按钮被点击',icon: 'none'})},_righttap(e){var year = e.detail.yearwx.showToast({title: '右边按钮被点击,选择的值为:'+year,icon: 'none'})//保存选择的年份that.setData({current:year})},_cancel(){wx.showToast({title: 'picker被取消',icon: 'none'})}})
最终效果图:
代码获取
如果你想要获取完整代码
请戳↓↓↓↓
点击用微信开发者工具打开
尾巴
这里还是要吐槽下微信小程序的API设计,这么一个简单的API都没有提供给开发者,为了这么一个小功能还得自己整一个picker。不过虽然折腾了下,我怎么觉得自定义的这个picker比官方的更好看,哈哈。
文章中关键位置已经做好注释,如果有问题欢迎留言。
老规矩,喜欢我的文章,欢迎素质三连:点赞,评论,关注,谢谢大家!