Dropdown.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <template>
  2. <!-- 下拉选项列表 -->
  3. <div class="nana-dropdown-wrapper">
  4. <div v-bind="$attrs" class="nana-dropdown" @click="isDropdownOpen=!isDropdownOpen">
  5. <span>{{ selectedLabel }}</span>
  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. <span>{{ option[labelKey] }}</span>
  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 '../display/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. white-space: nowrap;
  84. overflow: hidden;
  85. text-overflow: ellipsis;
  86. max-width: 100%;
  87. .arrow {
  88. width: 15px;
  89. height: 15px;
  90. transition: transform 0.3s;
  91. margin-left: 10px;
  92. &.open {
  93. transform: rotate(180deg);
  94. }
  95. }
  96. span {
  97. font-size: 17.5px;
  98. color: var(--nana-text-1);
  99. max-width: calc(100% - 25px);
  100. white-space: nowrap;
  101. overflow: hidden;
  102. text-overflow: ellipsis;
  103. }
  104. }
  105. .nana-dropdown-options {
  106. position: absolute;
  107. top: 100%;
  108. left: 0;
  109. width: 300px;
  110. background-color: transparent;
  111. border: 1px solid $primary-color;
  112. color: $text-color;
  113. z-index: 20;
  114. .nana-scroll-view {
  115. max-height: 50vh;
  116. }
  117. .option {
  118. padding: 8px 15px;
  119. background-color: $box-hover-color;
  120. user-select: none;
  121. cursor: pointer;
  122. &:hover, .selected {
  123. background-color: $box-hover-color;
  124. }
  125. text {
  126. font-size: rpx(24);
  127. color: $text-color;
  128. }
  129. }
  130. }
  131. </style>