主题
自定义 picker
内置 picker 无法满足多列联动、复杂选项或自定义操作区时,可以组合 root-portal、page-container、picker-view 和 picker-view-column 实现底部选择器。
| 组件 | 作用 |
|---|---|
root-portal | 将浮层提升到页面根节点,避免祖先布局和层叠上下文影响 |
page-container | 提供遮罩、底部进出场动画和返回行为 |
picker-view | 管理各列当前选中项的索引 |
picker-view-column | 定义一列可滚动选项 |
结构
xml
<root-portal enable>
<page-container
show="{{showPicker}}"
position="bottom"
round
overlay
bind:clickoverlay="closePicker"
>
<view class="picker-sheet">
<view class="picker-sheet__header">
<button class="picker-sheet__action" bindtap="closePicker">取消</button>
<text>选择地区</text>
<button class="picker-sheet__action" bindtap="confirmPicker">确定</button>
</view>
<picker-view
class="picker-sheet__body"
value="{{draftValue}}"
indicator-style="height: 88rpx;"
bindchange="handlePickerChange"
>
<picker-view-column>
<view
wx:for="{{provinces}}"
wx:key="id"
class="picker-sheet__item"
>
{{item.name}}
</view>
</picker-view-column>
<picker-view-column>
<view wx:for="{{cities}}" wx:key="id" class="picker-sheet__item">
{{item.name}}
</view>
</picker-view-column>
</picker-view>
</view>
</page-container>
</root-portal>css
.picker-sheet {
padding-bottom: env(safe-area-inset-bottom);
background: #fff;
}
.picker-sheet__header {
display: flex;
align-items: center;
justify-content: space-between;
height: 96rpx;
padding: 0 24rpx;
}
.picker-sheet__action {
margin: 0;
padding: 0;
color: #576b95;
background: transparent;
}
.picker-sheet__action::after {
border: 0;
}
.picker-sheet__body {
width: 100%;
height: 440rpx;
}
.picker-sheet__item {
display: flex;
align-items: center;
justify-content: center;
height: 88rpx;
}picker-view 的 value 是索引数组,数组位置对应列,数组值对应该列的选项索引。列数据变化后,应同步修正越界索引。
js
Page({
data: {
showPicker: false,
value: [0, 0],
draftValue: [0, 0],
provinces: [],
cities: [],
},
openPicker() {
this.setData({
showPicker: true,
draftValue: [...this.data.value],
})
},
handlePickerChange(event) {
const draftValue = event.detail.value
// 第一列变化时,在此更新第二列数据,并将无效索引重置为 0。
this.setData({ draftValue })
},
closePicker() {
this.setData({ showPicker: false })
},
confirmPicker() {
this.setData({
value: [...this.data.draftValue],
showPicker: false,
})
},
})状态与兼容性
- 将已确认值与弹层内的临时值分开;取消时丢弃临时值,确认时再提交。
bindchange在滚动停止后触发。多列联动应根据最新索引更新后续列,并处理空数组。picker-view必须具有明确高度,列中的每个选项也应保持一致高度。- 同一页面最多使用一个
page-container。关闭动作统一修改show,避免视图状态与业务状态不一致。 root-portal需要基础库 2.25.2 及以上,page-container需要基础库 2.16.0 及以上;使用前确认最低基础库版本,并为低版本准备普通定位浮层。
参考:
