dma_exam_web/src/components/CustomSelect.vue
2026-10-26 18:07:56 +08:00

123 lines
2.4 KiB
Vue

<script setup>
import { ref, computed } from 'vue'
const props = defineProps({
options: Array,
modelValue: [String, Number]
})
const emit = defineEmits(['update:modelValue'])
const isOpen = ref(false)
const selectedLabel = computed(() =>
props.options.find(opt => opt.value === props.modelValue)?.label || '请选择'
)
const toggleDropdown = () => {
isOpen.value = !isOpen.value
}
const selectOption = (option) => {
emit('update:modelValue', option.value)
isOpen.value = false
}
</script>
<template>
<div class="custom-select">
<div
class="select-header"
:class="{ 'select-active': isOpen }"
@click="toggleDropdown"
>
{{ selectedLabel }}
<span class="arrow"></span>
</div>
<transition name="slide">
<div v-show="isOpen" class="select-options">
<div
v-for="(option, index) in options"
:key="index"
class="select-item"
@click="selectOption(option)"
>
{{ option.label }}
</div>
</div>
</transition>
</div>
</template>
<style scoped>
.custom-select {
position: relative;
width: 100%;
}
.select-header {
height: 56px;
padding: 0 15px;
border: 1px solid #B2B3B5;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
transition: border-color 0.3s;
}
.select-header:hover {
border-color: #79BBFF;
}
.select-active {
border-color: #79BBFF;
}
.arrow {
width: 24px;
height: 24px;
background: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%2366676C' d='M7 10l5 5 5-5z'/%3E%3C/svg%3E");
transition: transform 0.3s;
}
.select-active .arrow {
transform: rotate(180deg);
}
.select-options {
position: absolute;
top: 60px;
left: 0;
right: 0;
text-align: left;
background: #fff;
border: 1px solid #eee;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
z-index: 100;
}
.select-item {
padding: 12px 16px;
cursor: pointer;
transition: background 0.2s;
}
.select-item:hover {
background: #f5f7fa;
}
.slide-enter-active,
.slide-leave-active {
transition: all 0.3s ease;
}
.slide-enter-from,
.slide-leave-to {
opacity: 0;
transform: translateY(-10px);
}
</style>