介绍
可向下/向上弹出菜单列表,或自定义弹出的菜单内容。
引入
js
import Dropdown from 'sard-uniapp/components/dropdown/dropdown.vue'
import DropdownItem from 'sard-uniapp/components/dropdown-item/dropdown-item.vue'代码演示
基础使用
使用 options 配置下拉菜单项,使用 v-model 绑定选中的值。
vue
<template>
<sar-dropdown>
<sar-dropdown-item v-model="value1" :options="options1" />
<sar-dropdown-item v-model="value2" :options="options2" />
</sar-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>
<sar-dropdown>
<sar-dropdown-item v-model="value1" :options="options1" />
<sar-dropdown-item v-model="value2" :options="options2" />
</sar-dropdown>
</template>
<script setup lang="js">
import { ref } from "vue";
const options1 = [
{
label: "\u8DDD\u79BB\u4F18\u5148",
value: "1"
},
{
label: "\u901F\u5EA6\u4F18\u5148",
value: "2"
},
{
label: "\u8BC4\u5206\u4F18\u5148",
value: "3"
}
];
const options2 = [
{
label: "30\u5206\u949F\u5185",
value: "1"
},
{
label: "40\u5206\u949F\u5185",
value: "2"
},
{
label: "50\u5206\u949F\u5185",
value: "3"
}
];
const value1 = ref("1");
const value2 = ref("1");
</script>占位符
占位符会在未选中值时显示说明文字。
vue
<template>
<sar-dropdown>
<sar-dropdown-item placeholder="排序" :options="options1" />
<sar-dropdown-item placeholder="配送时间" :options="options2" />
</sar-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>
<sar-dropdown>
<sar-dropdown-item placeholder="排序" :options="options1" />
<sar-dropdown-item placeholder="配送时间" :options="options2" />
</sar-dropdown>
</template>
<script setup lang="js">
const options1 = [
{
label: "\u8DDD\u79BB\u4F18\u5148",
value: "1"
},
{
label: "\u901F\u5EA6\u4F18\u5148",
value: "2"
},
{
label: "\u8BC4\u5206\u4F18\u5148",
value: "3"
}
];
const options2 = [
{
label: "30\u5206\u949F\u5185",
value: "1"
},
{
label: "40\u5206\u949F\u5185",
value: "2"
},
{
label: "50\u5206\u949F\u5185",
value: "3"
}
];
</script>添加 label
相较于占位符, label 会一直显示。
vue
<template>
<sar-dropdown>
<sar-dropdown-item label="排序" :options="options1" model-value="1" />
<sar-dropdown-item label="速度" :options="options2" model-value="2" />
</sar-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>
<sar-dropdown>
<sar-dropdown-item label="排序" :options="options1" model-value="1" />
<sar-dropdown-item label="速度" :options="options2" model-value="2" />
</sar-dropdown>
</template>
<script setup lang="js">
const options1 = [
{
label: "\u8DDD\u79BB\u4F18\u5148",
value: "1"
},
{
label: "\u901F\u5EA6\u4F18\u5148",
value: "2"
},
{
label: "\u8BC4\u5206\u4F18\u5148",
value: "3"
}
];
const options2 = [
{
label: "30\u5206\u949F\u5185",
value: "1"
},
{
label: "40\u5206\u949F\u5185",
value: "2"
},
{
label: "50\u5206\u949F\u5185",
value: "3"
}
];
</script>向上展开
底部空间不足时可以配置向上弹出菜单。
vue
<template>
<sar-dropdown direction="up">
<sar-dropdown-item :options="options1" model-value="1" />
<sar-dropdown-item :options="options2" model-value="2" />
</sar-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>
<sar-dropdown direction="up">
<sar-dropdown-item :options="options1" model-value="1" />
<sar-dropdown-item :options="options2" model-value="2" />
</sar-dropdown>
</template>
<script setup lang="js">
const options1 = [
{
label: "\u8DDD\u79BB\u4F18\u5148",
value: "1"
},
{
label: "\u901F\u5EA6\u4F18\u5148",
value: "2"
},
{
label: "\u8BC4\u5206\u4F18\u5148",
value: "3"
}
];
const options2 = [
{
label: "30\u5206\u949F\u5185",
value: "1"
},
{
label: "40\u5206\u949F\u5185",
value: "2"
},
{
label: "50\u5206\u949F\u5185",
value: "3"
}
];
</script>禁用
禁用的菜单项不可点击。
vue
<template>
<sar-dropdown disabled>
<sar-dropdown-item :options="options1" model-value="1" />
<sar-dropdown-item :options="options2" model-value="2" />
</sar-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>
<sar-dropdown disabled>
<sar-dropdown-item :options="options1" model-value="1" />
<sar-dropdown-item :options="options2" model-value="2" />
</sar-dropdown>
</template>
<script setup lang="js">
const options1 = [
{
label: "\u8DDD\u79BB\u4F18\u5148",
value: "1"
},
{
label: "\u901F\u5EA6\u4F18\u5148",
value: "2"
},
{
label: "\u8BC4\u5206\u4F18\u5148",
value: "3"
}
];
const options2 = [
{
label: "30\u5206\u949F\u5185",
value: "1"
},
{
label: "40\u5206\u949F\u5185",
value: "2"
},
{
label: "50\u5206\u949F\u5185",
value: "3"
}
];
</script>自定义内容
除了显示菜单项,下拉菜单还可以显示任意内容,这时可以使用 v-model:visible 控制显隐。
vue
<template>
<sar-dropdown>
<sar-dropdown-item :options="options1" model-value="1" />
<sar-dropdown-item title="筛选" v-model:visible="visible">
<sar-list inlaid>
<sar-list-item title="包邮">
<template #value>
<sar-switch :model-value="true" />
</template>
</sar-list-item>
<sar-list-item title="团购">
<template #value>
<sar-switch />
</template>
</sar-list-item>
<sar-list-item>
<sar-button round @click="visible = false">确认</sar-button>
</sar-list-item>
</sar-list>
</sar-dropdown-item>
</sar-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>
<sar-dropdown>
<sar-dropdown-item :options="options1" model-value="1" />
<sar-dropdown-item title="筛选" v-model:visible="visible">
<sar-list inlaid>
<sar-list-item title="包邮">
<template #value>
<sar-switch :model-value="true" />
</template>
</sar-list-item>
<sar-list-item title="团购">
<template #value>
<sar-switch />
</template>
</sar-list-item>
<sar-list-item>
<sar-button round @click="visible = false">确认</sar-button>
</sar-list-item>
</sar-list>
</sar-dropdown-item>
</sar-dropdown>
</template>
<script setup lang="js">
import { ref } from "vue";
const options1 = [
{
label: "\u8DDD\u79BB\u4F18\u5148",
value: "1"
},
{
label: "\u901F\u5EA6\u4F18\u5148",
value: "2"
},
{
label: "\u8BC4\u5206\u4F18\u5148",
value: "3"
}
];
const visible = ref(false);
</script>异步开关 1.19+
如果 beforeOpen 返回 false,则取消打开菜单;如果返回 Promise 对象,则会在 resolve 时才打开菜单。
如果 beforeClose 返回 false,则取消关闭菜单;如果返回 Promise 对象,则会在 resolve 时才关闭菜单。
vue
<template>
<sar-dropdown direction="up">
<sar-dropdown-item
v-model="value1"
:options="options1"
:before-open="beforeOpen"
:before-close="beforeClose"
/>
<sar-dropdown-item
v-model="value2"
:options="options2"
:before-open="beforeOpen"
:before-close="beforeClose"
/>
</sar-dropdown>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { toast, type DropdownCloseType } from 'sard-uniapp'
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>
<sar-dropdown direction="up">
<sar-dropdown-item
v-model="value1"
:options="options1"
:before-open="beforeOpen"
:before-close="beforeClose"
/>
<sar-dropdown-item
v-model="value2"
:options="options2"
:before-open="beforeOpen"
:before-close="beforeClose"
/>
</sar-dropdown>
</template>
<script setup lang="js">
import { ref } from "vue";
import { toast } from "sard-uniapp";
const options1 = [
{
label: "\u8DDD\u79BB\u4F18\u5148",
value: "1"
},
{
label: "\u901F\u5EA6\u4F18\u5148",
value: "2"
},
{
label: "\u8BC4\u5206\u4F18\u5148",
value: "3"
}
];
const options2 = [
{
label: "30\u5206\u949F\u5185",
value: "1"
},
{
label: "40\u5206\u949F\u5185",
value: "2"
},
{
label: "50\u5206\u949F\u5185",
value: "3"
}
];
const value1 = ref("1");
const value2 = ref("1");
const doSomething = () => {
return new Promise((resolve) => {
setTimeout(resolve, 500);
});
};
const beforeOpen = () => {
toast.loading("\u52A0\u8F7D\u4E2D", {
overlay: true
});
return doSomething().finally(() => {
toast.hide();
});
};
const beforeClose = (type) => {
if (type === "option") {
toast.loading("\u52A0\u8F7D\u4E2D", {
overlay: true
});
return doSomething().finally(() => {
toast.hide();
});
}
};
</script>可取消选择 1.19.3+
如果想点击时取消选中的选项,可以使用 togglable 属性。
vue
<template>
<sar-dropdown togglable direction="up">
<sar-dropdown-item
v-model="value1"
placeholder="排序"
:options="options1"
/>
<sar-dropdown-item
v-model="value2"
placeholder="配送时间"
:options="options2"
/>
</sar-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>
<sar-dropdown togglable direction="up">
<sar-dropdown-item
v-model="value1"
placeholder="排序"
:options="options1"
/>
<sar-dropdown-item
v-model="value2"
placeholder="配送时间"
:options="options2"
/>
</sar-dropdown>
</template>
<script setup lang="js">
import { ref } from "vue";
const options1 = [
{
label: "\u8DDD\u79BB\u4F18\u5148",
value: "1"
},
{
label: "\u901F\u5EA6\u4F18\u5148",
value: "2"
},
{
label: "\u8BC4\u5206\u4F18\u5148",
value: "3"
}
];
const options2 = [
{
label: "30\u5206\u949F\u5185",
value: "1"
},
{
label: "40\u5206\u949F\u5185",
value: "2"
},
{
label: "50\u5206\u949F\u5185",
value: "3"
}
];
const value1 = ref("1");
const value2 = ref("1");
</script>分隔线 1.28+
可以使用 separator 来设置菜单与面板之间的分割线类型。
vue
<template>
<sar-dropdown separator="line" direction="up">
<sar-dropdown-item v-model="value1" :options="options1" />
<sar-dropdown-item v-model="value2" :options="options2" />
</sar-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>
<sar-dropdown separator="line" direction="up">
<sar-dropdown-item v-model="value1" :options="options1" />
<sar-dropdown-item v-model="value2" :options="options2" />
</sar-dropdown>
</template>
<script setup lang="js">
import { ref } from "vue";
const options1 = [
{
label: "\u8DDD\u79BB\u4F18\u5148",
value: "1"
},
{
label: "\u901F\u5EA6\u4F18\u5148",
value: "2"
},
{
label: "\u8BC4\u5206\u4F18\u5148",
value: "3"
}
];
const options2 = [
{
label: "30\u5206\u949F\u5185",
value: "1"
},
{
label: "40\u5206\u949F\u5185",
value: "2"
},
{
label: "50\u5206\u949F\u5185",
value: "3"
}
];
const value1 = ref("1");
const value2 = ref("1");
</script>API
DropdownProps
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| root-class | 组件根元素类名 | string | - |
| root-style | 组件根元素样式 | StyleValue | - |
| direction | 菜单弹出方向 | 'down' | 'up' | 'down' |
| disabled | 是否禁用 | boolean | false |
| away-closable | 是否在点击外部区域后自动隐藏 | boolean | true |
| overlay-closable | 是否在点击遮罩后自动隐藏 | boolean | true |
| duration | 显隐动画时长,单位 ms | number | 300 |
| togglable 1.19.3+ | 是否可取消选中的选项 | boolean | false |
| value-on-clear 1.19.3+ | 取消选项时设置的值 | any | undefined |
| separator 1.28+ | 菜单与面板之间的分割线类型 | 'shadow' | 'line' | 'none' | 'shadow' |
DropdownSlots
| 插槽 | 描述 | 属性 |
|---|---|---|
| default | 自定义默认内容 | - |
DropdownItemProps
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| root-class | 组件根元素类名 | string | - |
| root-style | 组件根元素样式 | StyleValue | - |
| title | 标题,用于自定义菜单内容 | string | - |
| label | 标签说明 | string | - |
| options | 菜单选项 | DropdownOption[] | [] |
| direction | 菜单弹出方向 | 'down' | 'up' | 'down' |
| disabled | 是否禁用 | boolean | false |
| model-value (v-model) | 当前选择的菜单项的值 | any | - |
| visible (v-model) | 弹出框是否可见 | boolean | - |
| separator | 标签后面分隔符 | string | - |
| placeholder | 占位符 | string | - |
| togglable 1.19.3+ | 是否可取消选中的选项 | boolean | false |
| value-on-clear 1.19.3+ | 取消选项时设置的值 | any | undefined |
| before-open 1.19.1+ | 打开前的回调,返回 false 或 rejected 状态的 Promise 可阻止打开 | () => any | - |
| before-close 1.19+ | 关闭前的回调,返回 false 或 rejected 状态的 Promise 可阻止关闭 | DropdownBeforeClose | - |
DropdownBeforeClose
ts
type DropdownBeforeClose = (type: DropdownCloseType) => any
type DropdownCloseType =
| 'overlay'
| 'away'
| 'other-button'
| 'button'
| 'option'关闭类型:
overlay点击遮罩away点击除遮罩和菜单之外的区域other-button点击其他菜单按钮button点击当前的菜单按钮option点击菜单项
DropdownItemSlots
| 插槽 | 描述 | 属性 |
|---|---|---|
| default | 自定义默认内容 | - |
DropdownItemEmits
| 事件 | 描述 | 类型 |
|---|---|---|
| update:model-value | 选中菜单选项时触发 | (value: any) => void |
| change 1.12.2+ | 选中菜单选项时触发 | (value: any) => void |
| update:visible | 弹出框显隐时触发 | (visible: boolean) => void |
| visible-hook 1.18+ | 入场/退场动画状态改变时触发 | (name: TransitionHookName) => void |
| before-enter 1.18+ | 入场动画开始前触发 | () => void |
| enter 1.18+ | 入场动画开始时触发 | () => void |
| after-enter 1.18+ | 入场动画结束时触发 | () => void |
| enter-cancelled 1.18+ | 入场动画取消时触发 | () => void |
| before-leave 1.18+ | 退场动画开始前触发 | () => void |
| leave 1.18+ | 退场动画开始时触发 | () => void |
| after-leave 1.18+ | 退场动画结束时触发 | () => void |
| leave-cancelled 1.18+ | 退场动画取消时触发 | () => void |
DropdownOption
| 属性 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| label | 定义选项标签 | string | - |
| value | 定义选项的值 | any | - |
主题定制
CSS 变量
scss
page,
.sar-portal {
--sar-dropdown-height: 88rpx;
--sar-dropdown-bg: var(--sar-emphasis-bg);
--sar-dropdown-box-shadow: var(--sar-shadow-lg);
--sar-dropdown-line-color: var(--sar-border-color);
--sar-dropdown-item-padding-x: 16rpx;
--sar-dropdown-item-active-opacity: var(--sar-active-opacity);
--sar-dropdown-item-show-color: var(--sar-primary);
--sar-dropdown-value-font-size: var(--sar-text-base);
--sar-dropdown-label-font-size: var(--sar-text-base);
--sar-dropdown-label-color: var(--sar-tertiary-color);
--sar-dropdown-label-margin-right: 16rpx;
--sar-dropdown-placeholder-color: var(--sar-fourth-color);
--sar-dropdown-arrow-margin-left: 8rpx;
--sar-dropdown-arrow-color: var(--sar-border-color);
--sar-dropdown-arrow-font-size: var(--sar-text-sm);
--sar-dropdown-popup-z-index: 1000;
--sar-dropdown-option-active-color: var(--sar-primary);
--sar-dropdown-option-icon-font-size: var(--sar-text-base);
}