Skip to content

DropMenu 下拉菜单

介绍

DropMenu 下拉菜单是一个向下或向上弹出的菜单列表组件,常用于筛选、排序等场景。组件由 wd-drop-menuwd-drop-menu-item 两部分组成,支持多个菜单项同时存在,点击某一菜单项时会自动关闭其他已展开的菜单。

组件支持向上和向下两种展开方向,提供了丰富的配置选项,包括自定义选项数据、禁用状态、切换前回调等功能,能够满足各种筛选场景的需求。

核心特性:

  • 双向展开 - 支持向上(up)和向下(down)两种展开方向
  • 自动互斥 - 点击某一菜单时自动关闭其他已展开的菜单
  • 遮罩层 - 可配置是否显示遮罩层及点击遮罩关闭
  • 禁用状态 - 支持禁用单个菜单项
  • 切换回调 - 支持 beforeToggle 回调控制菜单展开/关闭
  • 自定义内容 - 支持通过插槽自定义菜单内容

基本用法

基础下拉菜单

通过 options 设置选项数据,v-model 绑定选中值。

vue
<template>
  <wd-drop-menu>
    <wd-drop-menu-item v-model="value1" :options="options1" />
    <wd-drop-menu-item v-model="value2" :options="options2" />
  </wd-drop-menu>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const value1 = ref(0)
const value2 = ref('a')

const options1 = ref([
  { label: '全部商品', value: 0 },
  { label: '新款商品', value: 1 },
  { label: '活动商品', value: 2 },
])

const options2 = ref([
  { label: '综合排序', value: 'a' },
  { label: '销量优先', value: 'b' },
  { label: '价格优先', value: 'c' },
])
</script>

自定义菜单标题

设置 title 属性可以自定义菜单标题,不再根据选中值自动显示。

vue
<template>
  <wd-drop-menu>
    <wd-drop-menu-item v-model="value" title="商品分类" :options="options" />
  </wd-drop-menu>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const value = ref(0)
const options = ref([
  { label: '全部商品', value: 0 },
  { label: '新款商品', value: 1 },
  { label: '活动商品', value: 2 },
])
</script>

向上展开

设置 direction="up" 使菜单向上展开。

vue
<template>
  <wd-drop-menu direction="up">
    <wd-drop-menu-item v-model="value1" :options="options1" />
    <wd-drop-menu-item v-model="value2" :options="options2" />
  </wd-drop-menu>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const value1 = ref(0)
const value2 = ref('a')

const options1 = ref([
  { label: '全部商品', value: 0 },
  { label: '新款商品', value: 1 },
])

const options2 = ref([
  { label: '综合排序', value: 'a' },
  { label: '销量优先', value: 'b' },
])
</script>

禁用菜单

设置 disabled 属性禁用菜单项。

vue
<template>
  <wd-drop-menu>
    <wd-drop-menu-item v-model="value1" :options="options1" />
    <wd-drop-menu-item v-model="value2" :options="options2" disabled />
  </wd-drop-menu>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const value1 = ref(0)
const value2 = ref('a')

const options1 = ref([
  { label: '全部商品', value: 0 },
  { label: '新款商品', value: 1 },
])

const options2 = ref([
  { label: '综合排序', value: 'a' },
  { label: '销量优先', value: 'b' },
])
</script>

带提示文字的选项

通过 tipKey 设置选项提示文字的字段名。

vue
<template>
  <wd-drop-menu>
    <wd-drop-menu-item v-model="value" :options="options" tip-key="tip" />
  </wd-drop-menu>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const value = ref(0)
const options = ref([
  { label: '全部商品', value: 0, tip: '共1000件' },
  { label: '新款商品', value: 1, tip: '共200件' },
  { label: '活动商品', value: 2, tip: '共50件' },
])
</script>

自定义选中图标

通过 icon-name 设置选中项的图标。

vue
<template>
  <wd-drop-menu>
    <wd-drop-menu-item v-model="value" :options="options" icon-name="success" />
  </wd-drop-menu>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const value = ref(0)
const options = ref([
  { label: '全部商品', value: 0 },
  { label: '新款商品', value: 1 },
  { label: '活动商品', value: 2 },
])
</script>

切换前回调

通过 before-toggle 属性设置切换前回调,可以阻止菜单展开或关闭。

vue
<template>
  <wd-drop-menu>
    <wd-drop-menu-item
      v-model="value"
      :options="options"
      :before-toggle="handleBeforeToggle"
    />
  </wd-drop-menu>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import type { DropMenuItemBeforeToggle } from '@/wd/components/wd-drop-menu-item/wd-drop-menu-item.vue'

const value = ref(0)
const options = ref([
  { label: '全部商品', value: 0 },
  { label: '新款商品', value: 1 },
  { label: '活动商品', value: 2 },
])

const handleBeforeToggle: DropMenuItemBeforeToggle = ({ status, resolve }) => {
  if (status) {
    // 打开前的逻辑,如权限校验
    console.log('即将打开菜单')
  } else {
    // 关闭前的逻辑
    console.log('即将关闭菜单')
  }
  // 调用 resolve(true) 允许操作,resolve(false) 阻止操作
  resolve(true)
}
</script>

自定义菜单内容

不传 options 时,可以通过默认插槽自定义菜单内容。

vue
<template>
  <wd-drop-menu>
    <wd-drop-menu-item v-model="value" :options="options" />
    <wd-drop-menu-item title="筛选">
      <view class="custom-content">
        <wd-cell title="包邮" center>
          <wd-switch v-model="freeShipping" />
        </wd-cell>
        <wd-cell title="有货" center>
          <wd-switch v-model="inStock" />
        </wd-cell>
        <view class="custom-content__footer">
          <wd-button type="primary" block @click="handleConfirm">确定</wd-button>
        </view>
      </view>
    </wd-drop-menu-item>
  </wd-drop-menu>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const value = ref(0)
const freeShipping = ref(false)
const inStock = ref(false)

const options = ref([
  { label: '全部商品', value: 0 },
  { label: '新款商品', value: 1 },
])

const handleConfirm = () => {
  // 关闭菜单的逻辑
}
</script>

<style lang="scss" scoped>
.custom-content {
  padding: 24rpx;

  &__footer {
    margin-top: 24rpx;
  }
}
</style>

监听事件

监听 change 事件获取选中值变化。

vue
<template>
  <wd-drop-menu>
    <wd-drop-menu-item
      v-model="value"
      :options="options"
      @change="handleChange"
      @open="handleOpen"
      @close="handleClose"
    />
  </wd-drop-menu>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const value = ref(0)
const options = ref([
  { label: '全部商品', value: 0 },
  { label: '新款商品', value: 1 },
  { label: '活动商品', value: 2 },
])

const handleChange = ({ value, selectedItem }) => {
  console.log('选中值:', value)
  console.log('选中项:', selectedItem)
}

const handleOpen = () => {
  console.log('菜单打开')
}

const handleClose = () => {
  console.log('菜单关闭')
}
</script>

API

DropMenu Props

参数说明类型默认值
direction菜单展开方向'up' | 'down'down
modal是否显示遮罩层booleantrue
close-on-click-modal是否点击遮罩层关闭菜单booleantrue
duration菜单展开收起动画时间,单位 msnumber200
z-index弹框层级number12
custom-class自定义根节点样式类string-
custom-style自定义根节点样式string-

DropMenuItem Props

参数说明类型默认值
v-model当前选中项的 valuestring | number-
options选项数据Array<{label, value, tip?}>[]
title菜单标题string-
disabled是否禁用booleanfalse
icon菜单图标stringarrow-down
icon-size菜单图标大小string | number-
icon-name选中项的图标名称stringcheck
value-key选项中 value 对应的 keystringvalue
label-key选项中展示文本对应的 keystringlabel
tip-key选项中提示文字对应的 keystringtip
before-toggle切换前回调函数DropMenuItemBeforeToggle-
custom-class自定义根节点样式类string-
custom-style自定义根节点样式string-
custom-title自定义标题样式类string-
custom-icon自定义图标样式类string-
custom-popup-class自定义弹出层样式类string-
custom-popup-style自定义弹出层样式string-

DropMenuItem Events

事件名说明回调参数
change选中值改变时触发{ value: string | number, selectedItem: object }
open菜单打开前触发-
opened菜单打开后触发-
close菜单关闭前触发-
closed菜单关闭后触发-

DropMenuItem Methods

通过 ref 获取组件实例后可调用以下方法:

方法名说明参数返回值
open打开菜单--
close关闭菜单--
toggle切换菜单显示状态--
getShowPop获取菜单显示状态-boolean

DropMenuItem Slots

插槽名说明
default自定义菜单内容,不传 options 时生效

类型定义

typescript
/**
 * 下拉菜单方向类型
 */
type DropDirction = 'up' | 'down'

/**
 * 切换前回调选项
 */
interface DropMenuItemBeforeToggleOption {
  /** 操作状态:true 打开,false 关闭 */
  status: boolean
  /** 回调函数,resolve(true) 允许操作,resolve(false) 阻止操作 */
  resolve: (isPass: boolean) => void
}

/**
 * 切换前回调函数类型
 */
type DropMenuItemBeforeToggle = (option: DropMenuItemBeforeToggleOption) => void

/**
 * 选项数据结构
 */
interface DropMenuOption {
  /** 选项标签 */
  label: string
  /** 选项值 */
  value: string | number
  /** 提示文字 */
  tip?: string
}

主题定制

CSS 变量

组件提供了以下 CSS 变量用于主题定制:

变量名说明默认值
--wd-drop-menu-color菜单文字颜色#333333
--wd-drop-menu-fs菜单字体大小28rpx
--wd-drop-menu-height菜单高度88rpx
--wd-drop-menu-disabled-color禁用状态颜色#c0c4cc
--wd-drop-menu-side-padding菜单项内边距32rpx
--wd-drop-menu-arrow-fs箭头图标大小40rpx
--wd-drop-menu-line-color激活状态下划线颜色主题色
--wd-drop-menu-line-height激活状态下划线高度6rpx
--wd-drop-menu-item-fs选项字体大小28rpx
--wd-drop-menu-item-color选项文字颜色#333333
--wd-drop-menu-item-height选项高度88rpx
--wd-drop-menu-item-color-active选项激活状态颜色主题色
--wd-drop-menu-item-color-tip提示文字颜色#909399
--wd-drop-menu-item-fs-tip提示文字字体大小24rpx

暗黑模式

组件已适配暗黑模式,在暗黑主题下会自动切换样式。

最佳实践

1. 商品筛选场景

vue
<template>
  <wd-drop-menu>
    <wd-drop-menu-item v-model="category" :options="categoryOptions" />
    <wd-drop-menu-item v-model="sort" :options="sortOptions" />
    <wd-drop-menu-item title="筛选" @open="handleFilterOpen">
      <view class="filter-content">
        <!-- 自定义筛选内容 -->
      </view>
    </wd-drop-menu-item>
  </wd-drop-menu>
</template>

2. 控制菜单开关

vue
<template>
  <wd-drop-menu>
    <wd-drop-menu-item ref="menuItemRef" v-model="value" :options="options" />
  </wd-drop-menu>
  <wd-button @click="openMenu">打开菜单</wd-button>
</template>

<script lang="ts" setup>
import { ref } from 'vue'

const menuItemRef = ref()

const openMenu = () => {
  menuItemRef.value?.open()
}
</script>

常见问题

1. 菜单展开方向不对?

确保 direction 属性设置正确,down 向下展开,up 向上展开。向上展开时,组件需要有足够的上方空间。

2. 如何异步加载选项数据?

vue
<script lang="ts" setup>
import { ref, onMounted } from 'vue'

const options = ref([])

onMounted(async () => {
  const data = await fetchOptions()
  options.value = data
})
</script>

3. 如何在选择后执行额外逻辑?

监听 change 事件:

vue
<wd-drop-menu-item
  v-model="value"
  :options="options"
  @change="({ value, selectedItem }) => {
    // 执行额外逻辑,如请求数据
    fetchData(value)
  }"
/>
移动端预览