index.vue 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. <template>
  2. <div class="select-filter">
  3. <div v-for="item in data" :key="item.key" class="select-filter-item">
  4. <div class="select-filter-item-title">
  5. <span>{{ item.title }} :</span>
  6. </div>
  7. <span v-if="!item.options.length" class="select-filter-notData">暂无数据 ~</span>
  8. <el-scrollbar>
  9. <ul class="select-filter-list">
  10. <li
  11. v-for="option in item.options"
  12. :key="option.value"
  13. :class="{
  14. active: option.value === selected[item.key] || (Array.isArray(selected[item.key]) && selected[item.key].includes(option.value))
  15. }"
  16. @click="select(item, option)"
  17. >
  18. <slot :row="option">
  19. <el-icon v-if="option.icon">
  20. <component :is="option.icon" />
  21. </el-icon>
  22. <span>{{ option.label }}</span>
  23. </slot>
  24. </li>
  25. </ul>
  26. </el-scrollbar>
  27. </div>
  28. </div>
  29. </template>
  30. <script setup lang="ts" name="selectFilter">
  31. import { ref, watch } from 'vue'
  32. interface OptionsProps {
  33. value: string | number
  34. label: string
  35. icon?: string
  36. }
  37. interface SelectDataProps {
  38. title: string // 列表标题
  39. key: string // 当前筛选项 key 值
  40. multiple?: boolean // 是否为多选
  41. options: OptionsProps[] // 筛选数据
  42. }
  43. interface SelectFilterProps {
  44. data?: SelectDataProps[] // 选择的列表数据
  45. defaultValues?: { [key: string]: any } // 默认值
  46. }
  47. const props = withDefaults(defineProps<SelectFilterProps>(), {
  48. data: () => [],
  49. defaultValues: () => ({})
  50. })
  51. // 重新接收默认值
  52. const selected = ref<{ [key: string]: any }>({})
  53. watch(
  54. () => props.defaultValues,
  55. () => {
  56. props.data.forEach(item => {
  57. if (item.multiple) selected.value[item.key] = props.defaultValues[item.key] ?? ['']
  58. else selected.value[item.key] = props.defaultValues[item.key] ?? ''
  59. })
  60. },
  61. { deep: true, immediate: true }
  62. )
  63. // emit
  64. const emit = defineEmits<{
  65. change: [value: any]
  66. }>()
  67. /**
  68. * @description 选择筛选项
  69. * @param {Object} item 选中的哪项列表
  70. * @param {Object} option 选中的值
  71. * @return void
  72. * */
  73. const select = (item: SelectDataProps, option: OptionsProps) => {
  74. if (!item.multiple) {
  75. // * 单选
  76. if (selected.value[item.key] !== option.value) selected.value[item.key] = option.value
  77. } else {
  78. // * 多选
  79. // 如果选中的是第一个值,则直接设置
  80. if (item.options[0].value === option.value) selected.value[item.key] = [option.value]
  81. // 如果选择的值已经选中了,则删除选中的值
  82. if (selected.value[item.key].includes(option.value)) {
  83. let currentIndex = selected.value[item.key].findIndex((s: any) => s === option.value)
  84. selected.value[item.key].splice(currentIndex, 1)
  85. // 当全部删光时,把第第一个值选中
  86. if (selected.value[item.key].length == 0) selected.value[item.key] = [item.options[0].value]
  87. } else {
  88. // 未选中点击值的时候,追加选中值
  89. selected.value[item.key].push(option.value)
  90. // 单选中全部并且点击到了未选中的值,把第一个值删除掉
  91. if (selected.value[item.key].includes(item.options[0].value)) selected.value[item.key].splice(0, 1)
  92. }
  93. }
  94. emit('change', selected.value)
  95. }
  96. </script>
  97. <style scoped lang="scss">
  98. @import './index.scss';
  99. </style>