Dropdown.vue 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. <template>
  2. <!-- 下拉选项列表 -->
  3. <div class="nana-dropdown-wrapper">
  4. <div class="nana-dropdown" @click="isDropdownOpen=!isDropdownOpen">
  5. <text>{{ selectedLabel }}</text>
  6. <DropDownIcon :class="['arrow',isDropdownOpen?'open':'']" />
  7. </div>
  8. <div v-if="isDropdownOpen" class="nana-dropdown-options">
  9. <SimpleScrollView :scroll-y="true">
  10. <div
  11. v-for="(option, index) in options"
  12. :key="index"
  13. :class="[
  14. 'option',
  15. selectedValue === option[valueKey] ? 'selected' : '',
  16. ]"
  17. @click="selectOption(option)"
  18. >
  19. <text>{{ option[labelKey] }}</text>
  20. </div>
  21. </SimpleScrollView>
  22. </div>
  23. </div>
  24. </template>
  25. <script setup lang="ts">
  26. import { computed, ref, type PropType } from 'vue';
  27. import DropDownIcon from './DropdownIcon.vue';
  28. import SimpleScrollView from '../container/SimpleScrollView.vue';
  29. const props = defineProps({
  30. options: {
  31. type: Array as PropType<any[]>,
  32. default: () => [],
  33. },
  34. labelKey: {
  35. type: String,
  36. default: 'title',
  37. },
  38. valueKey: {
  39. type: String,
  40. default: 'value',
  41. },
  42. placeholder: {
  43. type: String,
  44. default: '请选择',
  45. },
  46. selectedValue: {
  47. type: null
  48. },
  49. })
  50. const emit = defineEmits([ 'update:selectedValue' ])
  51. const selectedLabel = computed(() => {
  52. const selectedOption = props.options.find(option => option[props.valueKey] === props.selectedValue);
  53. return selectedOption ? selectedOption[props.labelKey] : props.placeholder;
  54. });
  55. const isDropdownOpen = ref(false);
  56. function selectOption(option: any) {
  57. isDropdownOpen.value = false;
  58. emit('update:selectedValue', option[props.valueKey]);
  59. }
  60. </script>
  61. <style lang="scss">
  62. @use "@/assets/scss/colors.scss" as *;;
  63. .nana-dropdown-wrapper {
  64. position: relative;
  65. &.dark {
  66. .nana-dropdown {
  67. background-color: $box-dark-trans-color;
  68. border: 1px solid $border-dark-color;
  69. }
  70. }
  71. }
  72. .nana-dropdown {
  73. position: relative;
  74. display: flex;
  75. flex-direction: row;
  76. align-items: center;
  77. justify-content: space-between;
  78. padding: 10px 15px;
  79. background-color: $box-inset-color;
  80. border: 1px solid $primary-color;
  81. user-select: none;
  82. cursor: pointer;
  83. .arrow {
  84. width: 15px;
  85. height: 15px;
  86. transition: transform 0.3s;
  87. margin-left: 10px;
  88. &.open {
  89. transform: rotate(180deg);
  90. }
  91. }
  92. text {
  93. font-size: 17.5px;
  94. color: var(--nana-text-1);
  95. }
  96. }
  97. .nana-dropdown-options {
  98. position: absolute;
  99. top: 100%;
  100. left: 0;
  101. width: 300px;
  102. background-color: transparent;
  103. border: 1px solid $primary-color;
  104. z-index: 20;
  105. .nana-scroll-view {
  106. max-height: 50vh;
  107. }
  108. .option {
  109. padding: 8px 15px;
  110. background-color: $box-hover-color;
  111. user-select: none;
  112. cursor: pointer;
  113. &:hover, .selected {
  114. background-color: $box-hover-color;
  115. }
  116. text {
  117. font-size: rpx(24);
  118. color: $text-color;
  119. }
  120. }
  121. }
  122. </style>