介绍
可向下/向上弹出菜单列表,或自定义弹出的菜单内容。
代码演示
基础使用
使用 options 配置下拉菜单项,使用 v-model 绑定选中的值。
vue
<template>
<s-dropdown>
<s-dropdown-item v-model="value1" :options="options1" />
<s-dropdown-item v-model="value2" :options="options2" />
</s-dropdown>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const options2 = [
{
label: '30分钟内',
value: '1',
},
{
label: '40分钟内',
value: '2',
},
{
label: '50分钟内',
value: '3',
},
]
const value1 = ref('1')
const value2 = ref('1')
</script>vue
<template>
<s-dropdown>
<s-dropdown-item v-model="value1" :options="options1" />
<s-dropdown-item v-model="value2" :options="options2" />
</s-dropdown>
</template>
<script setup lang="js">
import { ref } from 'vue'
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const options2 = [
{
label: '30分钟内',
value: '1',
},
{
label: '40分钟内',
value: '2',
},
{
label: '50分钟内',
value: '3',
},
]
const value1 = ref('1')
const value2 = ref('1')
</script>占位符
占位符会在未选中值时显示说明文字。
vue
<template>
<s-dropdown>
<s-dropdown-item placeholder="排序" :options="options1" />
<s-dropdown-item placeholder="配送时间" :options="options2" />
</s-dropdown>
</template>
<script setup lang="ts">
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const options2 = [
{
label: '30分钟内',
value: '1',
},
{
label: '40分钟内',
value: '2',
},
{
label: '50分钟内',
value: '3',
},
]
</script>vue
<template>
<s-dropdown>
<s-dropdown-item placeholder="排序" :options="options1" />
<s-dropdown-item placeholder="配送时间" :options="options2" />
</s-dropdown>
</template>
<script setup lang="js">
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const options2 = [
{
label: '30分钟内',
value: '1',
},
{
label: '40分钟内',
value: '2',
},
{
label: '50分钟内',
value: '3',
},
]
</script>添加 label
相较于占位符, label 会一直显示。
vue
<template>
<s-dropdown>
<s-dropdown-item label="排序" :options="options1" model-value="1" />
<s-dropdown-item label="速度" :options="options2" model-value="2" />
</s-dropdown>
</template>
<script setup lang="ts">
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const options2 = [
{
label: '30分钟内',
value: '1',
},
{
label: '40分钟内',
value: '2',
},
{
label: '50分钟内',
value: '3',
},
]
</script>vue
<template>
<s-dropdown>
<s-dropdown-item label="排序" :options="options1" model-value="1" />
<s-dropdown-item label="速度" :options="options2" model-value="2" />
</s-dropdown>
</template>
<script setup lang="js">
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const options2 = [
{
label: '30分钟内',
value: '1',
},
{
label: '40分钟内',
value: '2',
},
{
label: '50分钟内',
value: '3',
},
]
</script>向上展开
底部空间不足时可以配置向上弹出菜单。
vue
<template>
<s-dropdown direction="up">
<s-dropdown-item :options="options1" model-value="1" />
<s-dropdown-item :options="options2" model-value="2" />
</s-dropdown>
</template>
<script setup lang="ts">
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const options2 = [
{
label: '30分钟内',
value: '1',
},
{
label: '40分钟内',
value: '2',
},
{
label: '50分钟内',
value: '3',
},
]
</script>vue
<template>
<s-dropdown direction="up">
<s-dropdown-item :options="options1" model-value="1" />
<s-dropdown-item :options="options2" model-value="2" />
</s-dropdown>
</template>
<script setup lang="js">
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const options2 = [
{
label: '30分钟内',
value: '1',
},
{
label: '40分钟内',
value: '2',
},
{
label: '50分钟内',
value: '3',
},
]
</script>禁用
禁用的菜单项不可点击。
vue
<template>
<s-dropdown disabled>
<s-dropdown-item :options="options1" model-value="1" />
<s-dropdown-item :options="options2" model-value="2" />
</s-dropdown>
</template>
<script setup lang="ts">
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const options2 = [
{
label: '30分钟内',
value: '1',
},
{
label: '40分钟内',
value: '2',
},
{
label: '50分钟内',
value: '3',
},
]
</script>vue
<template>
<s-dropdown disabled>
<s-dropdown-item :options="options1" model-value="1" />
<s-dropdown-item :options="options2" model-value="2" />
</s-dropdown>
</template>
<script setup lang="js">
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const options2 = [
{
label: '30分钟内',
value: '1',
},
{
label: '40分钟内',
value: '2',
},
{
label: '50分钟内',
value: '3',
},
]
</script>自定义内容
除了显示菜单项,下拉菜单还可以显示任意内容,这时可以使用 v-model:visible 控制显隐。
vue
<template>
<s-dropdown>
<s-dropdown-item :options="options1" model-value="1" />
<s-dropdown-item title="筛选" v-model:visible="visible">
<s-list inlaid>
<s-list-item title="包邮">
<template #value>
<s-switch :model-value="true" />
</template>
</s-list-item>
<s-list-item title="团购">
<template #value>
<s-switch />
</template>
</s-list-item>
<s-list-item>
<s-button round @click="visible = false">确认</s-button>
</s-list-item>
</s-list>
</s-dropdown-item>
</s-dropdown>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const visible = ref(false)
</script>vue
<template>
<s-dropdown>
<s-dropdown-item :options="options1" model-value="1" />
<s-dropdown-item title="筛选" v-model:visible="visible">
<s-list inlaid>
<s-list-item title="包邮">
<template #value>
<s-switch :model-value="true" />
</template>
</s-list-item>
<s-list-item title="团购">
<template #value>
<s-switch />
</template>
</s-list-item>
<s-list-item>
<s-button round @click="visible = false">确认</s-button>
</s-list-item>
</s-list>
</s-dropdown-item>
</s-dropdown>
</template>
<script setup lang="js">
import { ref } from 'vue'
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const visible = ref(false)
</script>异步开关
如果 beforeOpen 返回 false,则取消打开菜单;如果返回 Promise 对象,则会在 resolve 时才打开菜单。
如果 beforeClose 返回 false,则取消关闭菜单;如果返回 Promise 对象,则会在 resolve 时才关闭菜单。
vue
<template>
<s-dropdown direction="up">
<s-dropdown-item
v-model="value1"
:options="options1"
:before-open="beforeOpen"
:before-close="beforeClose"
/>
<s-dropdown-item
v-model="value2"
:options="options2"
:before-open="beforeOpen"
:before-close="beforeClose"
/>
</s-dropdown>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { toast, type DropdownCloseType } from 'sard'
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const options2 = [
{
label: '30分钟内',
value: '1',
},
{
label: '40分钟内',
value: '2',
},
{
label: '50分钟内',
value: '3',
},
]
const value1 = ref('1')
const value2 = ref('1')
const doSomething = () => {
return new Promise((resolve) => {
setTimeout(resolve, 500)
})
}
const beforeOpen = () => {
toast.loading('加载中', {
overlay: true,
})
return doSomething().finally(() => {
toast.hide()
})
}
const beforeClose = (type: DropdownCloseType) => {
if (type === 'option') {
toast.loading('加载中', {
overlay: true,
})
return doSomething().finally(() => {
toast.hide()
})
}
}
</script>vue
<template>
<s-dropdown direction="up">
<s-dropdown-item
v-model="value1"
:options="options1"
:before-open="beforeOpen"
:before-close="beforeClose"
/>
<s-dropdown-item
v-model="value2"
:options="options2"
:before-open="beforeOpen"
:before-close="beforeClose"
/>
</s-dropdown>
</template>
<script setup lang="js">
import { ref } from 'vue'
import { toast } from 'sard'
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const options2 = [
{
label: '30分钟内',
value: '1',
},
{
label: '40分钟内',
value: '2',
},
{
label: '50分钟内',
value: '3',
},
]
const value1 = ref('1')
const value2 = ref('1')
const doSomething = () => {
return new Promise((resolve) => {
setTimeout(resolve, 500)
})
}
const beforeOpen = () => {
toast.loading('加载中', { overlay: true })
return doSomething().finally(() => {
toast.hide()
})
}
const beforeClose = (type) => {
if (type === 'option') {
toast.loading('加载中', { overlay: true })
return doSomething().finally(() => {
toast.hide()
})
}
}
</script>可取消选择
如果想点击时取消选中的选项,可以使用 togglable 属性。
vue
<template>
<s-dropdown togglable direction="up">
<s-dropdown-item v-model="value1" placeholder="排序" :options="options1" />
<s-dropdown-item v-model="value2" placeholder="配送时间" :options="options2" />
</s-dropdown>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const options2 = [
{
label: '30分钟内',
value: '1',
},
{
label: '40分钟内',
value: '2',
},
{
label: '50分钟内',
value: '3',
},
]
const value1 = ref('1')
const value2 = ref('1')
</script>vue
<template>
<s-dropdown togglable direction="up">
<s-dropdown-item v-model="value1" placeholder="排序" :options="options1" />
<s-dropdown-item v-model="value2" placeholder="配送时间" :options="options2" />
</s-dropdown>
</template>
<script setup lang="js">
import { ref } from 'vue'
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const options2 = [
{
label: '30分钟内',
value: '1',
},
{
label: '40分钟内',
value: '2',
},
{
label: '50分钟内',
value: '3',
},
]
const value1 = ref('1')
const value2 = ref('1')
</script>分隔线
可以使用 separator 来设置菜单与面板之间的分割线类型。
vue
<template>
<s-dropdown separator="shadow" direction="up">
<s-dropdown-item v-model="value1" :options="options1" />
<s-dropdown-item v-model="value2" :options="options2" />
</s-dropdown>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const options2 = [
{
label: '30分钟内',
value: '1',
},
{
label: '40分钟内',
value: '2',
},
{
label: '50分钟内',
value: '3',
},
]
const value1 = ref('1')
const value2 = ref('1')
</script>vue
<template>
<s-dropdown separator="shadow" direction="up">
<s-dropdown-item v-model="value1" :options="options1" />
<s-dropdown-item v-model="value2" :options="options2" />
</s-dropdown>
</template>
<script setup lang="js">
import { ref } from 'vue'
const options1 = [
{
label: '距离优先',
value: '1',
},
{
label: '速度优先',
value: '2',
},
{
label: '评分优先',
value: '3',
},
]
const options2 = [
{
label: '30分钟内',
value: '1',
},
{
label: '40分钟内',
value: '2',
},
{
label: '50分钟内',
value: '3',
},
]
const value1 = ref('1')
const value2 = ref('1')
</script>API
DropdownProps
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| direction | 菜单弹出方向 | 'down' | 'up' | 'down' |
| disabled | 是否禁用 | boolean | false |
| away-closable | 是否在点击外部区域后自动隐藏 | boolean | true |
| overlay-closable | 是否在点击遮罩后自动隐藏 | boolean | true |
| togglable | 是否可取消选中的选项 | boolean | false |
| value-on-clear | 取消选项时设置的值 | () => any | () => undefined |
| separator | 菜单与面板之间的分割线类型 | 'shadow' | 'line' | 'none' | 'line' |
DropdownSlots
| 插槽 | 描述 | 属性 |
|---|---|---|
| default | 自定义默认内容 | - |
DropdownItemProps
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| title | 标题,用于自定义菜单内容 | string | - |
| label | 标签说明 | string | - |
| options | 菜单选项 | DropdownOption[] | [] |
| disabled | 是否禁用 | boolean | false |
| model-value | 当前选择的菜单项的值 | any | - |
| visible | 弹出框是否可见 | boolean | - |
| placeholder | 占位符 | string | - |
| togglable | 是否可取消选中的选项 | boolean | false |
| value-on-clear | 取消选项时设置的值 | () => any | () => undefined |
| before-open | 打开前的回调,返回 false 或 rejected 状态的 Promise 可阻止打开 | () => any | - |
| before-close | 关闭前的回调,返回 false 或 rejected 状态的 Promise 可阻止关闭 | DropdownBeforeClose | - |
DropdownBeforeClose
ts
type DropdownBeforeClose = (type: DropdownCloseType) => any
type DropdownCloseType = 'overlay' | 'away' | 'other-button' | 'option' | 'button'关闭类型:
overlay点击遮罩away点击除遮罩和菜单之外的区域other-button点击其他菜单按钮button点击当前的菜单按钮option点击菜单项
DropdownItemSlots
| 插槽 | 描述 | 属性 |
|---|---|---|
| default | 自定义默认内容 | - |
DropdownItemEmits
继承 MotionEmits。
| 事件 | 描述 | 类型 |
|---|---|---|
| update:modelValue | 选中菜单选项时触发 | (value: any) => void |
| change | 选中菜单选项时触发 | (value: any) => void |
| update:visible | 弹出框显隐时触发 | (visible: boolean) => void |
DropdownOption
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| label | 定义选项标签 | string | - |
| value | 定义选项的值 | any | - |
主题定制
样式变量
| CSS 变量 | 值 |
|---|---|
--s-dropdown-z-index | var(--s-z-index-tertiary) |
--s-dropdown-height | var(--s-content-height) |
--s-dropdown-bg | var(--s-bg-color-elevated) |
--s-dropdown-box-shadow | var(--s-box-shadow-tertiary) |
--s-dropdown-line-color | var(--s-border-color) |
--s-dropdown-item-padding-x | var(--s-size-xs) |
--s-dropdown-item-opacity-active | var(--s-opacity-active) |
--s-dropdown-item-show-color | var(--s-color-primary) |
--s-dropdown-value-font-size | var(--s-font-size) |
--s-dropdown-label-font-size | var(--s-font-size) |
--s-dropdown-label-color | var(--s-text-color-tertiary) |
--s-dropdown-label-margin-end | var(--s-size-xs) |
--s-dropdown-placeholder-color | var(--s-text-color-fourth) |
--s-dropdown-arrow-margin-start | var(--s-size-2xs) |
--s-dropdown-arrow-color | var(--s-border-color) |
--s-dropdown-arrow-font-size | var(--s-font-size-sm) |
--s-dropdown-option-color-active | var(--s-color-primary) |
--s-dropdown-option-icon-font-size | var(--s-font-size) |