Skip to content

自定义微信小程序 picker 组件

约 780 字大约 3 分钟

微信小程序

2025-04-29

微信小程序中的 picker 是一个从底部弹起的滚动选择器,虽然能够满足大多数应用场景, 但如果我们需要让内容不局限于选择器,而是要在这个 抽屉 里面放各式各样的内容, 那官方 api 就不太能够满足这个需求了,我们需要自定义一个 picker 组件。这个效果实现起来并不难,但是涉及到一些基础知识,因此稍加记录。

组件结构

picker 译为 选择器,但我们想要完成的这个组件的内容可能是一些表单、一些文档等,它可以像抽屉一样弹出,因此我们将它 命名为 drawer

为了模仿原本 picker 的效果,可以将 drawer 写为 两个 view ,一个为 黑色蒙版,一个为 抽屉内容,其中内容需要留一个 slot。在弹出抽屉 时,黑色蒙版缓慢渐显,抽屉内容缓慢从底部弹出,所以需要先设定两者动画时间。

需要点击黑色蒙版时,关闭抽屉,使用 bindtap 绑定父视图的点击事件,同时使用 catchtap 绑定子视图的点击事件(空事件),阻止事件冒泡到父视图。

<!-- drawer.wxml -->
<!--黑色蒙版-->
<view class="mask" style="opacity: {{maskOpacity}};" wx:if="{{isShow}}" bindtap="closeDrawerHandler">
  <!-- 内容区域 -->
  <view class="content" style="transform: translateY({{transformValue}});" catchtap="handleChildTap">
    <slot></slot>
  </view>
</view>

在 js 中定义 isShow 用老控制 drawer 是否渲染,maskOpacity 用来控制蒙版透明度,transformValue 用来控制抽屉内容移动的距离。

小程序中的 setData 是异步的,因此可以用到 setData 的第二个参数,回调函数( setData 成功之后执行的函数)来执行组件被渲染后的 DOM 操作。或者使用 wx.nextTick() 确保在数据变更引起的视图渲染完成后,再执行 DOM 操作。同时,因为在 wxss 中定义的动画时间为 300 毫秒,因此在关闭抽屉时,需要在动画执行结束后 300 毫秒后, 再设置 isShowfalse

外部引用

在父视图的 .json 中定义 usingComponents ,将 drawer 组件引入:

  "usingComponents": {
    "drawer": "/components/drawer/drawer"
  }

wxml 中使用 drawer 组件,并给组件一个 ID:

<drawer id="custom-drawer">
    <view>
        抽屉内容
    </view>
</drawer>
<button type="primary" bindtap="showDrawer"></button>

js 中使用 selectComponent 获取组件实例,并调用组件的 showDrawerHandler 方法:

showDrawer(){
    let drawer = this.selectComponent("#custom-drawer")
    picker.showDrawerHandler()
}

最终效果

img.png