在开发中,小程序提供了内置picker组件来供开发者使用。但picker组件无法自定义按钮颜色、选择器样式,造成在有UI要求时束手无策(我觉得滑动体验也不是很好orz)。这个时候就需要使用picker-view组件来自定义弹出滚动选择器了。
样式如下:
首先确定组件的属性
加入pickerShow是因为项目中有需要触发选择器弹出的需求
- picker-show 【Boolean】控制弹出隐藏
- range 【二维Array】 二维数组,长度表示多少列,数组的每项表示每列的数据
- title 【Array】 选择器每列标题
- value 【Array】 value 每一项的值表示选择了 range 对应项中的第几个(下标从 0 开始)
- is-shadow 【Boolean】 是否需要显示遮罩层
- bindchange 【EventHandle】 value 改变时触发 change 事件 event.detail = value
- bindfinish 【EventHandle】 完成时触发 event.detail = value
- bindcancel 【EventHandle】 取消时触发
需要有几列,就在 range 中传入几项
// 使用时,可插入选择器标题
从底部弹起的滚动选择器
// 页面逻辑
Page({
data: {
val: [// 数据列表
['大天狗', '玉藻前', '妖刀姬', '茨木童子'],
['追月神', '姑获鸟', '犬神', '黑童子']
]
},
finishHandler(e){
console.log(e.detail)// 选择的结果 如:["妖刀姬", "犬神"]
}
})
// .json
{
"usingComponents": {
"my-picker": "/components/my-picker/my-picker"
}
}
如有需要定制样式,就可以直接在components组件中直接修改就可以啦~
下面是组件的完整代码
// my-picker.js
Component({
/**
* 组件的属性列表
*/
properties: {
pickerShow:{
type: Boolean, // 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Array, null(表示任意类型)
value: false, // 属性初始值(可选),如果未指定则会根据类型选择一个
observer (newVal, oldVal, changedPath) {
// 属性被改变时执行的函数(可选),也可以写成在methods段中定义的方法名字符串, 如:'_propertyChange'
// 通常 newVal 就是新设置的数据, oldVal 是旧数据
}
},
isShadow: {
type: Boolean,
value: true,
observer(newVal, oldVal, changedPath) {}
},
range:{
type: Array,
value: []
},
title:{
type: Array,
value: []
},
value: {// picker-view 内的 picker-view-column 当前选择的是第几项
type: Array,
value: [2, 2]
}
},
/**
* 组件的方法列表
*/
methods: {
pickerHandler() {// 控制弹出层显示隐藏
this.setData({ pickerShow: !this.data.pickerShow })
},
bindChange(e) {// value 改变时触发 change 事件
const val = e.detail.value
this.setData({ value: val })
let arr = []
this.data.range.forEach((v, i) => {
arr.push(v[this.data.value[i]])
})
this.triggerEvent('change', arr, {})
},
pickerFinish() {// 滚动选择器 - 完成
let arr = []
this.data.range.forEach((v, i) => {
arr.push(v[this.data.value[i]])
})
this.pickerHandler()
this.triggerEvent('finish', arr, {})
},
pickerCancel() {// 滚动选择器 - 取消
this.pickerHandler()
this.triggerEvent('cancel', arr, {})
}
}
})
// my-picker.wxml
取消
完成
{{item}}
{{a}}
/*my-picker.wxss*/
picker-view-column{font-size: 14px;text-align: center;}
.com-picker-view{position: fixed;bottom: 0;width: 100%;z-index: 3;background: #fff;}
/* 弹出标题 */
.com-picker-title{display: flex;padding: 10px 15px;font-size: 14px;border-bottom: #f8f8f8 1px solid;}
.com-picker-cancel{color: #999;}
.com-picker-finish{color: palevioletred;}
.com-picker-result{flex: 1;text-align: center;color: #999;}
.com-title{display: flex;border-bottom: #f8f8f8 1px solid;}
.com-title > view{flex:1;text-align: center;line-height: 40px;font-size: 14px;}
/* 弹出效果 */
.com-picker-view.false{transform:translateY(100%);-webkit-transform:translateY(100%);transition: all .3s cubic-bezier(0,.54,.51,.99);-webikit-transition: all .3s cubic-bezier(0,.54,.51,.99);opacity: 1;}
.com-picker-view.true{transform:translateY(0%);-webkit-transform:translateY(0%);transition: all .3s cubic-bezier(0,.54,.51,.99);-webikit-transition: all .3s cubic-bezier(0,.54,.51,.99);opacity: 1;}
/* 遮罩 */
.com-picker-shadow{width: 100%;height: 100%;position: fixed;top: 0;left: 0; background-color:rgba(0,0,0,0.3);z-index: 2}
.com-picker-shadow.true{ -webkit-transition: opacity 0.35s, visibility 0.35s;transition: opacity 0.35s, visibility 0.35s;visibility: visible;opacity: 1;}
.com-picker-shadow.false{visibility: hidden;opacity: 0; -webkit-transition: opacity 0.35s, visibility 0.35s;transition: opacity 0.35s, visibility 0.35s;}
// my-picker.json
{
"component": true,
"usingComponents": {}
}