124 lines
2.6 KiB
Vue
124 lines
2.6 KiB
Vue
<!--
|
||
原生 uni-app 下拉组件(不依赖 Element UI)
|
||
特点:
|
||
- 点击展开下拉菜单
|
||
- 选择后关闭
|
||
- v-model 支持
|
||
- 简洁轻量
|
||
|
||
用法:
|
||
<uni-native-dropdown v-model="value" :items="['编辑','删除','更多']" />
|
||
|
||
<uni-native-dropdown
|
||
v-model="selected"
|
||
:items="[
|
||
{ label: '编辑', value: 'edit' },
|
||
{ label: '删除', value: 'del' }
|
||
]
|
||
placeholder="请选择操作"
|
||
/>
|
||
-->
|
||
<template>
|
||
<view class="dropdown-container">
|
||
<!-- 触发区域 -->
|
||
<view @click="toggle">
|
||
<slot name="trigger" :selected="selectedLabel">
|
||
<view class="default-trigger">
|
||
<text>{{ selectedLabel }}</text>
|
||
<view class="arrow">▼</view>
|
||
</view>
|
||
</slot>
|
||
</view>
|
||
|
||
<!-- 下拉菜单 -->
|
||
<view v-if="open" class="dropdown-menu">
|
||
<view
|
||
class="dropdown-item"
|
||
v-for="(item, i) in normalizedItems"
|
||
:key="i"
|
||
@click="selectItem(item)"
|
||
>
|
||
{{ item.label }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: 'UniNativeDropdown',
|
||
props: {
|
||
modelValue: { type: [String, Number, Object], default: '' },
|
||
items: { type: Array, default: () => [] },
|
||
placeholder: { type: String, default: '请选择' }
|
||
},
|
||
data() {
|
||
return { open: false }
|
||
},
|
||
computed: {
|
||
normalizedItems() {
|
||
// 如果传的是 string 数组,转成 {label, value}
|
||
return this.items.map(i =>
|
||
typeof i === 'string' ? { label: i, value: i } : i
|
||
)
|
||
},
|
||
selectedLabel() {
|
||
const item = this.normalizedItems.find(i => i.value === this.modelValue)
|
||
return item ? item.label : this.placeholder
|
||
}
|
||
},
|
||
methods: {
|
||
toggle() {
|
||
this.open = !this.open
|
||
},
|
||
selectItem(item) {
|
||
this.$emit('update:modelValue', item.value)
|
||
this.$emit('change', item)
|
||
this.open = false
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.dropdown-container {
|
||
position: relative;
|
||
width: auto;
|
||
}
|
||
.dropdown-trigger {
|
||
border: 1px solid #ccc;
|
||
padding: 20rpx;
|
||
border-radius: 8rpx;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
background: #fff;
|
||
}
|
||
.arrow {
|
||
font-size: 28rpx;
|
||
margin-left: 10rpx;
|
||
transform: scaleY(0.8);
|
||
display: inline-block; /* 重要 */
|
||
}
|
||
.dropdown-menu {
|
||
position: absolute;
|
||
top: 100%;
|
||
left: 0;
|
||
width: 100%;
|
||
background: #fff;
|
||
border: 1px solid #ccc;
|
||
border-radius: 8rpx;
|
||
margin-top: 6rpx;
|
||
z-index: 999;
|
||
}
|
||
.dropdown-item {
|
||
padding: 20rpx;
|
||
border-bottom: 1px solid #eee;
|
||
}
|
||
.dropdown-item:last-child {
|
||
border-bottom: 0;
|
||
}
|
||
.dropdown-item:active {
|
||
background: #f2f2f2;
|
||
}
|
||
</style> |